How to use a ending number as a variable - batch-file

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"

Related

Find multiple strings in multiple lines

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)

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"
)

Editing text in a file using a batch file

I am trying to edit some lines of text within a text file using a batch file. The lines are as below -
#TEST_RSA_KEY=1
#V3SERVER0=109.73.122.107;29006
#DOWNLOAD0=109.73.122.112;29006
I need to change these to be
#TEST_RSA_KEY=0
#V3SERVER0=91.207.36.31;29006
#DOWNLOAD0=91.207.36.37;29006
How would you recommend I do this via a batch file, I am very new to this and have very basic knowledge so simple and clear answers please! :) Thank you
Not tested
#echo off
set file_loc=C:\text.file.txt
for "usebackq tokens=* delims=" %%a in ("%file_loc%") do (
set "%%a"
)
set "#TEST_RSA_KEY=0"
set "#V3SERVER0=91.207.36.31;29006"
set "#DOWNLOAD0=91.207.36.37;29006"
set #>"%file_loc%"
I've assumed that all properties start with #
Note - I have not tested any of the code examples below, so there could be bugs. But I have successfully used all of the techniques below in the past, and any fixes (if necessary) should be fairly trivial.
All of my solutions below assume that spaces never appear in any of the name value pairs. Each of the solutions could be adapted to support spaces, if necessary.
If the order of the lines is not important, then the following pure batch solution works well and is quite fast. I use FINDSTR to remove the lines that are to be altered, before appending the new values to the end:
#echo off
>"file.txt.new" (
findstr /v /b "#TEST_RSA_KEY= #V3SERVER0= #DOWNLOAD0=" "file.txt"
echo #TEST_RSA_KEY=0
echo #V3SERVER0=91.207.36.31;29006
echo #DOWNLOAD0=91.207.36.37;29006
)
move /y "file.txt.new" "file.txt" >nul
If the order of the lines is important, then I would use my JREPL.BAT utility - a hybrid JScript/batch regular expression text processor. It is pure script that runs natively on any Windows machine from XP onward. I recommend putting the script within a directory that is listed within your path. I like to use "c:\utils" for all my non-standard utilities.
A simple one replacement at a time strategy is the simplest effective solution, and it should be plenty fast unless the file is exceptionally large:
#echo off
call jrepl "^(#TEST_RSA_KEY)=.*" "$1=0" /f "file.txt" /o -
call jrepl "^(#V3SERVER0)=.*" "$1=91.207.36.31;29006" /f "file.txt" /o -
call jrepl "^(#DOWNLOAD0)=.*" "$1=91.207.36.37;29006" /f "file.txt" /o -
The above strategy can be made easy to maintain (add additional replacements) with a bit more code, as long as none of the strings contain * or ?, and no value begins with =:
#echo off
for %%A in (
"#TEST_RSA_KEY=0"
"#V3SERVER0=91.207.36.31;29006"
"#DOWNLOAD0=91.207.36.37;29006"
) do for /f "tokens=1* delims==" %%B in (%%A) do (
call jrepl "^(%%B)=.*" "$1=%%C" /f "file.txt" /o -
)
The * and ? limitation can be removed if the replacement strings are already in a separate file (replace.txt):
#echo off
for /f "tokens=1* delims==" %%A in (replace.txt) do (
call jrepl "^(%%A)=.*" "$1=%%B" /f "file.txt" /o -
)
Or the replacement strings could be embedded within the batch script itself
#echo off
for /f "tokens=1* delims==" %%A in ('findstr "^#" "%~f0"') do (
call jrepl "^(%%A)=.*" "$1=%%B" /f "file.txt" /o -
)
exit /b
#TEST_RSA_KEY=0
#V3SERVER0=91.207.36.31;29006
#DOWNLOAD0=91.207.36.37;29006
The entire job can be done much more efficiently in one pass if you are willing to do the capture group bookkeeping and prepare a long command line (8191 byte length max):
#call jrepl "(#TEST_RSA_KEY)=.* (#V3SERVER0)=.* (#DOWNLOAD0)=.*" "$2=0 $4=91.207.36.31;29006 $6=91.207.36.37;29006" /b /t " " /f "file.txt" /o -
A variation of any of the prior 3 methods could be used to make this efficient solution easier to maintain, as long as ! never appears in the values. For example:
#echo off
setlocal enableDelayedExpansion
set "find="
set "repl="
set "n=0"
for /f "tokens=1* delims==" %%A in ('findstr "^#" "%~f0"') do (
set "find=!find! (%%A)=.*"
set /a n+=2
set "repl=!repl! $!n!=%%B"
)
call jrepl "!find:~1!" "!repl:~1!" /b /t " " /f "file.txt" /o -
exit /b
#TEST_RSA_KEY=0
#V3SERVER0=91.207.36.31;29006
#DOWNLOAD0=91.207.36.37;29006

