Findstr, how to read part of string/line - variables

I have file with a list of names and extensions, formatted such as below each on it's own line:
JoeBloggs=102
JohnSmith=109
What I want to do is use findstr but read the number after the equals sign. So I am using the following command:
#echo off
for /F "delims=" %%a in ('findstr /p %username% extensions.txt') do set ext=%%a
If a user logs on as JoeBloggs it will capture JoeBloggs=102, what I want it to do is only capture 102. So essentially only the numbers after the equals sign.

#echo off
for /f "tokens=1,2 delims==" %%a in (names.txt) do (
if "%%a"=="%username%" set ext=%%b
)
echo %ext%
pause >nul
This will read each line of your text file and split it when it comes across an = sign.
I have specified to use tokens 1 and 2, 1 being before the split, and 2 being after so we can compare the first and if it's what you want, use the second.

Related

CMD: extract part of a filename and use it as variable

I ripped my CDs with EAC to CUE+WAV files, added cover art and all my files are in the same folder with filenames pattern "Album artist - Album title", for ex.:
Clannad - Legend.wav/cue/jpg
David Bowie - Best Of Bowie [Disc 1].wav/cue/jpg
David Bowie - Best Of Bowie [Disc 2].wav/cue/jpg
I'm new to this so I wrote a simple CMD batch to convert my music to FLAC format, but it requires manual copying and pasting of the actual wav/cue/jpg filenames and input of album artist, disc no. and total disc no. for their corresponding tags. It cannot be stored in cuesheet file for some reason, but in my case I have them in filenames as you can see above).
ECHO WAV/CUE/JPG FILENAME
SET /P "input="
ECHO ALBUMARTIST
SET /P "albumartist="
ECHO DISCNUMBER
SET /P "discnumber="
ECHO TOTALDISCS
SET /P "totaldiscs="
flac.exe -0 --picture="D:\Music\%input%.jpg" --tag-from-file="CUESHEET=D:\Music\%input%.cue" -T "ALBUMARTIST=%albumartist%" -T "DISCNUMBER=%discnumber%" -T "TOTALDISCS=%totaldiscs%" "D:\Music\%input%.wav"
My question is about automation of converting all my ripped albums. How can I extract album artist/disc no./total disc no. info from filenames and loop that for every .wav file?
#ECHO OFF
SETLOCAL
SET "destdir=U:\destdir"
PUSHD "%destdir%"
:: Find all .jpgs where there is a .wav and .cue with the same name
FOR /f "delims=" %%a IN ('dir /b /a-d *.jpg') DO IF EXIST "%%~na.wav" IF EXIST "%%~na.cue" (
FOR %%b IN (input albumartist discnumber totaldiscs) DO SET "%%b="
SET "input=%%~na"
FOR /f "delims=-" %%b IN ("%%a") DO SET "albumartist=%%b"
FOR /f "tokens=2delims=[]" %%b IN ("%%a") DO SET "disc=%%b"
IF DEFINED disc (
FOR /f "tokens=1delims=[]" %%d IN ("%%a") DO FOR /f %%c IN ('dir /b "%%d[*.wav"') DO SET /a totaldiscs+=1
)
CALL :gflac
)
POPD
GOTO :EOF
:gflac
:: remove trailing spaces from INPUT
IF "%albumartist:~-1%"==" " SET "albumartist=%albumartist:~0,-1%"&GOTO gflac
:: presume default for disc and totaldiscs
IF DEFINED disc (FOR /f "tokens=2" %%d IN ("%disc%") DO SET /a disc=%%d) ELSE (SET /a disc=1)
IF NOT DEFINED totaldiscs SET /a totaldiscs=1
ECHO( flac.exe -0 --picture="D:\Music\%input%.jpg" --tag-from-file="CUESHEET=D:\Music\%input%.cue" -T "ALBUMARTIST=%albumartist%" -T "DISCNUMBER=%discnumber%" -T "TOTALDISCS=%totaldiscs%" "D:\Music\%input%.wav"
GOTO :eof
You would need to change the setting of destdir to suit your circumstances.
The above will merely echo the required flac line. I left it as you posted but set the scant test data you posted up as I interpret it (ie. there is a set of 3 files) on my U: drive.
Sadly, you've given us insufficient information. I've assumed that you need all three files to be present, and the default for totaldiscs is 1.
First, look for all .jpgs, and if there is a corresponding .wav and .cue then process for flac generation as follows:
Set input to the name part of the .jpg found
set albumartist to the first part of the filename, up to the -
get the [disc n] string if it's present
count the number of .wavs that start with the filename up to the [
generate the flac line.
Within the generation of the flac line, we strip off the trailing spaces from input, convert disc n to n or set disc to 1 (although this information may not be needed), and set the totaldiscs to 1 if it's not been calculated.
You don't say what flac produces as output, but I'd suggest that you further gate that filetype so that the procedure doesn't run if the %input%.finalproductwhateverthatis file is present.
[edited per dbenham's comments]
This is very similar to Magoo's answer, with some bug fixes, and everything is done in one master loop without a CALL. As with Magoo's answer, modify your destination folder at the beginning to suit your needs.
#echo off
:: Delayed expansion must be disabled to protect ! when expanding FOR variables.
:: It is normally disabled by default, but I'm making it explicit, just to be sure.
setlocal disableDelayedExpansion
:: Define where source files are coming from
set "source=D:\Music"
:: Define where output should be stored
set "destination=D:\Music"
pushd "%destination%"
:: Iterate each .wav file (A) and only proceed if .jpg and .cue also exists
for /f "delims=" %%A in ('dir /b /a-d "%source%\*.wav"') do if exist "%source%\%%~nA.jpg" if exist "%source%\%%~nA.cue" (
%= Get base name with path, but without extension =%
set "file=%source%\%%~nA"
%= Extract "artist - album " (B) and "Disc #" (C) from base name (~nA) =%
for /f "delims=[] tokens=1,2" %%B in ("%%~nA") do (
%= Extract "artst " (D) from "artist - abum ". (~nxD) trims trailing space =%
for /f "delims=-" %%D in ("%%B") do set "artist=%%~nxD"
%= Extract the number (E) from "Disc #", use 1 as default if not there =%
set "disc=1"
for /f "tokens=2" %%E in ("%%C") do set "disc=%%E"
%= Count the number of discs (F), will be 0 if no [Disc #] =%
%= The [ is appended to name to prevent something like "Greatest Hits 2" from matching "Greatist Hits" =%
for /f %%F in ('dir /b /a-d "%source%\%%B[*.wav" 2^>nul ^|find /c /v ""') do set "count=%%F"
%= temporarily enable delayed expansion to access variables set within loop =%
setlocal enableDelayedExpansion
%= Set count to 1 if no [Disc #] =%
if !count! equ 0 set /a count=1
flac.exe -0 --picture="!file!.jpg" --tag-from-file="CUESHEET=!file!.cue" -T "ALBUMARTIST=!artist!" -T "DISCNUMBER=!disc!" -T "TOTALDISCS=!count!" "!file!.wav"
%= pop the setlocal stack to get back to state at beginning of loop =%
endlocal
)
)
popd
You may want to add a check to only proceed if the FLAC file does not already exist so you can run the script multiple times without reprocessing files. The outer loop would look something like this, but I can't be sure since I don't know the format of the output file name:
for /f "delims=" %%A in ('dir /b /a-d "%source%\*.wav"') do if exist "%source%\%%~nA.jpg" if exist "%source%\%%~nA.cue" if not exist "%destination%\%%~nA.flac" (
The logic is much simpler using my JREPL.BAT utility if you understand regular expressions:
#echo off
:: Delayed expansion must be disabled to protect ! when expanding FOR variables.
:: It is normally disabled by default, but I'm making it explicit, just to be sure.
setlocal disableDelayedExpansion
:: Define where source files are coming from
set "source=D:\music"
:: Define where output should be stored
set "destination=D:\music"
pushd "%destination%"
:: Iterate all *.wav and use JREPL to format result as "fullFileName|artist - album|artist|Disc#"
:: %%A %%B %%C %%D
:: Only proceed if .jpg and .cue also exist
for /f "tokens=1-4 delims=|" %%A in (
'dir /b /a-d "%source%\*.wav"^|jrepl "^((.+?) - .+?)(?:\[Disc (\d+)])?\.wav$" "$&|$1|$2|$3" /i'
) do if exist "%%~nA.jpg" if exist "%%~nA.cue" (
%= disc and count are both 1 if %%D is empty =%
if "%%D" equ "" (
flac.exe -0 --picture="%source%\%%~nA.jpg" --tag-from-file="CUESHEET=%source%\%%~nA.cue" -T "ALBUMARTIST=%%C" -T "DISCNUMBER=1" -T "TOTALDISCS=1" "%source%\%%A"
%= else count the number of .wav files =%
) else for /f %%E in ('dir /b /a-d "%%B[*.wav"^|find /c /v ""') do (
flac.exe -0 --picture="%source%\%%~nA.jpg" --tag-from-file="CUESHEET=%source%\%%~nA.cue" -T "ALBUMARTIST=%%C" -T "DISCNUMBER=%%D" -T "TOTALDISCS=%%E" "%source%\%%A"
)
)
popd
Again, you can add an IF to the outer loop to proceed only if the .flac file does not already exist in the destination.

Saving command into variable

I've question about this variables.How can I store result of a command into a variable? For example: saving drive serial into location variable.
thanks.
E.g:
#ECHO OFF
SET location=vol
ECHO We're working with %location%
for /f "delims=" %%x in ('your command and parameters') do set "var=%%x"
where the 'single quotes' are required around the command from which you wish to save output.
Edit - now we know which command.
Comment - one variable can contain up to ~8,000 characters.
Here's a routine that will set the values in $1...$whatever and the entire set in $all with each field enclosed in angle-brackets.
#ECHO OFF
SETLOCAL
SET "$all="
FOR /f "tokens=1*delims=:" %%a IN (
'systeminfo 2^>nul^|findstr /n /r "$"'
) DO (
SET "$%%a=%%b"
FOR /f "tokens=*" %%c IN ("%%b") DO CALL SET "$all=%%$all%%<%%c>"
SET /a max=%%a
)
SET $
pause
FOR /l %%z IN (1,1,%max%) DO CALL ECHO %%$%%z%%
GOTO :EOF
thank you...please see my batch file contents:
for /f "delims=" %%x in ('systeminfo') do set "var=%%x"
command_line.exe %var%
only last line of 'systeminfo' saved in var variable and it is:
"data execution perevention available: yes"
I want to store all contetnt of systeminfo into variable!
thank you.I'm too basic
do you mean result of systeminfo is into all variable? at the end of your code can I add this command:
start command_line.exe $%all%
is this true?
can you put complete code for my batch file?

Insert Input into a variable

I'm working on a batch script for fun and learning.
I've set up multiple choises, e.g Fint IP address, MAC address...and so on.
The problem is that i can't find out how i can insert the output of those two lines into variables.
for /f "usebackq skip=1" %%f in (`wmic COMPUTERSYSTEM get name`) do ???
for /f "usebackq skip=1" %%f in (`wmic COMPUTERSYSTEM get domain`) do ???
So I can use the output in a sentence like;
Your DNS-name is %dns_name_output% and your domain is %domain_name_output%.
try this:
for /f %%f in ("%computername%") do set "name=%%f"
for /f %%f in ("%userdomain%") do set "domain=%%f"
echo %name% %domain%
To capture wmic get output, use the /value flag like this
for /f "tokens=2 delims==" %%A in ('wmic computersystem get name /value') do set "Name=%%A"
for /f "tokens=2 delims==" %%A in ('wmic computersystem get domain /value') do set "Domain=%%A"
The problem you are seeing arises from the fact that WMIC output is in unicode. By some mechanism that I do not fully understand (a bug?), the FOR /F command transforms the unicode command output into ASCII, but mysteriously appends an extra carriage return (<CR>) at the end of each line.
FOR /F does not return empty lines, but the mysterious and seemingly blank lines are not really blank - they contain a <CR>.
Even if the extra lines are properly ignored, the last value in the list will include an unwanted <CR> that is included when assigning the value to an environment variable. The <CR> will not be apparent if the variable is later expanded normally using %VAR% because the command parser automatically strips all <CR> characters. But the <CR> is preserved and can cause problems if delayed expansion !VAR! is used.
The FOR /F command strips the last character from each line if it happens to be a <CR>. So passing the value through an extra FOR /F will eliminate the problem. David Ruhman's suggestion to use the /value switch is a good one, and can be improved upon. Multiple values may be requested in one loop, and the property name can be used as the variable name. Having only one name/value pair per line eliminates potential parsing problems with spaces and or commas in values.
The commas in the WMIC command must either be escaped or quoted when used within FOR /F. In this case, quoting the entire command seems easiest. The following will properly define two environment variables - Domain, and Name:
for /f "delims=" %%A in ('"wmic computersystem get domain, name /value"') do (
for /f "tokens=1* delims==" %%B in ("%%A") do set "%%B=%%C"
)
echo Your host name is %name% and your domain is %domain%
This works using wmic without any odd spaces or CRs embedded.
#echo off
for /f "tokens=2 delims=<>" %%a in ('wmic COMPUTERSYSTEM get name /format:htable^|find "hidden"') do set "name=%%a"
for /f "tokens=2 delims=<>" %%a in ('wmic COMPUTERSYSTEM get domain /format:htable^|find "hidden"') do set "dom=%%a"
echo "%name%,%dom%"
pause
You can define a variable, and assign it's value to the result of a command using back-tick enclosure.
Try this:
a=`ls`
echo $a

Get variable values used inside a loop for outside of the loop

I need to get a part of some lines(Myfile) out of the 'for' loop either into two separate variables or into an array.My goal is to use each other for constituting path of the following lines result*.txt. I write what you are seing below but it's visible that my 'a' variable is only echoing 'C:\Temp\FR'(the end of line matching token in Myfile).
Please, Is there any way to get all matching tokens in a variable/array? For example, in my case, I need to get 'C:\Temp\USA' and 'C:\Temp\FR' out of the loop for? Thanks
for /f "tokens=2 delims==" %%x in (Myfile) do (
set a=%%x
)
echo %a%
'MyFile
DIR1= C:\Temp\USA
DIR2= C:\Temp\FR
result1.txt
result2.txt
Try this:
#echo off&setlocal
for /f "tokens=1* delims== " %%x in (Myfile) do (
if /i "%%x"=="dir1" set "path1=%%y"
if /i "%%x"=="dir2" set "path2=%%y"
)
echo %path1%
echo %path2%
Output is:
C:\Temp\USA
C:\Temp\FR
There are several ways to do that. If you want read a few lines from the beginnng of the file, the easiest way is to directly read them in a couple variables:
< Myfile (
set /P var1=
set /P var2=
)
Note that these variables contain the complete lines, so it is necessary to extract the part after the equal sign.
In your example you just want the lines with equal sign, so we may use findstr "=" Myfile in a FOR command to just process they. If the number of lines is undefined, you must save all desired lines in an array as you suggested:
setlocal EnableDelayedExpansion
set n=0
for /F "tokens=2 delims==" %%a in ('findstr "=" Myfile') do (
set /A n+=1
set var[!n!]=%%a
)
rem Show all array elements
for /L %%i in (1,1,%n%) do (
echo !var[%%i]!
)
rem Show just the second element
echo %var[2]%
However, in your particular case the lines you want have the form of variable assignments. This means that if you execute such lines with a SET command, the values in the lines will be "automatically" saved:
for /F "delims=" %%a in ('findstr "=" Myfile') do set %%a
After previous FOR , you may directly get the values of DIR1 or DIR2 variables, for example:
echo %DIR1%
echo %DIR2%
This method is very simple and don't require any testing on the individual variables being loaded.
If you want to remove the space after the equal sign in the value, you may adjust FOR options to do so:
for /F "tokens=1* delims== " %%a in ('findstr "=" Myfile) do set %%a=%%b

How to delete a line of a text file, given the line number using batch (.bat) script?

I want to write a batch script where the user can enter the line number and the script will delete that line of a text file.
Eg: tmp.txt
1. aaa
2. bbb
3. ccc
4. ddd
I want when i execute my script and user inputs 3, the tmp.txt to be
1. aaa
2. bbb
4. ddd
I am trying something like this:
#ECHO OFF
SET /P LINENUMBER=Enter the Line No:
FOR /F "tokens=1* delims=[]" %%a IN ('FIND /n /v "" ^< tmp.txt') DO (
IF %%a equ %LINENUMBER% (
????????????????????
)
)
You cannot modify the file directly. You must create a new file with the desired content and then replace the original file with the new file.
You create the new file by redirecting output and ECHOing the desired content. I use ECHO(%%b in case %%b is empty because the line was blank. ECHO %%b would produce ECHO is off. if b is empty. Most people use ECHO., but that can fail under esoteric conditions. ECHO( will never fail.
You use MOVE to replace the original file with the new.
You can eliminate the need to check for the number within your FOR /F loop by using FINDSTR after FIND to filter out the unwanted line.
Note that your code, as written so far, will strip any leading [ and ] characters from each line. Because the line filter is applied before the FOR iteration, you can improve the situation slightly by setting DELIMS to ] only.
#ECHO OFF
SET /P LINENUMBER=Enter the Line No:
>tmp.txt.new (
FOR /F "tokens=1* delims=]" %%a IN (
'FIND /n /v "" ^<tmp.txt^|FINDSTR /VLB "[%LINENUMBER%]"'
) DO ECHO(%%b
)
>nul MOVE /y tmp.txt.new tmp.txt
If any of your original lines already begin with ] then you can use FINDSTR instead of FIND to introduce the line number. That uses nn: format instead of [nn]. This solution will strip leading : from your lines.
#ECHO OFF
SET /P LINENUMBER=Enter the Line No:
>tmp.txt.new (
FOR /F "tokens=1* delims=:" %%a IN (
'FINDSTR /n "^" tmp.txt^|FINDSTR /VLB "%LINENUMBER%:"'
) DO ECHO(%%b
)
>nul MOVE /y tmp.txt.new tmp.txt
If your text file contains lines that begin both with : and ] then you can't use FOR /F to parse out the line number. Instead you use search and replace. Delayed expansion is toggled on and off within the loop to protect any ! that may exist in the file.
#ECHO OFF
setlocal disableDelayedExpansion
SET /P LINENUMBER=Enter the Line No:
>tmp.txt.new (
FOR /F "delims=" %%a IN (
'FINDSTR /n "^" tmp.txt ^| FINDSTR /VLB "%LINENUMBER%:"'
) DO (
set "ln=%%a"
setlocal enableDelayedExpansion
echo(!ln:*:=!
endlocal
)
)
>nul MOVE /y tmp.txt.new tmp.txt
try out this:
#echo off & setlocal
set "InFile=Z:\Text.txt"
set "OutFile=Z:\Erg.txt"
set /p LineToDelete=
if exist "%OutFile%" del "%OutFile%"
for /f "tokens=1* delims=:" %%i in ('findstr /n $ "%InFile%"^|findstr /b "%LineToDelete%:"') do findstr /v /b /c:"%%j" "%InFile%">>"%OutFile%"