My findstr /c:"^string" works in funny way.
To lookup top of each lines using findstr /r with "^", is there any way to put the same query? At least, I found where there's variable as file name, /c:"^^abc" picks up properly, but /c:"^abc" doesn't.
>type test.txt
abc
abc
>type test.bat
setlocal enabledelayedexpansion
set Myfile=test.txt
for /F "usebackq delims=" %%i in (`findstr /n /r /i /c:"^abc" "!Myfile!"`) do (
echo %%i
)
goto :eof
>test.bat
1: abc
2:abc
>
Only when I put 2 "^"s, i.e /c:"^^abc", then,
...
for /F "usebackq delims=" %%i in (`findstr /n /r /i /c:"^^abc" "!Myfile!"`) do (
...
>test.bat
2:abc
>
Or, when I put %Myfile% instead of !Myfile!, it looks working with c:"^abc". But, Myfile will vary through each run. So %variable%, or immediate_value won't work for me.
Is there any ways to put a Universal lookup (any switch available?) so that I don't need to check each time I write codes? This would reduce quite a lot of time to debug.
FYI, Replacing !Myfile! with %%x by putting one more "For" loop works with Single "^". This is the only way I can forget about "^^"against !Myfile! for now.
>type test2.bat
setlocal enabledelayedexpansion
set Myfile=test.txt
for /F "usebackq delims=" %%h in (`dir /a-d /b "!Myfile!"`) do (
for /F "usebackq delims=" %%i in (`findstr /n /r /i /c:"^abc" "%%h"`) do (
echo %%i
)
)
goto :eof
>test2.bat
2:abc
>
Related
I need to set a variable to a substring I get from a find command, but it is returning the command
findstr /is "CouId:" C:\dev\AssayInfo.txt
set number=findstr /is "CouId:" C:\dev\AssayInfo.txt
echo %number%
pause
This is what the file that I'm using findstr looks like:
Protocol: NVD_RCP_Fluidic_Accuracy_v0.4
ProtocolVersion: 1
SampleId: FLQC+20191126+00111280+96
InstrumentId: 123456789001
CouId: 138527011
CouSlot: 1
The variable should have the value 138527011 in this case.
Here you go:
#echo off
for /f "tokens=1,* delims=: " %%i in ('type "C:\dev\AssayInfo.txt" ^| findstr /i CouID') do set "number=%%j"
echo %number%
:# Here you can add your if statements etc.
pause
Note, that this is exactly what you required, as per this question and not the other question and therefore this is all I can give you now.
However, this is not even needed, you can do it without the set variable:
#echo off
for /f "tokens=1,* delims=: " %%i in ('type "C:\dev\AssayInfo.txt" ^| findstr /i CouID') do (
echo %%i
:# Here you can add your if statements etc.
)
pause
Personally, I would use:
#echo off
for /F "tokens=2" %%A IN ('findstr /ibc:"CouId: " C:\dev\AssayInfo.txt') do set "num=%%A"
rem Do some code here:
pause
exit /b 0
which is much shorter.
Note that direct comparisons can be done directly inside the for loop like:
#echo off
setlocal EnableDelayedExpansion
for /F "tokens=2" %%A IN ('findstr /ibc:"CouId: " C:\dev\AssayInfo.txt') do (
set "num=%%A"
rem Do sum comparisons with '!num!', not '%num%'!:
)
pause
exit /b %errorlevel%
Thanks in advance for any help given.
After searching through all relative threads and google search I'm stumped on finding a solution to output a variable name for merging two PDF's.
So I have 100's of PDF's I need to combine (two at a time) in a folder c:/test
The files are set out like below
Company Name Invoice No 123456
Company Name Invoice No 123456 details
Now I have managed to move two files at a time to a different folder and merge them but can't seem to get the desrired output name I'm after which is to put a week ending date in front (or at the end, not fussed) of the first merged filename. Below is the code I have thus far which works but the output file name is blank but gets created.
Very new to batch scripting and would appreciate any help :)
#echo off
setlocal enableextensions enabledelayedexpansion
set pdftk=C:\Program Files (x86)\PDFtk Server\bin\pdftk.exe
set Source=C:\test
set Target=C:\test\test2
set num=2
set filenumber=1
for /F "tokens=1,2 delims=:" %%f in ('dir /b /a-d "%source%\*.pdf" ^| findstr /n "^" ') do (
if %%f leq %num% (
copy "%source%\%%g" "%target%" /y > nul
) else goto endCopy
)
:endCopy
endlocal
for /F "tokens=1,2 delims=:" %%f in ('dir /b /a-d "%target%\*.pdf" ^| findstr /n "^" ') do (
if %%f leq %filenumber% ( set file=%%~nA
)
)
pdftk *.pdf cat output we_19_9_2017_%file%.pdf
In endCopy you are trying to get the name of A whereas you are iterating with f. Use set file=%%~nf to set the name of file or set file=%%~ng for second file.
And move endlocal at the end to expand !file! at the end of script like this (note the !):
:endCopy
set "cmd=dir /b /a-d "%target%\*.pdf" ^| findstr /n "^""
for /F "tokens=1,2 delims=:" %%f in ('%cmd%') do if %%f leq %filenumber% set file=%%~nf
pdftk *.pdf cat output we_19_9_2017_!file!.pdf
endlocal
Read more about DelayedExpansion at: https://ss64.com/nt/delayedexpansion.html
The last command doesn't use the target folder for the input files and thus looks for the input files in the current folder, so either include the path or first change to the target path.
Also you set a path-variable for pdftk but don't use it.
If this path isn't included in the %path% it can't be find.
Try this (untested)
#echo off
setlocal enableextensions enabledelayedexpansion
set "pdftk=C:\Program Files (x86)\PDFtk Server\bin\pdftk.exe"
set "Source=C:\test"
set "Target=C:\test\test2"
set num=2
set filenumber=1
for /F "tokens=1,2 delims=:" %%f in (
'dir /b /a-d "%source%\*.pdf" ^| findstr /n "^" '
) do if %%f leq %num% (
copy "%source%\%%g" "%target%" /y > nul
) else goto endCopy
:endCopy
endlocal
for /F "tokens=1,2 delims=:" %%f in (
'dir /b /a-d "%target%\*.pdf" ^|findstr /n "^" '
) do if %%f leq %filenumber% set file=%%~nf
PushD "%Target%"
"%pdftk%" *.pdf cat output we_19_9_2017_%file%.pdf
PopD
I'm using the following code to get a list of programs being run at start up, and log them to a file.
for /f "skip=2 tokens=1,2*" %%A in ('REG QUERY "HKCU\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Run" 2^>NUL') do echo %%A : %%C >> Log.txt
This works with entries where the value name doesn't contain a space, but when it does, such as with "Google Update", it messes up the tokens, and %%C becomes: REG_SZ <path>, instead of just the path.
Does anyone have a better way to query the registry and log its values?
Well I got one working solution, I'd still love to see if anyone has anything better.
for /f "skip=2 tokens=*" %%A in ('REG QUERY "HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Run" 2^>NUL') do (
set regstr=%%A
set regstr=!regstr: =^|!
for /f "tokens=1,3 delims= |" %%X in ("!regstr!") do (
echo %%X : %%Y
)
)
Version specific, works in XP, does not work in Win 7 - see comments for details.
Columns in the output are separated by tab char (0x09), so use only tab as a separator:
for /f "skip=2 tokens=1,2* delims= " %%A
This does not show well because of how markup handles white chars, but the character after delims= must be actual TAB
Here's a better way via WMI calling the Win32_StartupCommand class, results output to screen as well as a CSV file in the same folder as per script name:
#echo off
setlocal enabledelayedexpansion
cd \ & pushd "%~dp0"
if exist "%~n0.tmp" (del /f /q "%~n0.tmp")
if exist "%~n0.csv" (del /f /q "%~n0.csv")
wmic /namespace:\\root\cimv2 path Win32_StartupCommand get /all /format:csv >"%~n0.tmp"
for /f "tokens=1,2,3,4,5,6,7,8,9 usebackq delims=, skip=2" %%a in (`type "%~n0.tmp"`) do (
echo %%b, %%c >>"%~n0.csv"
echo %%b, %%c
)
if exist "%~n0.tmp" (del /f /q "%~n0.tmp")
popd & endlocal
exit /b 0`
How do I make this grab the token from the first line ONLY in .txt file instead of looping through every line. I want %%m to be assigned to the 3rd token on line one only then stop.
#echo off
FOR %%A IN (.\xdrive\*.txt) DO (
FOR /F "usebackq tokens=3 delims=," %%m IN ("%%A") DO (
IF "%%m" == "F01" (xcopy /Y "%%A" .\Outbound)
pause
)
)
pause
set /p can be used to read the first line, and then you can use a FOR /F loop to get the third token
setlocal EnableDelayedExpansion
FOR %%A IN (%1) DO (
<%%A set /p firstline=
FOR /F "tokens=3 delims=," %%m IN ("!firstline!") DO (
echo %%m
)
)
Without see the eg files and knowing exactly what you're trying to do I can't test this, but here's the listing of firstline.bat which should do what you're asking for :) At first I thought this needed to be more complicated than it is... after your first if simply use a goto to exit the for structure after it's first call - problem solved?
#echo off
::: firstline.bat - Retrieve the first line from a series of files
::: usage: firstline $filespec
::: filespace - files to process (eg .\xdrive\*.txt)
if "%~1"=="" findstr "^:::" "%~f0"&GOTO:EOF
FOR %%A IN (%1) DO (
call :testfirst "%%A"
)
goto :eof
:testfirst
FOR /F "usebackq tokens=3 delims=," %%m IN (%1) DO (
IF "%%m" == "F01" (xcopy /Y %1 .\Outbound)
goto:eof
)
See this post, which shows how to mimic the gnu head utility using a dos batch file:
Windows batch command(s) to read first line from text file
untested
read first line tokens3
for /f "tokens=3 delims=," %%a in ('"findstr /n . %1|findstr /b 1:"') do set fltok3=%%a
echo(%fltok3%
Hackish =
#echo off
FOR %%A IN (.\xdrive\*.txt) DO (
FOR /F "usebackq tokens=3 delims=," %%m IN ("%%A") DO (
IF "%%m" == "F01" (xcopy /Y "%%A" .\Outbound)
GOTO:EOF
)
)
So all you're doing is escaping the loop after the first pass instead of continuing onto the next line.
I'm trying to concatenate many files into two individual files.
The first file will be a concatenation of all other files with "bob" in the filename. The second file will be a concatenation of all files WITHOUT "bob" in the filename. Both files will output the name of the file before actually doing the concatenation.
Here's what I have so far:
#echo off
setlocal EnableDelayedExpansion
set bob=All_bob.txt
set jimmy=All_jimmy.txt
if exist %bob% del %bob%
if exist %jimmy% del %jimmy%
for %%a in (*bob*.txt) do (
echo /* >>%bob%
echo * %%a >>%bob%
echo */ >>%bob%
copy/b %bob%+"%%a" %bob%
echo. >>%bob%
echo. >>%bob%)
for %%a not in (*bob*.txt) do (
echo /* >>%jimmy%
echo * %%a >>%jimmy%
echo */ >>%jimmy%
copy/b %jimmy%+"%%a" %jimmy%
echo. >>%jimmy%
echo. >>%jimmy%)
However, the second FOR loop (at the bottom) doesn't want to play nice using "not", and using an exclamation point like this...
for %%a !(*bob*.txt) do (
...doesn't want to work, either. So how do I concatenate files that do NOT contain what is inside the parenthesis?
I don't think there is a clean solution to this.
You could probably use FINDSTR to filter %%a but that would require turning *bob*.txt into a regular expression and that is probably not easy to automate.
Another (ugly) solution is to use nested loops:
echo bob:
for %%a in (*bob*.txt) do (
echo %%a
)
echo not bob:
for %%a in (*) do (
setlocal ENABLEDELAYEDEXPANSION&set inc=1
for %%b in (*bob*.txt) do if "%%~a"=="%%~b" set inc=0
if "!inc!"=="1" echo %%a
endlocal
)
How about using find:
for /F %%a in ('dir /b *.txt') do (
echo %%a | find /V "bob")
This should return all .txt files that don't have "bob" in them.
Using findstr and a regular expression for *bob*.txt:
for /f "usebackq delims=" %%a in (`dir /b ^| findstr ".*bob.*\.txt"`) do (…)
Just use the /V switch to process all other files:
for /f "usebackq delims=" %%a in (`dir /b ^| findstr /v ".*bob.*\.txt"`) do (…)
You can use the help command or the /? switch for for or findstr for more information.
I cleared the delimiters (delims=) to allow for spaces in the filenames.