Task in CMD.
1) How can I compare if string is in string? I checked manual here for "Boolean Test "does string exist ?"" But I can't understand the example or it does not work for me. This piece of code, it is just a try. I try to make a string compare of filter some sting if there is a tag <a> in a line.
FOR /f "tokens=* delims= usebackq" %%c in ("%source%") DO (
echo %%c
IF %%c == "<a" (pause)
)
So while I read a file, it should be paused if there is a link on a line.
2) I have one more ask. I would need to filter the line if there is a specific file in the link, and get content of the link. My original idea was to try to use findstr with regex, but it seems not to use sub-patterns. And next problem would be how to get the result to variable.
set "pdf=0_1_en.pdf"
type "%source%" | grep "%pdf%" | findstr /r /c:"%pdf%.*>(.*).*</a>"
So in summary, I want to go through file and if there is a link like this: REPAIRED: *
<b>GEN 0.1 Preface</b>
I forgot to style this as a code, so the inside of code was not displayed. Sorry.
Warnning: we don't know the path, only the basic filename.
Get the title GEN 0.1 Preface. But you should know, that there are also similar links with same link, which contain image, not a text inside a tag.
Code according Aacini to be changed a little bit:
#echo off
setlocal EnableDelayedExpansion
set "source=GEN 0 GENERAL.html"
set "pdf=0_1_en.pdf"
echo In file:%source%
echo Look for anchor:%pdf%
rem Process each line in %source% file:
for /F "usebackq delims=" %%c in ("%source%") do (
set "line=%%c"
rem Test if the line contain a "tag" that start with "<a" string:
set "tag=!line:*<a=!"
if not "!tag!" == "!line!" (
rem Take the string in tag that end in ">"
for /F "delims=^>" %%a in ("!tag!") do set "link=%%a"
echo Link found: !link!
if "!link!" == "GEN 0.1 Preface" echo Seeked link found
)
)
pause
Still not finished
Although your question is extensive it does not provide to much details, so I assumed several points because I don't know too much about .PDF files, tags, etc.
#echo off
setlocal EnableDelayedExpansion
set "source=GEN 0 GENERAL.html"
set "pdf=0_1_en.pdf"
echo In file: "%source%"
echo Look for anchor: "%pdf%"
rem Process each line in %source% file:
for /F "usebackq delims=" %%c in ("%source%") do (
set "line=%%c"
rem Test if the line contain "<a>" tag:
set "tag=!line:*<a>=!"
if not "!tag!" == "!line!" (
rem Test if "<a>" tag contain the anchor pdf file:
if not "!tag:%pdf%=!" == "!tag!" (
rem Get the value of "<b>" sub-tag
set "tag=!tag:<b>=$!"
set "tag=!tag:</b>=$!"
for /F "tokens=2 delims=$" %%b in ("!tag!") do set title=%%b
echo Title found: "!title!"
)
)
)
pause
Any missing point can be added or fixed, if you give me precise details about them.
EDIT: I fixed the program above after last indications from the OP. I used $ character to get the Title value; if this character may exist in original Tag, it must be changed by another unused one.
I tested this program with this "GEN 0 GENERAL.html" example file:
Line one
<a>href="/Dokumenter/EK_GEN_0_X_en.pdf" class="uline"><b>GEN 0.X Preface</b></a>
Line three
<a>href="/Dokumenter/EK_GEN_0_1_en.pdf" class="uline"><b>GEN 0.1 Preface</b></a>
Line five
and get this result:
In file: "GEN 0 GENERAL.html"
Look for anchor: "0_1_en.pdf"
Title found: "GEN 0.1 Preface"
EDIT: New faster method added
There is a simpler and faster method to solve this problem that, however, may fail if a line contains more than one tag:
#echo off
setlocal EnableDelayedExpansion
set "source=GEN 0 GENERAL.html"
set "pdf=0_1_en.pdf"
echo In file: "%source%"
echo Look for anchor: "%pdf%"
for /F "delims=" %%c in ('findstr /C:"<a>" "%source%" ^| findstr /C:"%pdf%"') do (
set "tag=%%c"
rem Get the value of "<b>" sub-tag
set "tag=!tag:<b>=$!"
set "tag=!tag:</b>=$!"
for /F "tokens=2 delims=$" %%b in ("!tag!") do set title=%%b
echo Title found: "!title!"
)
pause
First, one important question: does this really have to be implemented via a CMD script? Would you be able to go with VBScript, PowerShell, C#, or some other scripting/programming language? CMD is a notoriously painful scripting environment.
Secondly, I'm not sure if this answers your question--it's a bit unclear--but here's a quick trick you can use to see in CMD to see if a given string contains another substring:
setlocal enableextensions enabledelayedexpansion
set PATTERN=somepattern
for /f "delims=" %%f in (somefile.txt) do (
set CURRENT_LINE=%%f
if "!CURRENT_LINE:%PATTERN%=!" neq "!TEMP!" (
echo Found pattern in line: %%f
)
)
The idea is that you try to perform string replacement and see if anything was changed. This is certainly a hack, and it would be preferable if you could instead use a tool like findstr or grep, but if you're limited in your options, something like the above should work.
NOTE: I haven't actually run the above script excerpt, so let me know if you have any difficulty with it.
I have modified the way to do it. I realized that it is better to find name of pdf document first. This is my almost completed solution, but I ask you if you could help me with the last point. The last replacing statement does not work because I need to remove closing tag b. Just to get the title.
#echo off
setlocal EnableDelayedExpansion
set "source=GEN 0 GENERAL.html"
set "pdf=0_1_en.pdf"
echo In file:%source%
echo Look for anchor:%pdf%
rem Process each line in %source% file:
for /F "usebackq delims=" %%c in ("%source%") do (
set "line=%%c"
REM Test if the line contains pdf file I look for:
SET "pdfline=!line:%pdf%=!"
if not "!pdfline!" == "!line!" (
cls
echo Line: !line!
REM Test if the pdfline contains tag b
SET "tagline=!pdfline:*><b>=!"
if not "!tagline!" == "!pdfline!" (
cls
echo ACTUAL LINE: !tagline!
REM Remove closing tag b
SET "title=!tagline:</b*=!"
echo TITLE: !title!
pause
)
)
)
pause
BTW:
The html page I work with is here.
So I ask you to help complete/repair line SET "title=!tagline:</b*=!"
Related
I'm trying to get a line from a file in Windows batch with no success. I've tried several ways to do it with I'm not an expert and it's impossible to me. The number line to read is calculated dinamically:
set "file=C:\myfile.txt"
REM Looking for line number where the segment "<segment>" is.
for /f "tokens=1 delims=:" %%L in ('findstr /n "<segment>" %file%') do (
set begin_line=%%L
)
echo %begin_line%
So I'm trying to read the line %begin_line%+1 and store it into a var.
I'm sure that the way to achieve this is with for /f skip=%begin_line but I couldn't do it.
Any idea?
I hope what I have requested is possible.
Ivan
I'm not sure whether I understand your question. You are searching for the first line which contains the substring segment. Then you want to store the next line inside a variable. Is that correct? If yes, here is the code:
#ECHO OFF
SETLOCAL EnableDelayedExpansion
SET inputFile=C:\myfile.txt
SET fount=0
FOR /F "tokens=*" %%F IN (%inputFile%) DO (
IF !found!==1 (
SET foundLine=%%F
GOTO BREAK
)
SET line=%%F
SET line=!line:^<segment^>=!
IF NOT !line!==%%F SET found=1
)
:BREAK
ECHO !foundLine!
PAUSE
I made a Batch script to rename a large amount of files. It takes their name and searches for it in a text document, copies the line and takes the data I need from it and then renames the file.
It seems to work fine for the most part, but I can't check to see how it's doing because it is constantly producing errors/warnings in the console.
#echo off
set ogg=.ogg
Setlocal EnableDelayedExpansion
for %%a in (*.ogg) do (
set fileNameFull=%%a
set fileName=!fileNameFull:~0,-4!
for /F "delims=" %%a in ('findstr /I !fileName! strings.txt') do (
endlocal
set "stringLine=%%a%ogg%"
)
Setlocal EnableDelayedExpansion
set fullString=!stringLine:~26!
ren %%a "!fullString!"
)
pause
The code works, I'd just like to be able to track progress, as 10,000s of files are being renamed at a time and I've no indication of how far along the process is.
The errors are:
"FINDSTR: Cannot open [...]"
"The syntax of the command is incorrect."
#echo off
Setlocal EnableDelayedExpansion
for %%a in (*.ogg) do (
for /F "delims=" %%q in ('findstr /I /L /c:"%%~na" strings.txt') do (
set "stringLine=%%q"
)
ECHO ren "%%a" "!stringLine:~26!.ogg"
)
pause
This code should be equivalent, but fixed, to the code you've posted.
Fixes:
Removed the endlocal/setlocal complication - not required
changed the inner `for` metavariable - must not be duplicate `%%a`
Changed the `findstr` switches - add `/L` for literal and `/c:` to force single token in case of a separator-in-name; use `%%~na` to specify "the name part of `%%a`" to avoid the substringing gymnastics.
removed said gymnastics
Removed 2-stage string manipulation of destination filename
Removed superfluous setting of `ogg`
The resultant code should duplicate what you have originally, except that it will simply report the rename instruction. You should test this against a small representative sample to verify.
for counting/progress:
set /a count=0
for %%a in (*.ogg) do (
for /F "delims=" %%q in ('findstr /I /L /c:"%%~na" strings.txt') do (
set "stringLine=%%q"
)
ECHO ren "%%a" "!stringLine:~26!.ogg"
set /a count +=1
set /a stringline= count %% 1000
if %stringline% equ 0 echo !count! Processed
)
pause
which should show you progress each 1000.
You could use
if %stringline% equ 0 echo !count! Processed&pause
to wait for user-action before progressing...
BTW -I'm making the assumption that the newname is from column 27+ in your file, since you've not shown us a sample.Also, you should be aware that a simple findstr would locate the target string as a substring anywhere within the file - either as the newname or the oldname. If you invoke the /B switch on the findstr, then the string will match at the very beginning of the line only.
if my file conatins below text :
sampleA1xxx sampleA2yyyy sampleA3zzzzz ... sampleA4hhhhh
I want to find sampleA4 and display sampleA4hhhh using windows batch script.
Thats is my output should be: sampleA4hhhhh
Could anyone please help me.
take a batch or have a look at GNUWin sed:
>type file
^^sampleA1xxx ^^sampleA2yyyy ^^sampleA3zzzzz ^^sampleA4hhhhh
>sed -r "s/.*(\b\w+4\w+)/\1/" file
sampleA4hhhhh
#echo off
setlocal EnableDelayedExpansion
set target=sampleA4
set len=8
for /F "delims=" %%a in ('findstr "%target%" theFile.txt') do (
for %%b in (%%a) do (
set word=%%b
if "!word:~0,%len%!" equ "%target%" (
echo !word:~%len%!
)
)
)
#ECHO OFF
SETLOCAL
FOR /f "delims=" %%i IN (q17316008.txt) DO SET line=%%i
SET line=%line:^= %
SET line=%line:*sampleA4=sampleA4%
FOR %%i IN (%line:^^= %) DO SET line=%%i&GOTO :done
:done
ECHO %line%
GOTO :EOF
This should do what I gather to be the task. It assumes that the "samplea4" string exists in the file's single line, is case-insensitive and the line doesn't exceed the ~8K limit on line length.
Simply replace the carets with spaces, lop off the leading characters to the first occurrence of the target string, and process that target string as a list; the first element will be the required string, so stop the processing when it's available.
OK, I tried this myself with a similar case and it worked fine:
for /f "tokens=4 delims=^^" %%a in (seperate.txt) do (echo %%a)
pause
Note: This is designed for a batch file, and replace the 4 after "tokens=" with whichever separated text you want to stop at.
Hope this helped,
Yours Mona.
I have a requirement where i'd like to read values from a .properties file
my properties file test.properties content
file=jaguar8
extension=txt
path=c:\Program Files\AC
From the above file I need to fetch jaguar or anything after =
Please help me. Thanks
For /F "tokens=1* delims==" %%A IN (test.properties) DO (
IF "%%A"=="file" set file=%%B
)
echo "%file%"
hope this could help
#echo off
FOR /F "tokens=1,2 delims==" %%G IN (test.properties) DO (set %%G=%%H)
echo %file%
echo %extension%
echo %path%
Note that there is no space after %%H. Else this causes a space to be appended, to file paths for example, and will cause file not found errors when the variables from the property files are used as part of a file path.Struggled for hours because of this!
A solution with support for comments (# style). See comments in code for explanation.
test.properties:
# some comment with = char, empty line below
#invalid.property=1
some.property=2
some.property=3
# not sure if this is supported by .properties syntax
text=asd=f
properties-read.bat:
#echo off
rem eol stops comments from being parsed
rem otherwise split lines at the = char into two tokens
for /F "eol=# delims== tokens=1,*" %%a in (test.properties) do (
rem proper lines have both a and b set
rem if okay, assign property to some kind of namespace
rem so some.property becomes test.some.property in batch-land
if NOT "%%a"=="" if NOT "%%b"=="" set test.%%a=%%b
)
rem debug namespace test.
set test.
rem do something useful with your vars
rem cleanup namespace test.
rem nul redirection stops error output if no test. var is set
for /F "tokens=1 delims==" %%v in ('set test. 2^>nul') do (
set %%v=
)
output from set test. (see above):
test.some.property=3
test.text=asd=f
The most important parts are:
the for-loop with the eol and delims option and
the if-checks that both variables %%a and %%b are set.
What you do in the for-loop with the variable and its value is certainly up to you - assigning to some prefixed variables was just an example. The namespacing approach avoids that any other global variable gets overridden.
For example if you have something like appdata defined in your .properties file.
I'm using this to get rid of an extra config.bat and instead using one .properties file for both the java app and some support batch files.
Works for me, but certainly not every edge case is covered here, so improvements welcome!
Try this
echo off
setlocal
FOR /F "tokens=3,* delims=.=" %%G IN (test.properties) DO ( set %%G=%%H )
rem now use below vars
if "%%G"=="file"
set lfile=%%H
if "%%G"=="path"
set lpath=%%H
if "%%G"=="extension"
set lextention=%%H
echo %path%
endlocal
I know this is ancient post but I would like to expand on toschug's great answer.
If the path in the .properties file would be defined as %~dp0 or any other variable that needs to be expanded first before using it, I recommend doing it the following way:
In the .properties file:
path=%~dp0
In the batch file you can then use it the following way (the code is to be used between the two for(s) defining one <=> cleanup one):
if "!test.path!" NEQ "" (
echo Not expanded path: !test.path!
call :expand !test.path! test.path
)
echo test.path expanded: !test.path!
pause
:expand
SET "%~2=%~1"
GOTO :EOF
Don't forget to use (at the start of the batch file):
SETLOCAL ENABLEDELAYEDEXPANSION
you can try this:
#ECHO OFF
#SETLOCAL
FOR /F "tokens=1* delims==" %%A IN (test.properties) DO (
ECHO %%A = %%B
)
#ENDLOCAL
i am writing a batch script monotonic file renamer. basically, it makes the titles of all the files 1 2 3 4 .... and so on. i have since expanded it to be able to handle files of different types (txt, doc, flv, etc) but not everything is working out.
my main concern is i have broken the delayed expansion calls i was making before. now using !var1! is never expanded, or never recognized as a variable.
here is a verbosely commented version of my script
::a monotonic file renamer
#echo off
SETLOCAL ENABLEDELAYEDEXPANSION
SET tempfile=temp.txt
SET exttemp=exttemp.txt
if [%1] == [] goto usage
::make sure your dont overwrite something useful
if EXIST %tempfile% (
ECHO Temp file already exists, are you sure you want to delete?
del /P %tempfile%
)
if EXIST %exttemp% (
ECHO EXT Temp file already exists, are you sure you want to delete?
del /P %exttemp%
)
::initialize
SET /a counter=0
SET type=
SET /a ender=%1
::write filenames to tempfile
DIR /B /ON > %tempfile%
::read lines one by one
for /f "usebackq delims=" %%a in (%tempfile%) do (
REM make sure we do not rename any of the working files
if NOT "%%a"=="renamer.bat" (
if NOT "%%a"=="temp.txt" (
if NOT "%%a"=="exttostr.bat" (
SET /a counter+=1
REM get file extension
exttostr %%a > %exttemp%
SET /P type= < %exttemp%
REM housekeeping
del /F %exttemp%
REM rename
ren %%a !counter!.!type!
ECHO Renamed "%%a" to "!counter!.!type!"
)))
REM exit when we have run enough
if "!counter!"=="!ender!" goto exit
)
goto exit
:usage
echo Usage: renamer NUMFILES
:exit
::final housekeeping
DEL temp.txt
the idea is i drop my two files, renamer.bat(this file) and exttostr.bat(helper to get the file extension) into the folder and run it, it will rename files sorted alphabetically from 1 to how ever many files i specify.
when i run the code, it never uses the variables marked for delayed expansion appropriately, always leaving them as "!varname!", so it renames the first file "!counter!.!type!" and throws errors for the rest because there is already a file in the directory with that name.
this brings me to a secondary issue. sorting the dir list alphabetically results in a poor handling of numbered files. for example the list:
"1 7 15 75 120"
is sorted:
"1 120 15 7 75"
i have not been able to find a way around this yet, only that it is indeed the intended result of the dir sort. the only workaround i have is padding numbers with enough zeroes in the front.
thanks in advance for any insight!
everything is sorted but the second problem. i think i have not spoken well. i have this issue when i take IN the directory file names, not when writing out. so they already need to be padded. i has hoping there was some other way to read the directory and have it be sorted appropriately.
the most promising thing i have found is here: http://www.dostips.com/DtCodeBatchFiles.php#Batch.SortTextWithNumbers
#ECHO OFF
if "%~1"=="/?" (
echo.Sorts text by handling first number in line as number not text
echo.
echo.%~n0 [n]
echo.
echo. n Specifies the character number, n, to
echo. begin each comparison. 3 indicates that
echo. each comparison should begin at the 3rd
echo. character in each line. Lines with fewer
echo. than n characters collate before other lines.
echo. By default comparisons start at the first
echo. character in each line.
echo.
echo.Description:
echo. 'abc10def3' is bigger than 'abc9def4' because
echo. first number in first string is 10
echo. first number in second string is 9
echo. whereas normal text compare returns
echo. 'abc10def3' smaller than 'abc9def4'
echo.
echo.Example:
echo. To sort a directory pipe the output of the dir
echo. command into %~n0 like this:
echo. dir /b^|%~n0
echo.
echo.Source: http://www.dostips.com
goto:EOF
)
if "%~1" NEQ "~" (
for /f "tokens=1,* delims=," %%a in ('"%~f0 ~ %*|sort"') do echo.%%b
goto:EOF
)
SETLOCAL ENABLEDELAYEDEXPANSION
set /a n=%~2+0
for /f "tokens=1,* delims=]" %%A in ('"find /n /v """') do (
set f=,%%B
(
set f0=!f:~0,%n%!
set f0=!f0:~1!
rem call call set f=,%%%%f:*%%f0%%=%%%%
set f=,!f:~%n%!
)
for /f "delims=1234567890" %%b in ("!f!") do (
set f1=%%b
set f1=!f1:~1!
call set f=0%%f:*%%b=%%
)
for /f "delims=abcdefghijklmnopqrstuwwxyzABCDEFGHIJKLMNOPQRSTUWWXYZ~`##$*_-+=:;',.?/\ " %%b in ("!f!") do (
set f2=00000000000000000000%%b
set f2=!f2:~-20!
call set f=%%f:*%%b=%%
)
echo.!f1!!f2!!f!,%%B
rem echo.-!f0!*!f1!*!f2!*!f!*%%a>&2
)
this code can sort the filenames with one number in them (i.e. video100.mov is fine, video100video10.mov would break it)
the issue i have is i think adding a call to this helper fn will break it again, so i will be trying to include this in my modified renamer.bat now. any help is appreciated.
Probably the batch for extracting the extension reset the local environment.
But, you don't need it. You may extract the extension with the ~x option. Something similar to this ....
:monotonicrename
set /a counter = 0
for %%a in (%1\*.*) do (
if exist %%~fa (
set /a counter += 1
echo ren %%~fa !counter!%%~xa
)
)
goto :eof
to include leading zeroes in the counter, so that the directory sorts correctly, replace the previous rename command with three lines
set zcounter=0000!counter!
set zcounter=!zcounter:~-4!
echo ren %%~fa !counter!%%~xa
So putting all pieces together, add the monotonicrename function you just created in the batch file that can be as simpler as...
#echo off
setlocal enabledelayedexpansion
call :monotonicrename %1
goto :eof
:monotonicrename
set /a counter = 0
for %%a in (%1\*.*) do (
if exist %%~fa (
set /a counter += 1
set zcounter=0000!counter!
set zcounter=!zcounter:~-4!
echo ren %%~fa !zcounter!%%~xa
)
)
goto :eof
I didn't experience any issues with delayed expansion, everything worked fine for me (except, of course, for the fact that I didn't have the exttostr.bat helper script.)
Anyway, there are several things that could be improved about your script:
You don't need to store the result of DIR into a file to read it afterwards. You can read the output directly in the FOR loop.
You don't need the helper batch script. The extension can be extracted from %%a by using the ~x modifier with the loop variable: %%~xa. You can read more about modifiers by issuing HELP FOR from the command prompt.
The renamer batch file's own name can be referenced in the script as %0. You can apply the ~n modifier where you only need to use the name without the extension. The combined modifier of ~nx will give you the name with the extension.
So, here's how your script might look like with the above issues addressed:
::a monotonic file renamer
#echo off
SETLOCAL ENABLEDELAYEDEXPANSION
IF [%1] == [] GOTO usage
::initialize
SET /A counter=0
SET type=
SET /A ender=%1
::read lines one by one
FOR /F "usebackq delims=" %%a IN (`DIR /B /ON`) DO (
REM make sure we do not rename any of the working files
IF NOT "%%~a"=="%~nx0" (
SET /A counter+=1
RENAME "%%~a" "!counter!%%~xa"
ECHO Renamed "%%~a" to "!counter!%%~xa"
)
REM exit when we have run enough
IF "!counter!"=="!ender!" GOTO :EOF
)
GOTO :EOF
:usage
ECHO Usage: %~n0 NUMFILES
As for your secondary issue, it can be easily resolved like this:
Use something like 100000 as counter's initial value. (Use however many 0s you like, but possibly no more than nine.) Add the same value to ender as well.
When renaming files, instead of !counter! use the expression that removes the first character (the 1): !counter:~1! (in fact, this is not about removal, but about extracting a substring starting from the offset of 1, learn more about it with the HELP SET command).
Here's the modified version of the above script:
::a monotonic file renamer
#echo off
SETLOCAL ENABLEDELAYEDEXPANSION
IF [%1] == [] GOTO usage
::initialize
SET /A counter=1000
SET type=
SET /A ender=%1
SET /A ender+=counter
::read lines one by one
FOR /F "usebackq delims=" %%a IN (`DIR /B /ON`) DO (
REM make sure we do not rename any of the working files
IF NOT "%%~a"=="%~nx0" (
SET /A counter+=1
RENAME "%%~a" "!counter:~1!%%~xa"
ECHO Renamed "%%~a" to "!counter:~1!%%~xa"
)
REM exit when we have run enough
IF "!counter!"=="!ender!" GOTO :EOF
)
GOTO :EOF
:usage
ECHO Usage: renamer NUMFILES
You can also see that I made some other enhancements, like making sure the file name is enclosed in double quotes, and using GOTO :EOF instead of GOTO exit (:EOF is a special pre-defined label that points at the end of the batch script so you don't need to define your own).