I am trying to write a Windows batch script which can replace text with an incremented counter.
I have a playlist with tv channels and I would like to replace each channel number throughout the playlist.
My playlist has this structure:
#EXTM3U
#EXTINF:-1,ACS NETWORK TV
http://127.0.0.1:6878/ace/getstream?id=***&.mp4
#EXTINF:-1,Ani
http://127.0.0.1:6878/ace/getstream?id=***&.mp4
#EXTINF:-1,Boomerang HD (France)
http://127.0.0.1:6878/ace/getstream?id=***&.mp4
#EXTINF:-1,BoomerŠ°ng TV
http://127.0.0.1:6878/ace/getstream?id=***&.mp4
I want to replace #EXTINF:-1, with:
#EXTINF:-1, 1
#EXTINF:-1, 2
#EXTINF:-1, 3
#EXTINF:-1, 4
etc.
My script have following structure:
findstr /c:"EXTINF" "C:\Users\home\Links\Desktop\TV-Playlist.m3u" | find /c /v "GarbageStringDefNotInYourResults" > C:\Users\home\Links\Desktop\1111.count
set /p VAR=< C:\Users\home\Links\Desktop\1111.count
for /L %%n in (1,1,%VAR%) do (
setlocal enableextensions disabledelayedexpansion
set "search=#EXTINF:-1,"
set "replace=#EXTINF:-1,!%%n! "
set "textFile=C:\Users\home\Links\Desktop\TV-Playlist.m3u"
for /f "delims=" %%i in ('type "%textFile%" ^& break ^> "%textFile%" ') do (
set "line=%%i"
setlocal enabledelayedexpansion
>>"%textFile%" echo(!line:%search%=%replace%!
endlocal
)
)
Here is one solution based on your code:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "PlayListFile=C:\Users\home\Links\Desktop\TV-Playlist.m3u"
if not exist "%PlayListFile%" goto EndBatch
set "Counter=1"
for /F "delims= eol=" %%I in ('type "%PlayListFile%" ^& break ^> "%PlayListFile%" ') do (
set "Line=%%I"
setlocal EnableDelayedExpansion
if "!Line:#EXTINF:-1,=!" == "!Line!" (
>>"%PlayListFile%" echo(!Line!
endlocal
) else (
>>"%PlayListFile%" call echo !Line:#EXTINF:-1,=#EXTINF:-1,%%Counter%% !
endlocal
set /A Counter+=1
)
)
:EndBatch
endlocal
But it removes empty lines from file because FOR always ignores empty lines.
This code keeps also empty lines:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "PlayListFile=C:\Users\home\Links\Desktop\TV-Playlist.m3u"
if not exist "%PlayListFile%" goto EndBatch
set "Counter=1"
set "TempFile=%TEMP%\%~n0.tmp"
(for /F "delims= eol=" %%I in ('%SystemRoot%\System32\findstr.exe /N /R "^" "%PlayListFile%"') do (
set "Line=%%I"
setlocal EnableDelayedExpansion
set "Line=!Line:*:=!"
if not defined Line (
echo(
endlocal
) else if "!Line:#EXTINF:-1,=!" == "!Line!" (
echo(!Line!
endlocal
) else (
call echo !Line:#EXTINF:-1,=#EXTINF:-1,%%Counter%% !
endlocal
set /A Counter+=1
)
))>"%TempFile%"
if not %Counter% == 1 move /Y "%TempFile%" "%PlayListFile%"
if exist "%TempFile%" del "%TempFile%"
:EndBatch
endlocal
For details on this solution see How to read and print contents of text file line by line?
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
del /?
echo /?
endlocal /?
findstr /?
for /?
goto /?
if /?
move /?
set /?
setlocal /?
So, if I understand your question, and if I can do one suggest:
Put 1 for to handle the counter and do rename the string, after all, replace the file:
#echo off && setlocal enableextensions enabledelayedexpansion
set _m3u_file_in="%userprofile%\Links\Desktop\TV-Playlist.m3u"
set _m3u_file_out="%userprofile%\Links\Desktop\TV-Playlist_New.m3u"
set _cnt=0&& type nul >!_m3u_file_out!
for /f "tokens=* delims= " %%i in ('type !_m3u_file_in! ^|findstr /lbc:"#EXTINF:-" ^|findstr /r "[0-9][\,]" ') do (
set "_old_=%%i"&& call set /a _cnt=!_cnt! + 1
set "_new_=#EXTINF:-1,!_cnt!!_new:~10!"
)
echo/ Total lines replace: !_cnt!
move /y !_m3u_file_out! !_m3u_file_in!
Related
I'm making a batch script to stop several services , however i get the syntax is incorrect error at second FOR which loops in serviceList.TEMP
setlocal EnableDelayedExpansion
setlocal enableExtensions
::queryex output file
sc queryex>services.TEMP
find /i /N "DISPLAY_NAME: Hotspot" services.TEMP>tmp1.TEMP
FOR /F "skip=2" %%G in (tmp1.TEMP) do (
set num=%%G
set num=!num:~1,3!
echo !num!>serviceList.TEMP
)
FOR %%X in (serviceList.TEMP) do (
set /a "SKIP_LINES=%%G+7"
set secondForFilter="skip=%SKIP_LINES%"
FOR /F %secondForFilter% %%Z in (services.TEMP) do (
call debug.cmd REM debug.cmd -> echo debug pause>nul
set serv=%%Z
set "serv=!serv: =!" REM Extract PID
set "serv=!serv::=!" REM Extract PID
set procID=!serv!
taskkill /pid %procID% /f >>debug.txt 2>>debug.txt
goto secondLoopEnd
)
:secondLoopEnd
)
del /S *.TEMP >>debug.txt 2>>debug.txt
the problem is here:
FOR %%X in (serviceList.TEMP) do (
set /a "SKIP_LINES=%%G+7"
set secondForFilter="skip=%SKIP_LINES%"
FOR /F %secondForFilter% %%Z in (services.TEMP) do (
call debug.cmd REM debug.cmd -> echo debug pause>nul
the usual approach when you set value in brackets context is to use delayed expansion but it wont work for parametrized for options.
Here you'll need a subroutine.
And you have GOTO in the for loop. GOTO breaks for context and the loops will be not called after goto is executed.
And rem cannot be used on the same line as the code without "&"
Consider something like this (though I cannot check the logic of the bat):
setlocal EnableDelayedExpansion
setlocal enableExtensions
::queryex output file
sc queryex>services.TEMP
find /i /N "DISPLAY_NAME: Hotspot" services.TEMP>tmp1.TEMP
FOR /F "skip=2" %%G in (tmp1.TEMP) do (
set num=%%G
set num=!num:~1,3!
echo !num!>serviceList.TEMP
)
FOR %%X in (serviceList.TEMP) do (
call :subroutine %%G
)
del /S *.TEMP >>debug.txt 2>>debug.txt
exit /b %errorlevel%
:subroutine
setlocal enableDelayedExpansion
set /a skiplines=%~1+7
set "filter="skip=%skiplines%""
FOR /F %filter% %%Z in (services.TEMP) do (
call debug.cmd
set serv=%%Z
rem extract PID
set "serv=!serv: =!"
set "serv=!serv::=!"
set procID=!serv!
taskkill /pid !procID! /f >>debug.txt 2>>debug.txt
goto :break_for
)
:break_for
endlocal
exit /b
Should the > in your echo to serviceList.TEMP be a >> so that you append to the file?
echo !num!>>serviceList.TEMP
In which case, you should also ensure that the file is deleted prior to the appending operations.
Also, I assume you missed the /F from your FOR loop, as you're trying to read the lines of the serviceList.TEMP file, yes?
FOR %%X in (serviceList.TEMP) do (
Should be...
FOR /F %%X in (serviceList.TEMP) do (
?
Also, you can append to the same file with both std out and err by doing this...
someprocesshere 1> out.log 2>&1
I have a Java program that appends new builds information in the last two lines of a file.
How can I read them in batch file?
This code segment do the trick...
for /F "delims=" %%a in (someFile.txt) do (
set "lastButOne=!lastLine!"
set "lastLine=%%a"
)
echo %lastButOne%
echo %lastLine%
EDIT: Complete TAIL.BAT added
This method may be modified in order to get a larger number of lines, that may be specified by a parameter. The file below is tail.bat:
#echo off
setlocal EnableDelayedExpansion
rem Tail command in pure Batch: Tail.bat filename numOfLines
rem Antonio Perez Ayala
for /F "delims=" %%a in (%1) do (
set /A i=%2, j=%2-1
for /L %%j in (!j!,-1,1) do (
set "lastLine[!i!]=!lastLine[%%j]!
set /A i-=1
)
set "lastLine[1]=%%a"
)
for /L %%i in (%2,-1,1) do if defined lastLine[%%i] echo !lastLine[%%i]!
2ND EDIT: New version of TAIL.BAT added
The version below is more efficient:
#echo off
setlocal EnableDelayedExpansion
rem Tail command in pure Batch, version 2: Tail.bat filename numOfLines
rem Antonio Perez Ayala
set /A firstTail=1, lastTail=0
for /F "delims=" %%a in (%1) do (
set /A lastTail+=1, lines=lastTail-firstTail+1
set "lastLine[!lastTail!]=%%a"
if !lines! gtr %2 (
set "lastLine[!firstTail!]="
set /A firstTail+=1
)
)
for /L %%i in (%firstTail%,1,%lastTail%) do echo !lastLine[%%i]!
This will solve the problem, where someFile.txt is the file where you want to read the lines from:
for /f %%i in ('find /v /c "" ^< someFile.txt') do set /a lines=%%i
echo %lines%
set /a startLine=%lines% - 2
more /e +%startLine% someFile.txt > temp.txt
set vidx=0
for /F "tokens=*" %%A in (temp.txt) do (
SET /A vidx=!vidx! + 1
set localVar!vidx!=%%A
)
echo %localVar1%
echo %localVar2%
del temp.txt
::change the values bellow with a relevant ones.
set "file=C:\some.file"
set "last_lines=2"
for /f %%a in ('findstr /R /N "^" "%file%" ^| find /C ":"') do #set lines=%%a
set /a m=lines-last_line
more +%m% "%file%"
Directly from the command line:
C:\>set "file=C:\some.file"
C:\>set "last_lines=5"
C:\>(for /f %a in ('findstr /R /N "^" "%file%" ^| find /C ":"') do #set lines=%a)&#set /a m=lines-last_lines&call more +%m% "%file%"
Using Windows Batch script, I need the output as shown below. Please help.
Input:
APP "Default Web Site/" (applicationPool:DefaultAppPool)
APP "Default Web Site/App1" (applicationPool:App1)
APP "Default Web Site/App1/Pages" (applicationPool:App1)
App "Site1/App2/" (applicationPool:App2)
App "Site1/App3/VD1" (applicationPool:VD1)
Output:
Default Web Site
Site1
This works with the sample data.
#echo off
(for /f "delims=/" %%a in (file.txt) do (
for /f "tokens=1,*" %%b in ("%%~a") do (
echo %%~c
)
))>temp.fil
sort <temp.fil |uniq
del temp.fil
pause
The code below is uniq.bat
Place uniq.bat in the same folder as the batch file above or in a directory on the path.
#if (#CodeSection == #Batch) #then
#CScript //nologo //E:JScript "%~F0" & goto :EOF & Rem aacini 2013
#end
var line, prevLine = "";
while ( ! WScript.Stdin.AtEndOfStream ) {
line = WScript.Stdin.ReadLine();
if ( line != prevLine ) {
WScript.Stdout.WriteLine(line);
prevLine = line;
}
}
#echo off
setlocal
set "arg_two=%~2"
for /f "tokens=1 delims=/" %%a in ("%arg_two%") do echo %%a
endlocal
test:
outputparser.bat APP "Default Web Site/" (applicationPool:DefaultAppPool)
>Default Web Site
outputparser.bat App "Site1/App3/VD1" (applicationPool:VD1)
>Site1
But if you set quotes around the input it will not work.
EDIT with a file to process (content is the same as in the question):
#echo off
setlocal
set "file_to_process=.\input_file.txt"
for /f "usebackq tokens=1 delims=(" %%W in ("%file_to_process%") do (
for /f usebackq^ tokens^=2^ delims^=/^" %%a in ('%%~W') do (
echo %%a
)
)
endlocal
#echo off
setlocal enableextensions enabledelayedexpansion
set "inputFile=c:\somewhere\file.dat"
rem Extract the required part of the lines
set "tempFile=%temp%\%~nx0.%random%.tmp"
> "%tempFile%" (
for /f usebackq^ tokens^=2^ delims^=^/^" %%a in ("file.txt") do (echo(%%a)
)
rem Remove the duplicates from the list
set "previous="
for /f "tokens=*" %%f in ('type "%tempFile%" ^| sort') do (
if not "%%f"=="!previous!" (
echo(%%f
set "previous=%%f"
)
)
rem Cleanup
del "%tempFile%" >nul 2>nul
endlocal
It uses the quotes and slashes as delimiters to cut the lines on the required points. Then the list is sorted to eliminate duplicates from the output
#echo off
setlocal enableDelayedExpansion
set "val="
for /f tokens^=2^ delims^=/^" %%A in ('sort input.txt') do (
if "!val!" neq "%%A" echo %%A
set "val=%%A"
)
In the unlikely event that a value may contain !, then you would need
#echo off
setlocal disableDelayedExpansion
set "val="
for /f tokens^=2^ delims^=/^" %%A in ('sort input.txt') do (
set "new=%%A"
setlocal enableDelayedExpansion
if "!val!" neq "!new!" echo !new!
endlocal
set "val=%%A"
)
I'm trying to make a loop that goes through a file with filenames on each line, set the first filename as a variable and execute the rest if the script. Then take the second line and do the same.
etc. etc.
The problem is that it only does the first line of filenames.txt
#echo off
for /F "tokens=*" %%G in (filenames.txt) do (
set filename=%%G
script
script
script
)
pause
It has be a batch file.
The whole script:
#ECHO OFF
for /F "tokens=*" %%G in (filenames.txt) do (
SET FileName=%%G
SET Word1="ts_confirmImplicitSAMM.gram"
SET Word2="SWIrcnd"
for /f "tokens=3" %%f in ('find /c /i %Word1% %FileName%') do set PairsToShow=%%f
SET /a Lines1=0, Lines2=0
FOR /f "delims=" %%a IN ('findstr "%Word1%" "%FileName%"') DO (
SET "str=%%a"
SET /a Lines1+=1
SETLOCAL enabledelayedexpansion
SET "$1!Lines1!=!str!"
FOR /f "tokens=1*delims==" %%b IN ('set "$1"') DO (IF "!"=="" endlocal)&SET "%%b=%%c"
)
FOR /f "delims=" %%a IN ('findstr "%Word2%" "%FileName%"') DO (
SET "str=%%a"
SET /a Lines2+=1
SETLOCAL enabledelayedexpansion
SET "$2!Lines2!=!str!"
FOR /f "tokens=1*delims==" %%b IN ('set "$2"') DO (IF "!"=="" endlocal)&SET "%%b=%%c"
)
SET /a Lines=Lines1+Lines2
ECHO(%Lines% lines read from %FileName%.
IF %Lines1% leq %Lines2% (SET /a MaxPairs=Lines1) ELSE SET /a MaxPairs=Lines2
IF %PairsToShow% gtr %MaxPairs% (
ECHO only text for %MaxPairs% pairs NOT %PairsToShow% :/
GOTO :END
)
(FOR /l %%a IN (1,1,%PairsToShow%) DO (
SETLOCAL ENABLEDELAYEDEXPANSION
CALL SET "Line1=%%$1%%a%%"
CALL SET "Line2=%%$2%%a%%"
<NUL SET /p "=!Line1!"
ECHO !Line2!
ENDLOCAL
))>> result1.txt
ENDLOCAL
TYPE result1.txt| FINDSTR /V EVNT=SWIgrld >> result.txt
DEL result1.txt
PAUSE
)
Without seeing the rest of your script... you probably need to do 1 of 2 things:
Use SETLOCAL ENABLEDELAYEDEXPANSION (as 2nd line of your script) and then reference the variable filename as !filename! instead of %filename% to use the run-time value instead of the load-time value. But that could cause other problems, depending on what goes on in "script".
Just use %%G instead of filename
I want to insert a line which has a command(mkdir/copy) in a batch file after a particular line using a batch file.(mkdir/copy command should be considered as a word rather than command)
Input:
set MTBBankpath=C:\InstallerOutput\QuickBooks-Sync\MTB
copy /Y %QBprovisionpath%\x86\Debug %ConnectorExecutionPath%\x86\Debug
Output:
set MTBBankpath=C:\InstallerOutput\QuickBooks-Sync\MTB
copy /Y %ConnectorExecutionPath%\%outqbsyncpath%
mkdir /Y %ConnectorExecutionPath%\%outqbsyncpath%
copy /Y %QBprovisionpath%\x86\Debug %ConnectorExecutionPath%\x86\Debug
A New line copy /Y %ConnectorExecutionPath%\%outqbsyncpath% - which has a copy command and mkdir /Y %ConnectorExecutionPath%\%outqbsyncpath% which has mkdir command, get inserted after a particular line set MTBBankpath=C:\InstallerOutput\QuickBooks-Sync\MTB
SETLOCAL ENABLEDELAYEDEXPANSION
set inputFile=%userprofile%\desktop\testSO.bat
set outputFile=%userprofile%\desktop\testSOout.bat
set _strInsert=set IndbBankpath=C:\InstallerOutput\QuickBooks-Sync\indb
set _strFind=set MTBBankpath=C:\InstallerOutput\QuickBooks-Sync\MTB
set i=0
FOR /F "usebackq tokens=1 delims=[]" %%A IN (FIND /N "%_strFind%" "%inputFile%") DO (set _strNum=%%A)
FOR /F "usebackq delims=" %%A IN ("%inputFile%") DO (
set /a i = !i! + 1
ECHO %%A>>"%outputFile%"
IF [!i!] == [%_strNum%] (
ECHO %_strInsert%>>"%outputFile%"
ECHO I WANT TO ADD THIS LINE ALSO>>"%outputFile%"
ECHO OOOO THIS LiNE TOO>>"%outputFile%"
ECHO ZOMGBBQSAUCE ADD THIS LINE ALSO>>"%outputFile%"
)
)
The above code doesn't work if I change set _strInsert=copy /Y %ConnectorExecutionPath%\%outqbsyncpath% or set _strInsert=mkdir %ConnectorExecutionPath%\%outqbsyncpath%
Please suggest a solution for this.
#echo off
set "particularLine=set MTBBankpath=C:\InstallerOutput\QuickBooks-Sync\MTB"
setlocal DisableDelayedExpansion
if exist output.bat del output.bat
for /F "delims=" %%a in (input.bat) do (
echo %%a
set "line=%%a"
setlocal EnableDelayedExpansion
if "!line!" == "!particularLine!" (
echo copy /Y %%ConnectorExecutionPath%%\%%outqbsyncpath%%
echo mkdir /Y %%ConnectorExecutionPath%%\%%outqbsyncpath%%
)
endlocal
) >> output.bat
Previous Batch file has several drawbacks: it remove empty lines and may fail if the line contain quotes.
EDIT: New version added
The Batch file below run faster if the input file is large; it also have several details fixed, like not removing empty lines.
#echo off
setlocal EnableDelayedExpansion
set "inputFile=%userprofile%\desktop\testSO.bat"
set "outputFile=%userprofile%\desktop\testSOout.bat"
set "particularLine=set MTBBankpath=C:\InstallerOutput\QuickBooks-Sync\MTB"
for /F "usebackq delims=:" %%a in (`findstr /N /C:"!particularLine!" "%inputFile%"`) do set theLine=%%a
if exist "%outputFile%" del "%outputFile%"
if not defined theLine echo The particular line doesn't exist in Input file & exit /B
setlocal DisableDelayedExpansion
set i=0
for /F "usebackq delims=" %%a in (`findstr /N "^" "%inputFile%"`) do (
set "line=%%a"
set /A i+=1
setlocal EnableDelayedExpansion
echo(!line:*:=!
if !i! eql %theLine% goto exitLoop
endlocal
) >> "%outputFile%"
:exitLoop
rem Insert here all the lines to insert, each one preceeded by ECHO
(
echo copy /Y "%%ConnectorExecutionPath%%\%%outqbsyncpath%%"
echo mkdir /Y "%%ConnectorExecutionPath%%\%%outqbsyncpath%%"
) >> "%outputFile%"
setlocal DisableDelayedExpansion
for /F "skip=%theLine% usebackq delims=" %%a in (`findstr /N "^" "%inputFile%"`) do (
set "line=%%a"
setlocal EnableDelayedExpansion
echo(!line:*:=!
endlocal
) >> "%outputFile%"
Please note that you must double the percent signs in the commands to insert; otherwise what is inserted is the current value of the variables instead of the %name% of the variables.
I believe the only problem you're running into is the fact that you're not encapsulating your paths for the COPY and MKDIR commands:
set _strInsert=mkdir %ConnectorExecutionPath%\%outqbsyncpath%
Try:
set _strInsert=mkdir "%ConnectorExecutionPath%\%outqbsyncpath%"
I would also do a check for the folder before creating it as well.
EDIT:
Now if you're adding in a bunch of different lines, just add them to the code. In your previous post you asked to add a single line to the code. If you're doing multiple lines, just echo them directly into the output file.
SETLOCAL ENABLEDELAYEDEXPANSION
set inputFile=%userprofile%\desktop\testSO.bat
set outputFile=%userprofile%\desktop\testSOout.bat
set _strFind=set MTBBankpath=C:\InstallerOutput\QuickBooks-Sync\MTB
set i=0
FOR /F "usebackq tokens=1 delims=[]" %%A IN (FIND /N "%_strFind%" "%inputFile%") DO (set _strNum=%%A)
FOR /F "usebackq delims=" %%A IN ("%inputFile%") DO (
set /a i = !i! + 1
ECHO %%A>>"%outputFile%"
IF [!i!] == [%_strNum%] (
ECHO set IndbBankpath=C:\InstallerOutput\QuickBooks-Sync\indb
ECHO copy /Y "%ConnectorExecutionPath%\%outqbsyncpath%"
ECHO mkdir /Y "%ConnectorExecutionPath%\%outqbsyncpath%"
ECHO copy /Y "%QBprovisionpath%\x86\Debug %ConnectorExecutionPath%\x86\Debug"
)>>"%outputFile%"
)