Using batch to count the number of specific files in folder

I have a bunch of files in a folder that their names are like a1.txt, a6.txt, a8.txt,..and I need to count them I tried this batch file but it does not recognize * as a way to account for all numbers and does not return the correct answer.
set /a count=0
for /F "tokens=* delims= " %%i in ('dir/s/b/a-d "C:\Users\xyz\desktop\Project\a.*"') do (set /a count=count+1)
Can you see what I am doing wrong? Thanks for your help in advance.
You could do this in a single line
dir /a-d "C:\Users\xyz\desktop\Project\a.*" | find /C "/"
Explanation:
dir is the directory listing command. The /a starts an attribute filter and the -d tells dir to not list directories. So all files in that directory with a. as the start of the filename are piped to the find command.
The find command has a built in /C option to count the lines and lines in this case are files.
What you're doing wrong is the wildcard for all files starting with a.
You're using dir a.* and expecting it to find files like a6.txt
Also, to handle filenames with spaces, I suggest you remove the delimiters.
set /a count=0
for /F "delims=" %%i in ('dir/s/b/a-d "C:\Users\xyz\desktop\Project\a*"') do (set /a count=count+1)
( Also listen to the other answers in terms of making your code more efficient. )
Faced with a similiar problem, I prefer to use a trick I learned from Raymond Chen, wich is to use find as a replacement for wc -l.
So the following scrit sets the batch variable count to the number of files that match patttern. Like your original script, directories are excluded from the count.
#echo off
setlocal
set count=0
set pattern=a?.txt
use dir /b %pattern% ^| find /c /v ""
for /f %%i in ('dir /b /a-d %pattern_you_are_looking_for% ^| find /c /v ""') do #call set count=%%i
echo %count%
endlocal
You have your asterisk in the wrong place. I think you intended a*.txt. But that will match any text file whose name begins with "a". It does not limit the results to text files that start with "a", followed by a number.
You can pipe the results of your DIR command to FINDSTR and use a regular expression to be more specific. The FINDSTR regex support is primitive, but it often gets the job done.
I'm going to assume you want to match names like "a1.txt", "a143.txt", but you don't want to match files like "a1b.txt" or "aba1.txt". If I got that wrong then you need to change the regex expression to match your requirements.
This regex \\a[0-9][0-9]*\.txt$ works as follows:
\\ is an escaped backslash, matching the last backslash before the file name
a matches itself of course
[0-9] matches a single digit (there must be at least 1)
[0-9]* matches 0 or more additional digits
\.txt$ escapes the dot and matches the ".txt" extension. The $ matches the end of the string - it will not match if additional characters follow.
The last thing to do is pipe the result of FINDSTR to FIND to let it count the number of files for you. FIND /C /V "" matches any line and the /C option gives the count of matching lines. It is more efficient than incrementing the counter in your loop.
#echo off
setlocal
set /a count=0
for /F %%N in ('dir/s/b/a-d "C:\Users\xyz\desktop\Project\a*.txt"^|findstr /ric:"\\a[0-9][0-9]*\.txt$"^|find /c /v ""') do set count=%%N
echo count=%count%
here's a little bit of a sneaky way to count:
for /f "tokens=1 usebackq" %a in (`dir a* ^| find ^"File^(s^)^"`) do set count=%a
this can be done from the command line - change to double % for a batch file
there is a lot of escaping (using ^) to stop the following characters getting interpreted as part of the batch file, instead of being passed to the command line
The command being executed is dir a* | find "File(s)" , but |,(,) and " tend to have special meanings
#SetLocal enabledelayedexpansion
#for /F "tokens=1" %%a IN ('Dir "..\*.txt" /-C/S/A:-D') Do #Set number_of_files=!n2! & Set n2=%%a
#echo %number_of_files%

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