Possible to assign a variable to empty line from file .txt? - batch-file

I am using this batch to check if in the second line of my output-mp3.txt outro word exist. If exist will do something, if not exist something else.
My problem is, if the second line is not there, my script ends.
My question is: Can I assign e variable to empty line and say No content or something, when my output-mp3.txt have one single line?
for /f "skip=2 tokens=5 delims=\" %%D in ('find "outro" "output-mp3.txt"')
sometimes my file is like:
file 'F:\...\continut\....\KMU4DP8C.mp3'
file 'F:\......\outro\....\KMU4DP8C.mp3'
and sometimes I don't have the second line
file 'F:\...\continut\....\KMU4DP8C.mp3'
thank you

set "_line1="
set "_line2="
for /f "skip=2 tokens=5 delims=\" %%D in ('find "outro" "output-mp3.txt"') do (
if defined _line1 (set "_line2=%%D") else (set "_line1=%%D")
)
if defined _line2 (echo _line2 was set) else (echo _line2 missing)
if defined _line1 (echo _line1 was set) else (echo _line1 missing)

Related

Batch script to add a line of text to files

I am a novice and found some info here on howto make a script that write a text line to files. The result seems fine (also for multiple files), except that the text ends up at the bottom and I need it at the top.
#echo off
set "$New_line=TEXT"
for /r "C:\" %%A in (*.txt) do >"%%A" echo %$New_line%
#ECHO Off
SETLOCAL
rem The following settings for the source directory, destination directory, target directory,
rem batch directory, filenames, output filename and temporary filename [if shown] are names
rem that I use for testing and deliberately include names which include spaces to make sure
rem that the process works using such names. These will need to be changed to suit your situation.
SET "sourcedir=u:\your files"
set "$New_line=TEXT"
:: a filename that simply won't exist in the subtree and doesn't end ".txt"
SET "dummyfilename=##qqyhnggqvxjr.#$#"
FOR /F "delims=" %%b IN ('dir /b /s/a-d "%sourcedir%\*.txt"') DO (
SET "skipme="
FOR /F "delims=:" %%c IN ('FINDSTR /n /L /C:"%$new_line%" "%%b"') DO IF "%%c" equ "1" SET "skipme=Y"
IF NOT DEFINED skipme (
>"%%~dpb%dummyfilename%" ECHO %$new_line%
TYPE "%%b">>"%%~dpb%dummyfilename%"
MOVE /y "%%~dpb%dummyfilename%" "%%b" >NUL
)
)
GOTO :EOF
I really don't believe you'd want to prepend the text to every .txt file on your c: drive. You should set "sourcedir" to start the processing on a small sample subtree.
The findstr processing looks for %$new_line% as the first line of each file selected by the outer for loop and sets skipme if that condition is found. In this way, the processing is skipped for files that have already been processed.
Re: use of closing parenthesis in added line:
If there are closed-parentheses in the line to be inserted, you need to "escape" the ) with a caret ^ thus : set "$New_line=#Firm_Begin(16368^)"
The reason for this is that batch will render the escaped-) as
IF NOT DEFINED skipme (
>"%%~dpb%dummyfilename%" ECHO #Firm_Begin(16368^)
TYPE "%%b">>"%%~dpb%dummyfilename%"
MOVE /y "%%~dpb%dummyfilename%" "%%b" >NUL
)
and recognise the ^) as an escaped-) hence treat the ) as if it was any regular text character.
Without the escape character, batch interprets the command as
IF NOT DEFINED skipme (
>"%%~dpb%dummyfilename%" ECHO #Firm_Begin(16368)
TYPE "%%b">>"%%~dpb%dummyfilename%"
MOVE /y "%%~dpb%dummyfilename%" "%%b" >NUL
)
This has two consequences.
For files where skipme is not defined, #Firm_Begin(16368 is sent to the dummy file as the first and only line, and the text of the entire file is then added and then fortunately the resultant is moved over the original file so that the dummy file does not exist.
In files where skipme is defined however, only the ...ECHO %$new_line% is skipped. The original file is then typed into the non-existent dummy file, and then the dummyfile overwrites the original - so no damage done....
...Or is there?
findstr...C:"%$new_line%"... discriminates whether to select the file to have the foreword added or not, via the flag skipme. Unfortunately, the value of $new_line now contains ^ and in this instance the ^ does not escape the ) because the /c:"expression" is quoted (as it has to be since the string-value contains spaces), so its contents are taken literally. findstring will search for the literal string #Firm_Begin(16368^), not #Firm_Begin(16368).
cure for this is to remove any ^ from $new_line, so
...'FINDSTR /n /L /C:"%$new_line:^=%" "%%b"'...
and add the /x switch as a refinement so that the string must match the entire line, hence
...
FOR /F "delims=" %%b IN ('dir /b /s/a-d "%sourcedir%\*.txt"') DO (
SET "skipme="
FOR /F "delims=:" %%c IN ('FINDSTR /n /x /L /c:"%$new_line:^=%" "%%b"') DO IF "%%c" equ "1" SET "skipme=Y"
IF NOT DEFINED skipme (
>"%%~dpb%dummyfilename%" ECHO %$new_line%
TYPE "%%b">>"%%~dpb%dummyfilename%"
MOVE /y "%%~dpb%dummyfilename%" "%%b" >NUL
)
)
GOTO :EOF
which should cure the problem.
But then there's the clean-up, where \x can be used to detect files which have #Firm_Begin(16368 as the first line, not #Firm_Begin(16368).
[this part I haven't tested, and unfortunately have no time to test atm]
FOR /F "delims=:" %%c IN ('FINDSTR /n /x /L /c:"%$new_line:~0,-3" "%%b"') DO IF "%%c" equ "1" echo incorrect headline in "%%b"
should indicate the files that suffer that condition. All that would need to be done for any such file detected would be to initialise the dummy file with the correct top line and then use >>"%dummyfile%" for /f "usebackqskip=1delims=" %%L in ("%%b") do echo %%L to append the contents of the file %%b , all but the first line to the dummy file.

Batch script to read a specific line from a log file

I am trying to write a batch script that reads 18th line from a .log file and outputs the same. The .log file name varies each time. abc_XXXX.log where xxxx are process IDs. Below is the code I am trying to run to achieve this.
:Test1
set "xprvar=" for /F "skip=17 delims=" %%p in (abc*.log) do (echo %%p& goto
break)
:break
pause
goto END
set var=anyCommand doesn't work. It just sets the var to the literal string.
The usage of afor /f is the right way, just the variable assignment works different:
for /F "skip=17 delims=" %%p in ('dir /b abc*.log') do ( set "xprvar=%%p"& goto break )
There is also an option using FindStr
#Echo Off
For /F "Tokens=1-2* Delims=:" %%A In ('FindStr/N "^" "abc_*.log" 2^>Nul'
) Do If %%B Equ 18 Echo %%A:%%C
Pause
The above example Echoes the <filename>:<18th line content>, but there's no reason in the appropriate situation why you couldn't change that to read:
#Echo Off
For /F "Tokens=1-2* Delims=:" %%A In ('FindStr/N "^" "abc_*.log" 2^>Nul'
) Do If %%B Equ 18 Set "xprvar=%%C"
If there is more than one matching filename in the directory, the variable would be set to the content in the last file parsed.
#ECHO Off
SETLOCAL
FOR %%f IN (abc*.log) DO (
SET "reported="
FOR /f "skip=17delims=" %%p IN (%%f) DO IF NOT DEFINED reported (
ECHO %%p
SET "reported=Y"
)
)
Assign each filename in turn to %%f.
For each filename found, clear the reported flag then read the file, skipping the first 17 lines. echo the 18th line and set the reported flag so that the remainder of the lines are not echoed.

Extract Part of a text file in BAT

I am capturing a m3U file on a daily basis but wish to parse part of it to another file with the few channels I need.
For example I have renamed my m3U to Test.txt file which say has the following fictional structure:
#EXTINF:0,ABC
#live link 1
#EXTINF:0,XYZ
#live link 2
#EXTINF:0,UVW
#live link 3
I would just like to capture say the line staring from "#EXTINF:0,XYZ" and say the line beneath it to end up with a Output.txt as follows:
#EXTINF:0,XYZ
#live link 2
I know that one needs to use the For loop but I am a bit of a noob on this area.
Put this code into the file filter.cmd.
#echo off
set INPUT=%1&set MATCH=%2& set MATCHED=0
for /f "delims=" %%a in (%INPUT%) do call :line "%%~a"
goto :eof
:line
set EXT=&TITLE=&
for /f "tokens=1 delims=:" %%a in ("%~1") do set EXT=%%~a
for /f "tokens=1,2,* delims=:," %%a in ("%~1") do set TITLE=%%~c
if "%EXT%" == "#EXTM3U" echo %~1
if "%EXT%" == "#EXTINF" (
set MATCHED=0
echo %TITLE%| findstr /l %MATCH% >nul && set MATCHED=1
)
if %MATCHED%==1 echo %~1
Use example:
filter.cmd input_file.m3u XYZ > output_file.m3u
Here is some explanation:
Every input line is split using for /f with tokens and delims.
MATCHED is set if the line begins with #EXTINF and the rest contains the string to match (second argument).
if MATCHED is set, the lines are output until next #EXTINF.
I would do it like this, supposing the .m3u file does not contain trailing white-spaces in the lines preceded by #EXTINF, like your sample data does:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here:
set "FILE=%~1"
set "HEADER=#EXTM3U"
set "PREFIX=#EXTINF"
set "MATCH=%~2"
set "FLAG="
for /F usebackq^ delims^=^ eol^= %%L in ("%FILE%") do (
if defined FLAG (
echo(%%L
set "FLAG="
)
for /F "delims=:" %%P in ("%%L") do (
if "%%P"=="%HEADER%" (
echo(%%L
) else if "%%P"=="%PREFIX%" (
set "LINE=%%L"
setlocal EnableDelayedExpansion
if /I "!LINE:*,=!"=="!MATCH!" (
echo(!LINE!
endlocal
set "FLAG=#"
) else endlocal
)
)
)
endlocal
exit /B
Call the script like this, supposing it is saved as extract-entry.bat:
extract-entry.bat "input_file.m3u" "XYZ" > "output_file.m3u"
The script walks through the given .m3u file line by line. It returns the current line unedited and resets variable FLAG, if variable FLAG is set, which is not the case at the beginning.
Then it looks for #EXTINF. If found (e. g., #EXTINF:0,XYZ), the string after the comma (XYZ) is compared against the given search string. If matched, the current line is output and FLAG variable is set now in order to get the following line too.
The header line #EXTM3U is always output.
Toggling delayed expansion makes this script robust against all characters that have special meaning to the command interpreter without losing them.

For /F doing the loop operations only for one string segment

#echo off
set files=InstallSlinger27.bat:Stash.txt
for /F "delims=:" %%i IN ("%files%") DO (
ECHO %%i
if exist %%i (
echo EXIST
) else (
echo DO NOT EXIST
)
)
I expect the batch file to check if the file InstallSlinger27.bat exists and then check if the file Stash.txt exists.
However, the output is
InstallSlinger27.bat
EXIST
It does not do the verification for the second file.
I tried some things, and I did loops in the past that where working. I don't want to do checks for %%i then %%j, because the files list could grow.
#ECHO OFF
SETLOCAL
set files=InstallSlinger27.bat:Stash.txt
FOR %%a IN ("%files::=","%") DO (
IF EXIST %%a (ECHO %%a exists) else (ECHO %%a missing)
)
GOTO :EOF
Although I'd suggest you re-think your choice of separator since : can occur within a full filename.

batch script - read line by line

I have a log file which I need to read in, line by line and pipe the line to a next loop.
Firstly I grep the logfile for the "main" word (like "error") in a separate file - to keep it small. Now I need to take the seperate file and read it in line by line - each line needs to go to another loop (in these loop I grep the logs and divide it in blocks) but I stuck here.
The log looks like
xx.xx.xx.xx - - "http://www.blub.com/something/id=?searchword-yes-no" 200 - "something_else"
with a for /f loop I just get the IP instead of the complete line.
How can I pipe/write/buffer the whole line? (doesn't matter what is written per line)
Try this:
#echo off
for /f "tokens=*" %%a in (input.txt) do (
echo line=%%a
)
pause
because of the tokens=* everything is captured into %a
edit:
to reply to your comment, you would have to do that this way:
#echo off
for /f "tokens=*" %%a in (input.txt) do call :processline %%a
pause
goto :eof
:processline
echo line=%*
goto :eof
:eof
Because of the spaces, you can't use %1, because that would only contain the part until the first space. And because the line contains quotes, you can also not use :processline "%%a" in combination with %~1. So you need to use %* which gets %1 %2 %3 ..., so the whole line.
The "call" solution has some problems.
It fails with many different contents, as the parameters of a CALL are parsed twice by the parser.
These lines will produce more or less strange problems
one
two%222
three & 333
four=444
five"555"555"
six"&666
seven!777^!
the next line is empty
the end
Therefore you shouldn't use the value of %%a with a call, better move it to a variable and then call a function with only the name of the variable.
#echo off
SETLOCAL DisableDelayedExpansion
FOR /F "usebackq delims=" %%a in (`"findstr /n ^^ t.txt"`) do (
set "myVar=%%a"
call :processLine myVar
)
goto :eof
:processLine
SETLOCAL EnableDelayedExpansion
set "line=!%1!"
set "line=!line:*:=!"
echo(!line!
ENDLOCAL
goto :eof
This has worked for me in the past and it will even expand environment variables in the file if it can.
for /F "delims=" %%a in (LogName.txt) do (
echo %%a>>MyDestination.txt
)
For those with spaces in the path, you are going to want something like this:
n.b. It expands out to an absolute path, rather than relative, so if your running directory path has spaces in, these count too.
set SOURCE=path\with spaces\to\my.log
FOR /F "usebackq delims=" %%A IN ("%SOURCE%") DO (
ECHO %%A
)
To explain:
(path\with spaces\to\my.log)
Will not parse, because spaces.
If it becomes:
("path\with spaces\to\my.log")
It will be handled as a string rather than a file path.
"usebackq delims="
See docs will allow the path to be used as a path (thanks to Stephan).

Resources