search and replace string using batch commands - batch-file

How can i search a string and replace it with a variable.
i would like to search version="1.37.0" but the version number could be anything. And there are two "version=" string in package.xml but i would like to replace second one.
how can i search version="x.x.x" and replace it with version="$variable"?
is there any one liner?
i did try to use something like this to search:
findstr "version="[0-9].[0-9].[0-9]" package.xml
and also same thing for desrciption="$variable1"
package.xml
<?xml version="1.0" encoding="utf-8"?>
<PackageManifest>
<Package name="audio"
description="something. . .."
version="1.37.0"
comment="">
</Package>
</PackageManifest>

ad hoc solution, but ...
Edited to adapt to comments
#echo off
setlocal enableextensions disabledelayedexpansion
rem Check input parameters. Needed the input file, the version and the description
if "%~3"=="" goto :eof
set "file=%~1"
set "newVersion=%~2"
set "newDescription=%~3"
rem Read the file into memory
for /f "tokens=1,* delims=:" %%a in ('findstr /n "^" "%file%"') do (
set /a "line=1000+%%a*10"
setlocal enabledelayedexpansion
for %%c in (!line!) do endlocal & set "l_%%c=|%%b"
)
rem %%a will search the required lines
rem %%c remove blanks at the start of the line
rem %%d get the key name
for /f "tokens=2,* delims=_=|" %%a in (
'set l_1 ^| findstr /i /r /c:"^[^<]*version=" /c:"description=" /c:"^[^<]*<Package"'
) do for /f %%c in ("%%b") do for /f "delims==" %%d in ("%%c") do (
if /i "%%d"=="description" ( set "value=%newDescription%" & set "newDescription="
) else if /i "%%d"=="version" ( set "value=%newVersion%" & set "newVersion="
) else if /i "%%d"=="<Package" ( set "packageLine=%%a" & set "value="
) else set "value="
if defined value ( setlocal enabledelayedexpansion
for /f "delims=" %%z in ("!value!") do ( endlocal
for /f tokens^=1^,2^,^*^ delims^=^" %%e in ("%%b") do set "l_%%a=|%%e"%%z"%%g"
)
)
)
rem Include the missing values
set /a "packageLine+=1"
if defined newDescription set "l_%packageLine%=| description="%newDescription%""
set /a "packageLine+=1"
if defined newVersion set "l_%packageLine%=| version="%newVersion%""
rem Output the changed information to console
for /f "tokens=1,* delims=|" %%a in ('set l_1') do echo(%%b
rem Save to file
>"%file%" (for /f "tokens=1,* delims=|" %%a in ('set l_1') do echo(%%b)

Try this :
#echo off
set $FindStr=Version="x.x.x"
set $ReplString=Version="y.y.y"
setlocal enabledelayedexpansion
for /f "delims=" %%a in ('type test.xml') do (
set $Ver=%%a
set $Ver=!$Ver: =!
If /i !$Ver!==%$FindStr% set $Ver=%$ReplString%
echo !$Ver! ) >> Output.xml
Very simplist but a good base
Edit :
This will ask for the version value of the second matched version=
#echo off
set "$FindStr=Version="
set $c=1
setlocal enabledelayedexpansion
for /f "delims=" %%a in ('type test.xml') do (
set $Ver=%%a
set $Ver=!$Ver: =!
If /i "!$Ver:~0,8!"=="%$FindStr%" (
if !$c! GTR 1 (
set /p "$NewVer=Enter New version : "
set $Ver=%$FindStr%!$NewVer!)
set /a $c+=1)
echo !$Ver! >> Output.xml)
The input file is text.xml and the ouputFile Output.xml

Related

Add numbers with same text together

I would like to create a batch file in which I can see what I have collected in a game.
The game saves this information in a .txt file.
The output would look like this.
70x Silver.
Back Pearl.
41x Copper.
Amethyst.
Amethyst.
12x Silver.
Back Pearl.
21x Copper.
5x Silver.
Back Pearl.
Back Pearl.
Amethyst.
What I want to do now, is to add the items with the same name together, like this:
128x Silver.
4x Back Pearl.
62x Copper.
3x Amethyst.
There are hundreds of items with different names, not just these 4.
Would that be possible?
Any help would be appreciated. Thanks!
Another one!
#echo off
setlocal EnableDelayedExpansion
for /F "delims=" %%l in (test.txt) do for /F "tokens=1*" %%a in ("%%l") do (
set "first=%%a"
if "!first:~-1!" equ "x" (set /A "num=!first:~0,-1!") else set "num=0"
if !num! equ 0 (
set "rest=%%l"
set /A "count[!rest: =_!]+=1"
) else (
set "rest=%%b"
set /A "count[!rest: =_!]+=num"
)
)
(for /F "tokens=2* delims=[]=" %%a in ('set count[') do (
set "item=%%a"
if %%b equ 1 (
echo !item:_= !
) else (
echo %%bx !item:_= !
)
)) > summary.txt
#ECHO OFF
SETLOCAL
rem The following settings for the source directory and filename 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 "filename1=%sourcedir%\q72672485.txt"
:: remove variables starting #
FOR /F "delims==" %%b In ('set # 2^>Nul') DO SET "%%b="
FOR /f "usebackqdelims=" %%b IN ("%filename1%") DO (
CALL :sub %%b
)
SETLOCAL ENABLEDELAYEDEXPANSION
(
FOR /F "tokens=1,2delims==" %%b In ('set # 2^>Nul') DO (
SET "line=%%cx%%b"
ECHO !line:#= !
)
)>summary.txt
endlocal
type summary.txt
GOTO :EOF
:sub
SET "quantity=%1"
SET "line=%*"
IF /i "%quantity:~-1%"=="x" (SET /a quantity=%quantity:~0,-1%&SET "line=%line:* =%") ELSE SET quantity=1
IF %quantity%==0 SET /a quantity=1&SET "line=%*"
SET /a #%line: =#%+=quantity
GOTO :eof
Different approach...
Would that be possible? - Yes.
#echo off
setlocal enabledelayedexpansion
for /f "delims=" %%a in (t.txt) do (
set " z=%%a"
set " z=!z:x =#!"
set " z=!z: =_!"
for /f "tokens=1,2 delims=#" %%b in ("!z!") do (
if "%%c" == "" (
set "x=1"
set "y=%%b
) else (
set "x=%%b"
set "y=%%c"
)
set /a #!y!+=!x!
)
)
(for /f "tokens=1,2 delims=#=" %%a in ('set #') do (
set "x=%%a"
set "y=%%bx "
echo !y:~0,4! !x:_= !
))>summary.txt
Output with your example data (I hope, alphabetic sorting is ok for you):
3x Amethyst.
4x Back Pearl.
62x Copper.
87x Silver.
(your calculation of 120 silver might be a bit optimistic with the given input data)
This is a different approach that use a "file merge" method. The overall code is somewhat simpler than other methods...
#echo off
setlocal EnableDelayedExpansion
set "lineNum=0"
(for /F "tokens=1,2* delims=:x " %%a in ('(type test.txt ^& echo 0x^) ^| findstr /N "[0-9][0-9]*x"') do (
if !lineNum! lss %%a call :locateLine %%a
set "line=%%c"
set /A "count[!line: =_!]+=%%b"
)) < test.txt
set "count[="
(for /F "tokens=2* delims=[]=" %%a in ('set count[') do (
set "item=%%a"
if %%b equ 1 (echo !item:_= !) else echo %%bx !item:_= !
)) > summary.txt
goto :EOF
:locateLine num
set /A "lineNum+=1" & set /P "line=" & if errorlevel 1 exit /B
if %lineNum% lss %1 set /A "count[%line: =_%]+=1" & goto locateLine
exit /B
Another approach (splitting the file into items with and without quantity) (also fixing the Pollux Infusion issue in my first answer):
#echo off
setlocal enabledelayedexpansion
REM process lines without quantity:
for /f "delims=" %%a in ('type test.txt^|findstr /vrc:"[0123456789][0123456789]*x "') do call :count 1 "%%a"
REM process lines with quantity:
for /f "tokens=1*delims=x " %%a in ('type test.txt^|findstr /rc:"[0123456789][0123456789]*x "') do call :count %%a "%%b"
REM reformat:
(for /f "tokens=1,2 delims=#=" %%a in ('set #') do (
set "count=%%bx "
set "line=!count:~0,5!%%a" &REM including '1x'
if %%b==1 set "line= %%a" &REM supressing '1x'
echo !line:_= !
))>summary.txt
type summary.txt
goto :eof
:count
set item=%~2
set "item=%item: =_%"
set /a #%item% +=%1
Included both with and without 1x. Remove the line, you don't want.

IN ECHO statement how can i print all the columns without defining multiple output parameters

for /f " tokens=%i%-%j% delims=," %%a in (%input%) DO (
(ECHO %%a %%b %%c %%d %%e %%f %%g %%h %%i %%j)>>%output%
)
"delims=" will force no delimiter and use full string making each line %%a instead of each word, delimited by ,.
for /f "delims=" %%a in (%input%) DO ECHO %%a >>%output%
If you would like to get rid of the , simply replace it.
#echo off
setlocal enabledelayedexpansion
for /f "delims=" %%a in (%input%) DO ( set string=%%a
set string=!string: =,!
ECHO !string! >> %output%
)
endlocal
According to your comments, the following should do exactly, what you want: multiple spaces are reduced to one delimiter, no delimiters at the end of a line.
#echo off
setlocal enabledelayedexpansion
(for /f "delims=" %%a in (input.txt) do (
set "new="
for %%b in (%%a) do (
set "new=!new!,%%b"
)
echo !new:~1!
))>output.txt
Because your ? characters may be problematic with some solutions, the following may do what you require:
#Echo Off
Set "input=input.txt"
Set "output=output.txt"
Set "_="
(For /F "UseBackQ Delims=" %%A In ("%input%"
) Do Set "_="&Call :Sub %%A&Call Echo(%%_:~1%%)>"%output%"
If Not Defined _ Del "%output%"
Exit /B
:Sub
If "%1"=="" GoTo :EOF
Set "_=%_%,%1"
Shift&GoTo :Sub

select file with the largest number of lines

It count number of line in all file but i need select the file with the largest number of lines.
for %%a in (*.*) do (
for /f %%b in (' find "" /v /c ^< "%%a" ') do (
echo %%a=%%b
)
)
Output:
test.txt=10
asdasd.txt=15
asdasd.txt=20
I need output:
asdasd.txt=20
only one file with the largest number of lines
Pleas help. Thx
First option, calling find for each file and then parsing output
#echo off
setlocal enableextensions enabledelayedexpansion
set "maxLines=0"
set "maxFile="
for %%a in (*.txt) do (
for /f %%b in ('^<"%%a" find /c /v ""') do if %%b gtr !maxLines! (
set "maxLines=%%b"
set "maxFile=%%a"
)
)
echo %maxFile%=%maxLines%
Second option, calling find only one time and parsing output
#echo off
setlocal enableextensions enabledelayedexpansion
set "maxLines=0"
set "maxFile="
for /f "tokens=* delims=- " %%a in ('find /c /v "" *.txt '
) do for /f "tokens=1,2 delims=:" %%b in ("%%a"
) do if %%c gtr !maxLines! (
for %%d in (%%c) do set "maxLines=%%d"
set "maxFile=%%b"
)
echo %maxFile%=%maxLines%
you need to set additional vars:
echo off
setlocal enableextensions enabledelayedexpansion
set /A counter=0
for /f "tokens=1,2* delims=-:" %%a in ('find /c /v "" *.*') do (
if !counter! LSS %%b (
set /A counter=%%b
set bezieher=%%~nxa)
)
)
echo %bezieher%=%counter%
pause
Rem Respect to the scriptwriter "MC ND" above!!

Loop through list, set variable

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

Order files list by batch

I have a long list of individual songs not in folders just songs, and I'd like to move them to the folder of theire artist. the songs are in the following format
artist - songname.flac
I can store them in a list, and echo it, but splitting the artist and songname in 2 vars, I can't seem to figure out.
Could someone help me with the splitting (or if you want even with the rest of the script)
this is what I have so far:
#echo off
setlocal enabledelayedexpansion
set N=0
for %%i in (*) do (
set Files[!N!]=%%~ni
set /a N+=1
)
for /l %%x in (1,1,%N%) do echo.!Files[%%x]!
pause
set SOURCE=c:\temp\test
for /f "delims=-. tokens=1,2" %%i in ('dir /b "%SOURCE%\*.flac"') do echo Artist : %%i Song : %%j
update for full script (got to check if it works with space and special chars in path) :
#echo off
setlocal enabledelayedexpansion
set SOURCE=c:\temp\test
set DESTINATION=c:\temp\test
for /f "tokens=*" %%i in ('dir /b "%SOURCE%\*.flac"') do call :OrderThatMess "%%i"
:OrderThatMess
set NAME=%1
for /f "tokens=1,2 delims=-. " %%j in (%1) do (
set ARTIST=%%j
set TITLE=%%k
if not exist "%DESTINATION%\%ARTIST%" (md "%DESTINATION%\%ARTIST%" )
copy %SOURCE%\%NAME% "%DESTINATION%\%ARTIST%\%TITLE%.flac"
)
#echo OFF &SETLOCAL ENABLEDELAYEDEXPANSION
for %%i in (*.flac) do (
set /a N+=1
FOR /f "tokens=1,2 delims=- " %%o IN ("%%~ni") DO (
set "FilesA[!N!]=%%~o"
set "FilesB[!N!]=%%~p"
)
)
for /l %%x in (1,1,%N%) do echo(!FilesA[%%x]! !filesB[%%x]!
Thanks for the answers ;) Thanks to Kayasax I fixed it
here is the full code:
#echo off
SETLOCAL ENABLEDELAYEDEXPANSION
set SOURCE=C:\music\folder\with\files\
for /f "tokens=1,2 delims=-" %%i in ('dir /b "%SOURCE%\*.flac"') do (
set "folder=%%i"
IF NOT EXIST "%SOURCE%\%%i" (
mkdir "%%i"
)
move "%SOURCE%\%%i-%%j" "%SOURCE%\!folder:~0, -1!\%%i-%%j"
)
pause

Resources