I am trying to write a Windows batch script which examines an XML file (the iml file) to search for a certain line, . I am having trouble with the spaces in the string. Is there a way to escape or compensate for the spaces?
for /f "tokens=*" %%a in (abcd.iml) do (
echo %%a
if %%a==^<orderEntry type="inheritedJdk" ^> (echo 'FOUND')
)
Put the %%a in quotes so it is like "%%a." Instead of using the "==" operator to compare %%a and "^" it would be better to use the EQU comparator so the final code would look like:
for /f "tokens=*" %%a in (abcd.iml) do (
echo %%a
if "%%a" EQU "<orderEntry type="inheritedJdk" >" (echo 'FOUND')
)
For more information on EQU and other operators see https://ss64.com/nt/if.html or https://ss64.com/nt/equ.html
no need for a for loop. A simple findstr is much faster:
findstr /c:"<orderEntry type=\"inheritedJdk\" >" "abcd.iml" >nul && echo found || echo nope
Note: the quotes within the string have to be escaped (escape character for findstr is a backslash)
Related
Currently my code is: findstr Starfy ./List.txt > result.txt
My result.txt is
3841 - Legendary Starfy, The (USA).zip
x166 - Legendary Starfy, The (USA) (Demo) (Kiosk).zip
However, I want result 1 and result 2 to have their own seperate files, so it would look like:
result1.txt > 3841 - Legendary Starfy, The (USA).zip
result2.txt > x166 - Legendary Starfy, The (USA) (Demo) (Kiosk).zip
I'm unsure how to make this work, and would love if someone is able to help point me in the right direction.
This works:
#echo off
for /F "tokens=1* delims=:" %%a in ('findstr "Starfy" .\List.txt ^| findstr /N "^"') do >result%%a.txt echo %%b
Just pass your original results into another instance of findstr /N command that add line numbers. After that, separate the number and the line in a for /F command and output each line to its corresponding numbered file...
for /f "tokens=1,* delims=:" %%S in ('findstr /i "echo" "%~f0"^|findstr /n /i "echo" ') do ECHO %%T>"U:\moreresults\result%%S.txt"
The command quoted in parentheses finds a string (in this case, echo) ignoring case (/i) within the file "%~f0" (this batch file, which contains a heap of standard code I use for testing). This is passed to another instance of findstr, this time looking for the same string, but numbering the lines (as serialnumber:linetext).
The resultant text is tokenised using : as a separator, so %%S receives the serialnumber and %%T receives the rest of the line (token *). Then simply build the result filename using %%S and write the text part of the line to it.
The caret is used to escape the pipe so that cmd knows that the pipe is part of the command-to-be-executed, not of the for command.
Assuming that you do not already have files in the location you're outputting your results, which could alalready be named using that intended naming scheme, then something like this may suit you:
#Echo Off
SetLocal EnableExtensions EnableDelayedExpansion
Set "i=0"
For /F Delims^=^ EOL^= %%G In (
'%SystemRoot%\System32\find.exe /I "Starfy" 0^<".\List.txt" 2^>NUL'
) Do (
Set /A i += 1
1>"Result!i!.txt" Echo %%G
)
Please note that I used find.exe instead of findstr.exe simply because your example used a simple string containing a series of alphabetic only characters. Feel free to change it to '%SystemRoot%\System32\findstr.exe /LIC:"Starfy" ".\List.txt" 2^>NUL', or similar, should you require a more specialized matching mechanism.
This DOS batch script is stripping out the blank lines and not showing the blank lines in the file even though I am using the TYPE.exe command to convert the file to make sure the file is ASCII so that the FIND command is compatible with the file. Can anyone tell me how to make this script include blank lines?
#ECHO off
FOR /F "USEBACKQ tokens=*" %%A IN (`TYPE.exe "build.properties" ^| FIND.exe /V ""`) DO (
ECHO --%%A--
)
pause
That is the designed behavior of FOR /F - it never returns blank lines. The work around is to use FIND or FINDSTR to prefix the line with the line number. If you can guarantee no lines start with the line number delimiter, then you simply set the appropriate delimiter and keep tokens 1* but use only the 2nd token.
::preserve blank lines using FIND, assume no line starts with ]
::long lines are truncated
for /f "tokens=1* delims=]" %%A in ('type "file.txt" ^| find /n /v ""') do echo %%B
::preserve blank lines using FINDSTR, assume no line starts with :
::long lines > 8191 bytes are lost
for /f "tokens=1* delims=:" %%A in ('type "file.txt" ^| findstr /n "^"') do echo %%B
::FINDSTR variant that preserves long lines
type "file.txt" > "file.txt.tmp"
for /f "tokens=1* delims=:" %%A in ('findstr /n "^" "file.txt.tmp"') do echo %%B
del "file.txt.tmp"
I prefer FINDSTR - it is more reliable. For example, FIND can truncate long lines - FINDSTR does not as long as it reads directly from a file. FINDSTR does drop long lines when reading from stdin via pipe or redirection.
If the file may contain lines that start with the delimiter, then you need to preserve the entire line with the line number prefix, and then use search and replace to remove the line prefix. You probably want delayed expansion off when transferring the %%A to an environment variable, otherwise any ! will be corrupted. But later within the loop you need delayed expansion to do the search and replace.
::preserve blank lines using FIND, even if a line may start with ]
::long lines are truncated
for /f "delims=" %%A in ('type "file.txt" ^| find /n /v ""') do (
set "ln=%%A"
setlocal enableDelayedExpansion
set "ln=!ln:*]=!"
echo(!ln!
endlocal
)
::preserve blank lines using FINDSTR, even if a line may start with :
::long lines >8191 bytes are truncated
for /f "delims=*" %%A in ('type "file.txt" ^| findstr /n "^"') do (
set "ln=%%A"
setlocal enableDelayedExpansion
set "ln=!ln:*:=!"
echo(!ln!
endlocal
)
::FINDSTR variant that preserves long lines
type "file.txt" >"file.txt.tmp"
for /f "delims=*" %%A in ('findstr /n "^" "file.txt.tmp"') do (
set "ln=%%A"
setlocal enableDelayedExpansion
set "ln=!ln:*:=!"
echo(!ln!
endlocal
)
del "file.txt.tmp"
If you don't need to worry about converting the file to ASCII, then it is more efficient to drop the pipe and let FIND or FINDSTR open the file specified as an argument, or via redirection.
There is another work around that completely bypasses FOR /F during the read process. It looks odd, but it is more efficient. There are no restrictions with using delayed expansion, but unfortunately it has other limitations.
1) lines must be terminated by <CR><LF> (this will not be a problem if you do the TYPE file conversion)
2) lines must be <= 1021 bytes long (disregarding the <CR><LF>)
3) any trailing control characters are stripped from each line.
4) it must read from a file - you can't use a pipe. So in your case you will need to use a temp file to do your to ASCII conversion.
setlocal enableDelayedExpansion
type "file.txt">"file.txt.tmp"
for /f %%N in ('find /c /v "" ^<"file.txt.tmp"') do set cnt=%%N
<"file.txt.tmp" (
for /l %%N in (1 1 %cnt%) do(
set "ln="
set /p "ln="
echo(!ln!
)
)
del "file.txt.tmp"
I wrote a very simple program that may serve as replacement for FIND and FINDSTR commands when they are used for this purpose. My program is called PIPE.COM and it just insert a blank space in empty lines, so all the lines may be directly processed by FOR command with no further adjustments (as long as the inserted space don't cares). Here it is:
#ECHO off
if not exist pipe.com call :DefinePipe
FOR /F "USEBACKQ delims=" %%A IN (`pipe ^< "build.properties"`) DO (
ECHO(--%%A--
)
pause
goto :EOF
:DefinePipe
setlocal DisableDelayedExpansion
set pipe=´)€ì!Í!ŠÐŠà€Ä!€ü.t2€ü+u!:æu8²A€ê!´#€ì!Í!².€ê!´#€ì!Í!²+€ê!´#€ì!Í!Šò€Æ!´,€ì!Í!"Àu°´LÍ!ëÒ
setlocal EnableDelayedExpansion
echo !pipe!>pipe.com
exit /B
EDIT: Addendum as answer to new comment
The code at :DefinePipe subroutine create a 88 bytes program called pipe.com, that basically do a process equivalent to this pseudo-Batch code:
set "space= "
set line=
:nextChar
rem Read just ONE character
set /PC char=
if %char% neq %NewLine% (
rem Join new char to current line
set line=%line%%char%
) else (
rem End of line detected
if defined line (
rem Show current line
echo %line%
set line=
) else (
rem Empty line: change it by one space
echo %space%
)
)
goto nextChar
This way, empty lines in the input file are changed by lines with one space, so FOR /F command not longer omit they. This works "as long as the inserted space don't cares" as I said in my answer.
Note that the pipe.com program does not work in 64-bits Windows versions.
Antonio
Output lines including blank lines
Here's a method I developed for my own use.
Save the code as a batch file say, SHOWALL.BAT and pass the source file as a command line parameter.
Output can be redirected or piped.
#echo off
for /f "tokens=1,* delims=]" %%a in ('find /n /v "" ^< "%~1"') do echo.%%ba
exit /b
EXAMPLES:
showall source.txt
showall source.txt >destination.txt
showall source.txt | FIND "string"
An oddity is the inclusion of the '^<' (redirection) as opposed to just doing the following:
for /f "tokens=1,* delims=]" %%a in ('find /n /v "" "%~1"') do echo.%%ba
By omitting the redirection, a leading blank line is output.
Thanks to dbenham, this works, although it is slightly different than his suggestion:
::preserve blank lines using FIND, no limitations
for /f "USEBACKQ delims=" %%A in (`type "file.properties" ^| find /V /N ""`) do (
set "ln=%%A"
setlocal enableDelayedExpansion
set "ln=!ln:*]=!"
echo(!ln!
endlocal
)
As mentioned in this answer to the above question, it doesn't seem that lines are skipped by default using for /f in (at least) Windows XP (Community - Please update this answer by testing the below batch commands on your version & service pack of Windows).
EDIT: Per Jeb's comment below, it seems that the ping command, in at least Windows XP, is
causing for /f to produce <CR>'s instead of blank lines (If someone knows specifically why, would
appreciate it if they could update this answer or comment).
As a workaround, it seems that the second default delimited token (<space> / %%b in the example)
returns as blank, which worked for my situation of eliminating the blank lines by way of an "parent"
if conditional on the second token at the start of the for /f, like this:
for /f "tokens=1,2*" %%a in ('ping -n 1 google.com') do (
if not "x%%b"=="x" (
{do things with non-blank lines}
)
)
Using the below code:
#echo off
systeminfo | findstr /b /c:"OS Name" /c:"OS Version"
echo.&echo.
ping -n 1 google.com
echo.&echo.
for /f %%a in ('ping -n 1 google.com') do ( echo "%%a" )
echo.&echo.&echo --------------&echo.&echo.
find /?
echo.&echo.
for /f %%a in ('find /?') do ( echo "%%a" )
echo.&echo.
pause
.... the following is what I see on Windows XP, Windows 7 and Windows 2008, being the only three versions & service packs of Windows I have ready access to:
i want to convert every whitespace in input to a new line character and save to a file (say tmp.txt) with batch file windows .
input:
http://www.example1.com wwwexample2com wwwexample3com wwwexample4com
to output in tmp.txt :
http://www.example1.com
wwwexample2com
wwwexample3com
wwwexample4com
how do I do that?
If the input is a file named "input file.txt" and the urls contain "=":
#echo off
setlocal enableDelayedExpansion
>"output file.txt" (for /f "usebackq delims=" %%a in ("input file.txt") do (
set line=%%a
call :listtokens "!line: =" "!"
))
pause & exit
:listtokens
if .%1==. (exit /b) else (echo %~1 & shift & goto listtokens)
If the input is a variable with alphanumeric words:
>"output file.txt" (for %%a in (%VARIABLE%) do echo %%a)
If the input is a file named "input file.txt" with alphanumeric words:
>"output file.txt" (for /f "usebackq delims=" %%a in ("input file.txt") do (
for %%b in (%%a) do echo %%b
))
If it's from a console utility that outputs alphanumeric words:
>"output file.txt" (for /f "delims=" %%a in ('run some command') do (
for %%b in (%%a) do echo %%b
))
The following pure batch script will put each space delimited "word" onto a separate line in the output. Empty lines will be stripped. The script is very robust. It should handle any ASCII text as long as every source line is <8kb. Note this will not convert other whitespace characters like tab into newlines.
#echo off
setlocal disableDelayedExpansion
>"input.txt.new" (
for /f "usebackq eol= tokens=* delims= " %%A in ("input.txt") do (
set "ln=%%A"
setlocal enableDelayedExpansion
echo(!ln: =^
!%= This line and the empty line above must remain exactly as written=%
endlocal
)
)
findstr . "input.txt.new" >"output.txt"
del "input.txt.new"
type output.txt
However, I would not use the above because I think pure batch makes text manipulation overly complex.
I would use a regular expression text processing utility called JREPL.BAT. It is pure script (hybrid JScript/batch) that runs natively on any Windows machine from XP onward. It is much simpler, faster, and more robust than any pure batch solution. The utility is extensively documented, and there are many regular expression tutorials available on the web.
The following one liner will efficiently put each whitespace delimtted "word" onto a separate line in the output.
jrepl "\S+" "$0" /jmatch /f "input.txt" /o "output.txt"
If you really want to convert every whitespace character into a newline, as you say in your comment, then you could use the following. But I don't think it is really what you want.
jrepl "\s" "\n" /x /f "input.txt" /o "output.txt"
I have a txt file with this format:
some text
another uninteresting line
// some more lines can come here
[ actually interesting
// this is the stuff I want
]
I want to be able to get everything between the square brackets [] (including the brackets themselves).
(since I know that there's no text after the closing bracket, it's enough to be able to delete just the first lines before the [ char).
I'm pretty sure I can do it with findStr, but not sure exactly how.
You can use VBScript. Save the following as extract.vbs
flag=0
Do While Not WScript.StdIn.AtEndOfStream
Line = WScript.StdIn.ReadLine()
If Left(Line,1)="[" Then flag=1 End If
If flag=1 Then
WScript.Stdout.WriteLine(Line)
End If
Loop
Then run
CSCRIPT /NOLOGO EXTRACT.VBS < YOURFILE
It sets a flag to zero, then reads the input file one line at a time till the end. If it encounters a line starting with "[" it sets flag=1. Then it prints every line it finds when flag is set to 1.
If you want to save the lines it finds, in a new file, run it like this:
CSCRIPT /NOLOGO EXTRACT.VBS < YOURFILE > NEWFILE
FINDSTR cannot solve this on its own.
Given your situation that you can simply delete all lines before the line that starts with [, all you need is the following native batch script.
#echo off
setlocal
for /f "delims=:" %%N in ('findstr /n [ "file.txt"') do if not defined N set /a N=%%N-1
set "skip="
if %N% gtr 1 set "skip=skip=%N%"
(for /f "usebackq %skip% delims=" %%A in ("file.txt") do echo %%A) >"newFile.txt"
If you know that your file does not contain tabs, or if it is OK that tabs are converted to a string of spaces, then it is even easier:
#echo off
setlocal
for /f "delims=:" %%N in ('findstr /n [ "file.txt"') do if not defined N set /a N=%%N-1
more +%N% "file.txt" >"newFile.txt"
The solution is a one liner if you use REPL.BAT - a hybrid JScript/batch utility that performs regular expression search and replace on stdin and writes the result to std out. It is pure script that will run natively on any modern Windows machine from XP onward.
Assuming that [ only appears once, then:
type "file.txt" | repl "[^[]*\[" "[" m >"newFile.txt"
It is even simple to support multiple blocks between square brackets where the [ and/or ] could be in the middle of a line:
type "file.txt" | repl "[^[]*(\[[\s\S]*?\])[^[]*" "$1\r\n" mx >"newFile.txt"
#echo off
setlocal enableextensions disabledelayedexpansion
set "dataFile=data.txt"
rem search the starting line
set "startLine="
for /f "tokens=1 delims=:" %%a in (
'findstr /l /b /n /c:"[" "%dataFile%"'
) do if not defined startLine set "startLine=%%a"
rem remove all lines before the starting one
if defined startLine for /f "tokens=1,* delims=:" %%a in (
'findstr /n "^" "%dataFile%" ^& break ^> "%dataFile%"'
) do if %%a geq %startLine% >>"%dataFile%" echo(%%b
endlocal
If you install some tools from a proper Operating System (Unix/Linux) you can do it without any code:
grep -A 999 \[ yourfile
That says look for a [ character in yourfile and print it and up to 999 lines after (-A) it. Unix Utils are available for free here.
Is it possible to use a piped stdin stream inside a batch file?
I want to be able to redirect the output of one command into my batch file process.bat list so:
C:\>someOtherProgram.exe | process.bat
My first attempt looked like:
echo OFF
setlocal
:again
set /p inputLine=""
echo.%inputLine%
if not (%inputLine%)==() goto again
endlocal
:End
When I test it with type testFile.txt | process.bat it prints out the first line repeatedly.
Is there another way?
set /p doesn't work with pipes, it takes one (randomly) line from the input.
But you can use more inside of an for-loop.
#echo off
setlocal
for /F "tokens=*" %%a in ('more') do (
echo #%%a
)
But this fails with lines beginning with a semicolon (as the FOR-LOOP-standard of eol is ;).
And it can't read empty lines.
But with findstr you can solve this too, it prefix each line with the linenumber, so you never get empty lines.
And then the prefix is removed to the first colon.
#echo off
setlocal DisableDelayedExpansion
for /F "tokens=*" %%a in ('findstr /n "^"') do (
set "line=%%a"
setlocal EnableDelayedExpansion
set "line=!line:*:=!"
echo(!line!
endlocal
)
Alternatively, on some environments (like WinRE) that don't include findstr, an alternative with find.exe might suffice. find will accept a null search string "", and allows search inversion. This would allow something like this:
#echo off
setlocal DisableDelayedExpansion
for /F "tokens=*" %%a in ('find /v ""') do (
...
The set "line=!line:*:=!" syntax is:
set requires one parameter that is a=b.
If a contains a space or something, you'll have to use the quotation marks around this parameter. Here I don't see any
!line:*:=!
For this syntax, you can type 'set /?' to see the official description on using variables.
!var! is like %var%, to get the value. But !var! means delayed expansion.
line var name
the first : variable modification mark.
**:= **:=(empty), replace the string in the variable's value matches "*:"(virtually from the string start to first : occurence) with (empty), i.e. delete the substring from start to first colon.
FOR /F "tokens=1* delims=]" %%A IN ('FIND /N /V ""') DO (
> CON ECHO.%%B
>> %File% ECHO.%%B
)
Source here: http://www.robvanderwoude.com/unixports.php#TEE
Alternatively, on some environments (like WinRE) that don't include findstr, an alternative with find.exe might suffice. find will accept a null search string "", and allows search inversion. This would allow something like this:
#echo off
setlocal DisableDelayedExpansion
for /F "tokens=*" %%a in ('find /v ""') do (
set "line=%%a"
echo(!line!
)