Find multiple strings in multiple lines - batch-file

I am making a script that can find multiple strings in an command output. For example, here is my output after running the command:
Mount Dir : D:\mount
Image File : F:\sources\boot.wim
Image Index : 1
Mounted Read/Write : No
Status : Needs Remount
I want the batch file to find the strings "D:\mount" and "Needs remount" in the output and they have to both match to give an output, but the problem is it keeps showing the wrong string:
Dir
Press any key to continue...
Needs
Press any key to continue...
I know the problems are in the delimiters, but even if I change it, the results are still the same. Here is the code that I used:
#echo off
for /f "tokens=2 delims=: " %%a in ('dism /get-mountedimageinfo ^| findstr /i /c:"Dir" /c:"status"') do (
#echo %%a
pause
)
Please help me out. Thanks in advance

Your issue is this:
for /f "tokens=2 delims=: " %%a in (...
"delims=: " doesn't mean "delimit by colon plus space", but "delimit by colon and space" (delimters are one-char only; a string is translated into several one-char delimiters).
So tokens=2 is not what you need. You need the string after the (first) colon:
for /f "tokens=1,* delims=:" %%a in (...
where %%a is the part before the first colon and %%b is the part after the first colon (* means "do not tokenize the rest, but take it as one token"). Sadly the space after the colon is part of %%b then, but you can delete it (when needed) with substring substitution:
set "line=%%b"
set "line=!line:~1!"
(of course, you need delayed expansion for that.
Or more elegant with another for:
for /f "tokens=1,* delims=:" %%a in ('dism /get-mountedimageinfo ^| findstr /ibc:"Mount Dir" /ibc:"Status"') do (
for /f "tokens=*" %%c in ("%%b") do (
echo "%%c"
)
)
Edit
According to your comment, you want to know if both the literal path D:\mount and the string Needs Remount occur in the output? Then the following approach is more straigthforward:
for /f %%a in ('dism /get-mountedimageinfo ^| findstr /ixc:"Mount Dir : D:\mount" /ixc:"Status : Needs Remount"^|find /c ":"') do set count=%%a
if %count%==2 echo both strings found
(search for both strings and count the number of lines; compare with expected "2"; No need to actually extract the strings)

Related

How to use a ending number as a variable

I'm trying to figure out how to echo %findstr% to only display the number after this word
filename.txt
"ncui": 8888,
I would like to echo only 8888 so I can use it as a set number=%findstr% to another script
I found this so far
#echo off
findstr /c /i "\<ncui\>" "filename.txt"
I tested this several ways and doesn't work, I only get this "ncui": 8888,
I found serval scripts here but none worked since all where designed to find words without " and :
Any Help would be great
Here are the two possibilities, from my comment, each now split to shorter lines, ready just be pasted into your own batch file.
The first works only if the target string contains just number characters, whereas the second is for more general target strings.
For /F "Tokens=2 Delims=:" %%G In ('%SystemRoot%\System32\findstr.exe
/RIC:"\"ncui\": " "filename.txt" 2^>NUL') Do Set /A number=%%G 2>NUL
For /F "Tokens=2 Delims=:, " %%G In ('%SystemRoot%\System32\findstr.exe
/RIC:"\"ncui\": " "filename.txt" 2^>NUL') Do Set "number=%%G"

Findstr based on column1 only [batch file]

I have been searching through StackOverflow but could not find an answer that hits the mark. I have 2 .txt files to compare and return a 3rd one where differences exist.
However, only the first column of the first 2 files need a comparison.
E:\Compare_flie\file_1.txt
GND ZERO
22XC44 XXYYZZ
33XC55 YYUUTT
E:\Compare_file\file_2.txt
GND ZERO
22XC44 KK77UU
33XC55 88JJ66
66NN77 HHOO99
99CC88 UU77RR
E:\Compare_file\file_3.txt (intended output)
66NN77 HH0099
99CC88 UU77RR
Tried the code below but it is only good at picking out the differences of all the strings in the line
%echo on
findstr /v /i /g:E:\Compare_files\file_1.txt E:\Compare_files\file_2.txt
> E:\Compare_files\file_3.txt
Refined it further but not hitting the mark yet.
%echo on
for /f "tokens=1 delims= " %%I in ("E:\Compare_files\file_1.txt") do
findstr /v /i "%%I"/g:"D:\Compare_files\file_2.txt"
> "D:\Compare_files\file_3.txt"
Appreciate if anyone can assist.
#ECHO OFF
SETLOCAL
SET "sourcedir=U:\sourcedir"
SET "destdir=U:\destdir"
SET "filename1=%sourcedir%\q48816766.txt"
SET "filename2=%sourcedir%\q48816766_2.txt"
SET "tempfile=%temp%\q48816766.tmp"
SET "outfile=%destdir%\outfile.txt"
(FOR /f "usebackq" %%a IN ("%filename1%") DO ECHO %%a )>"%tempfile%"
FINDSTR /b /v /g:"%tempfile%" "%filename2%">"%outfile%"
REM DEL "%tempfile%" /F /Q
GOTO :EOF
I've set up names to suit my system, but with the two files containing your data.
Obviously, the usebackq on the for/f is only required if the filename is quoted. The parentheses around the command permit the echoed output to be accumulated into the temporary file. What's important here is the space between the %%a and ). This ensures that the temporary file contains trailing spaces.
Then apply the temporary file to the second data file via /g as in OP's code. The presence of the trailing spaces in the tempfile ensure that the only lines selected for omission are those where the first column exactly matches so for instance had 66NN7 appeared in the first file, first column, then this would not match 66NN77 in the second file.
Here's a method using batch with the type command piping the first file's contents over to the findstr command then passing the arguments accordingly to redirect those results into a temp file.
Using a for /f loop with "usebackq tokens=1 delims= " it will iterate through the temp file and for each line in that file parsing accordingly, it will append the column one lines with an echo command using >> to redirect the results over to file_3.txt with the expected results.
Please note the addition of the if exist "%srcdir%\file_3.txt" del /q /f "%srcdir%\file_3.txt" to delete that file if it exists since the for /f echo commands will append one after the other to it.
#echo on
set srcdir=E:\Compare_files
set tmpfile=%temp%\%~N0.tmp
type "%srcdir%\file_1.txt" | findstr /vig:"%srcdir%\file_2.txt">"%tmpfile%"
if exist "%srcdir%\file_3.txt" del /q /f "%srcdir%\file_3.txt"
for /f "usebackq tokens=1 delims= " %%I in ("%tmpfile%") do (
echo %%~I>>"%srcdir%\file_3.txt"
)
Further Resources
FOR /F
FOR /?
usebackq - specifies that the new semantics are in force,
where a back quoted string is executed as a
command and a single quoted string is a
literal string command and allows the use of
double quotes to quote file names in
file-set.
Redirection
Comparing/finding the difference between two text files using findstr
As I understand your problem, you want the lines from file_2.txt whose first column are not contained in first column of file_1.txt, that is: file_2.txt minus file_1.txt. There is a simpler approach to get such result:
#echo off
setlocal
rem Fill "line" array with lines from file_2.txt
rem use the first column for the array keys
for /F "delims=" %%a in (file_2.txt) do for /F %%b in ("%%a") do set "line[%%b]=%%a"
rem Delete array elements with same key from file_1.txt
for /F %%b in (file_1.txt) do set "line[%%b]="
rem Show remaining elements
(for /F "tokens=1* delims==" %%a in ('set line[') do echo %%b) > file_3.txt

How to use FOR to find string in file, strip it of spaces, set variable to it for token?

#ECHO off
setlocal EnableDelayedExpansion
set "VAR=da da da YES123123"
echo %VAR% > testing.txt
FOR /F %%a in ('findstr "YES" .\testing.txt') do (
set BLAH=%%a
set "BLAH2=%BLAH: =%"
set "FINAL=%BLAH2:~15%"
echo %FINAL%
)
endlocal
Whether WITH or WITHOUT "setlocal EnableDelayedExpansion" the batch file simply does not work.
But that's all I have so far. However I also want to strip the preceding characters from the FINDSTR string, but set a variable to the FINDSTR string AND IT'S SUCCEEDING 123123 characters. Unfortunately, it doesn't work. It only outputs "ECHO is off."
I have used FOR correctly in other ways, but I can't figure it out this time. Any help would be greatly appreciated.
to get the last word, use a plain for to split your string by default delimiters (space, tab, comma, =). No need to know, how many tokens there are. The following works, even if there are more lines with YES:
for /f "delims=" %%a in ('findstr "YES" .\testing.txt') do (
for %%b in (%%a) do set final=%%b
echo !final!
)
EDIT to find YES until end of line:
There is a token * for "all the rest", so you could do:
for /f "tokens=3,* delims= " %%a in ('findstr "YES" .\testing.txt') do echo %%b
but I recommend another method (replacing *YES with just YES). set can do limited wildcard replacement (*string works, but string* does not). Advantage: you don't need to know, which token YES... is:
for /f "delims=" %%a in ('findstr "YES" testing.txt') do (
set line=%%a
echo !line:* YES=YES!
)
Understand first meaning
Tokens mean take only the column 1 or 2 or ...... of stdout
skip mean skip line 1,2........... from the list of text of stdout
delims mean the way this columns seperated between each other with what (space or dot or slash ..........)
Ok so i figured it out. Had to use the "token=1,2,3,4, delim= " thing, which I hate using and it's confusing but have used it before for other purposes. I was just really confused on how to echo or set the variable to the token at the end of the command. Here is the corrected code.
FOR /F "tokens=1,2,3,4 delims= " %%a in ('findstr "YES" .\testing.txt') do echo %%d

Using if conditions at the end of a FOR loop in Batch

I have a simple for loop in a batch file I'm working on but I can't get the variables to expand correctly. the whole script is below..
setlocal enabledelayedexpansion
set track=0
FOR /f "tokens=2" %%G IN ('find "PhysicalTrackNumber" %1') DO if %track% LSS %%G set track=%%G
echo %track%
echo %1
pause
The for command pulls all the rows with the physical track number and I'm just trying to get the biggest number. IT always stays 0 though when it's comparing. I've tried with !! around my variable as well but then the script seems to do something completely different. I thought it would take the new variable.
What am I missing to compare the outputs to the previous and just get the biggest number?
find "string" filename output consists of
an empty line;
a string of 10 dashes followed by the filename being searched line;
any matching lines of text in the file.
Use skip=2 option (a number of lines to skip at the beginning):
FOR /f "skip=2 tokens=2" %%G IN ('find "PhysicalTrackNumber" "%~1"') DO (
if !track! LSS %%G set "track=%%~G"
)
As an alternative, use findstr instead of find:
FOR /f "tokens=2" %%G IN ('findstr "PhysicalTrackNumber" "%~1"') DO (
if !track! LSS %%G set "track=%%~G"
)

DOS batch FOR loop with FIND.exe is stripping out blank lines?

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:

Resources