I need to find and insert a value - batch-file

I'm writing a script that needs to find a numerical values or digits in a text file and replace it with input from my keyboard.
I have searched on the internet and just can't find the correct way to do it.
The text file contains the following:
C:\Progra~1\Java\userapp\fundays\jv10_80cl1\test
i need to change the "80cl1" part to new values eg: 80cl1 changes to 84cl3
:begin1
setlocal ENABLEEXTENSIONS
setlocal ENABLEDELAYEDEXPANSION
SET /P E= new value 1:
FOR /F "tokens=1 delims=:" %%a in (install.txt) do findstr /r "^[1-9][0-9]*$"
echo "%%a"
SET /P R= New value 2:
FOR /F "tokens=1 delims=:" %%a in (install.txt) do findstr /r "^[1-9][0-9]*$"
echo "%%a"
So, the script needs to find those values and change it via keyboard input.

Something like this should help. You can change the set /p to not promp and just give it a value, either way will work:
#echo off
setlocal enabledelayedexpansion
set inputfile=install.txt
set /p "_strfind=Enter value to search?"
set /p "_strinsert=Replacement value?"
for /f "tokens=*" %%a in ('type "%inputfile%" ^| find /v /n "" ^& break ^> "%inputfile%"') do (
set "str=%%a"
set "str=!str:%_strfind%=%_strinsert%!"
set "str=!str:*]=!"
>>%inputfile% echo(!str!
)
If you do not want to be pompted, just set the values before hand:
#echo off
setlocal enabledelayedexpansion
set inputfile=install.txt
set "_strfind=80cl1"
set "_strinsert=84cl3"
for /f "tokens=*" %%a in ('type "%inputfile%" ^| find /v /n "" ^& break ^> "%inputfile%"') do (
set "str=%%a"
set "str=!str:%_strfind%=%_strinsert%!"
set "str=!str:*]=!"
>>%inputfile% echo(!str!
)
If by any chance your file might contain ! it will not replicate them to file, then simply use this:
#echo off
set "inputfile=ip.txt"
set /p "_strfind=string to replace?"
set /p "_strinsert=replacement string?"
for /f "tokens=*" %%a in ('type "%inputfile%" ^| find /v /n "" ^& break ^> "%inputfile%"') do (
set "str=%%a"
setlocal enabledelayedexpansion
set "str=!str:%_strfind%=%_strinsert%!"
call set "str=%%str:*]=%%"
>>%inputfile% echo(!str!
endlocal
)
Edit, as per your comment:
#echo off
set "inputfile=install.txt"
set /p "_strfind=string to replace? "
set /p "_strinsert=replacement string? "
set /p "_strfind2=enter Executable numeric value to replace? "
set /p "_strinsert2=enter the replacement value for executable? "
set "_strfind2=%_strfind2%.exe"
set "_strinsert2=%_strinsert2%.exe"
for /f "tokens=*" %%a in ('type "%inputfile%" ^| find /v /n "" ^& break ^> "%inputfile%"') do (
set "str=%%a"
setlocal enabledelayedexpansion
set "str=!str:%_strfind%=%_strinsert%!"
set "str=!str:%_strfind2%=%_strinsert2%!"
call set "str=%%str:*]=%%"
>>%inputfile% echo(!str!
endlocal
)

Related

How to read empty lines in .bat file and the variables are placed inside %xyz%

#echo off
cd /d D:\
setlocal enabledelayedexpansion
set /p "var=v3 "
set "file=Rev.bat"
for /F "tokens=1,* delims==" %%i in ('findstr "%var%" Rev.bat') do (
set "versionVar=%%~i"
set "versionVal=%%~j"
set /a sequence=%%~j+1
)
for /f "tokens=1,*delims=]" %%i in ('type "%file%" ^| find /v /n "" ^& break^>%file%') do (
set "line=%%j"
if "!line!" == "!versionVar!=!versionVal!" set line=!versionVar!=!sequence!
echo(!line!>>!file!
)
I tried this code it doesn't find the string
ok, so if I understand you correctly, this is what you're looking for:
#echo off
cd /d D:\
setlocal enabledelayedexpansion
set "file=rev.bat"
for /F "tokens=1,* delims==" %%i in ('findstr "%~1" rev.bat') do (
set "versionVar=%%~i"
set "versionVal=%%~j"
set /a sequence=%%~j+1
)
for /f "tokens=1,*delims=]" %%i in ('type "%file%" ^| find /v /n "" ^& break^>%file%') do (
set "line=%%j"
if "!line!" == "!versionVar!=!versionVal!" set line=!versionVar!=!sequence!
echo(!line!>>!file!
)
Explanation. We get the file content, using find to assign row id's Then we do search and replace and simply remove the row id's. Then write back everything to the file including the updated version.
note, you need to run the script with a parameter, i.e. script.cmd v3
Edit. to do more than one variable at a time by request, do:
#echo off
cd /d D:\
setlocal enabledelayedexpansion
:Begin
set /p "var=enter variable to replace [.ie v1, v2, v3]: "
set "file=rev.bat"
for /F "tokens=1,* delims==" %%i in ('findstr "%var%" rev.bat') do (
set "versionVar=%%~i"
set "versionVal=%%~j"
set /a sequence=%%~j+1
)
for /f "tokens=1,*delims=]" %%i in ('type "%file%" ^| find /v /n "" ^& break^>%file%') do (
set "line=%%j"
if "!line!" == "!versionVar!=!versionVal!" set line=!versionVar!=!sequence!
echo(!line!>>!file!
)

Windows Batch Scripting: Checking file for multiple strings

I have a batch file that processes scanned PDFs using ghostscript. One of the user prompts is for the resolution of the desired output. I wrote a crude autodetect routine like this:
for /f "delims=" %%a in ('findstr /C:"/Height 1650" %1') do set resdect=150
for /f "delims=" %%a in ('findstr /C:"/Height 3300" %1') do set resdect=300
for /f "delims=" %%a in ('findstr /C:"/Height 6600" %1') do set resdect=600
echo %resdect% DPI detected.
%1 is the filename passed to the batch script.
This should return the the highest resolution detected of some common sizes we see. My question to the community is: Is there a faster or more efficient way to do this other than search the file multiple times?
Assuming that the value of RESDECT is the /Height value divided by 11, and that no line contains more than one /Height token, the following code might work for you:
#echo off
for /F delims^=^ eol^= %%A in ('findstr /R /I /C:"/Height *[0-9][0-9]*" "%~1"') do (
set "LINE=%%A"
setlocal EnableDelayedExpansion
set "RESDECT=!LINE:*/Height =!"
set /A "RESDECT/=11"
echo/!RESDECT!
endlocal
)
If you only want to match the dedicated /Height values 1650, 3300, 6600, you could use this:
#echo off
for /F delims^=^ eol^= %%A in ('findstr /I /C:"/Height 1650" /C:"/Height 3300" /C:"/Height 6600" "%~1"') do (
set "LINE=%%A"
setlocal EnableDelayedExpansion
set "RESDECT=!LINE:*/Height =!"
set /A "RESDECT/=11"
echo/!RESDECT!
endlocal
)
To gather the greatest /Height value appearing in the file, you can use this script, respecting the aforementioned assumptions:
#echo off
set "RESDECT=0"
for /F delims^=^ eol^= %%A in ('findstr /R /I /C:"/Height *[0-9][0-9]*" "%~1"') do (
set "LINE=%%A"
setlocal EnableDelayedExpansion
set "HEIGHT=!LINE:*/Height =!"
for /F %%B in ('set /A HEIGHT/11') do (
if %%B gtr !RESDECT! (endlocal & set "RESDECT=%%B") else endlocal
)
)
echo %RESDECT%
Of course you can again exchange the findstr command line like above.
Here is another approach to get the greatest /Height value, using (pseudo-)arrays, which might be faster than the above method, because there are no extra cmd instances created in the loop:
#echo off
setlocal
set "RESDECT=0"
for /F delims^=^ eol^= %%A in ('findstr /R /I /C:"/Height *[0-9][0-9]*" "%~1"') do (
set "LINE=%%A"
setlocal EnableDelayedExpansion
set "HEIGHT=!LINE:*/Height =!"
set /A "HEIGHT+=0, RES=HEIGHT/11" & set "HEIGHT=0000000000!HEIGHT!"
for /F %%B in ("$RESOLUTIONS[!HEIGHT:~-10!]=!RES!") do endlocal & set "%%B"
)
for /F "tokens=2 delims==" %%B in ('set $RESOLUTIONS[') do set "RESDECT=%%B"
echo %RESDECT%
endlocal
At first all heights and related resolutions are collected in an array called $RESOLUTIONS[], where the /Height values are used as indexes and the resolutions are the values. The heights become left-zero-padded to a fixed number of digits, so set $RESOLUTIONS[ return them in ascending order. The second for /F loop returns the last arrays element whose value is the greatest resolution.
I do have to admit that this was inspired by Aacini's nice answer.
get the corresponding line to a variable and work with that instead of the whole file. Instead of your three for loops, you can use just one, when you change the logic a bit:
#echo off
setlocal enabledelayedexpansion
for /f "delims=" %%a in ('findstr /C:"/Height " %1') do (
set "line=%%a"
set "line=!line:*/Height =!"
for /f "delims=/ " %%b in ("!line!") do set "hval=!hval! %%b"
)
for %%a in (1650,3300,6600) do #(
echo " %hval% " | find " %%a " >nul && set /a resdect=%%a/11
)
echo %resdect% DPI detected.
A solution with jrepl.bat could look something like:
for /f %a in ('type t.txt^|find "/Height "^|jrepl ".*/Height ([0-9]{4}).*" "$1"^|sort') do set /a dpi==%a / 11
(given, all valid Heights have 4 digits)
Note: for use in batchfiles, use %%a instead of %a
I barely scratched the surface of jrepl - I'm quite sure, there is a much more elegant (and probably faster) solution.
You may directly convert the Height value into the highest resolution in a single operation using an array. However, to do that we need to know the format of the line that contain the Height value. In the code below I assumed that the format of such a line is /Height xxxx, that is, that the height is the second token in the line. If this is not true, just adjust the "tokens=2" value in the for /F command.
EDIT: Code modified as requested in comments
In this modified code the Height value may appear anywhere in the line.
#echo off
setlocal EnableDelayedExpansion
rem Initialize "resDect" array
for %%a in ("1650=150" "3300=300" "6600=600") do (
for /F "tokens=1,2 delims==" %%b in (%%a) do (
set "resDect[%%b]=%%c"
)
)
set "highResDect=0"
for /F "delims=" %%a in ('findstr "/Height" %1') do (
set "line=%%a"
set "line=!line:*/Height =!"
for /F %%b in ("!line!") do set /A "thisRectDect=resDect[%%b]"
if !thisRectDect! gtr !highResDect! set "highResDect=!thisRectDect!"
)
echo %highResDect% DPI detected.
For the record, the final code was:
setlocal enabledelayedexpansion
set resdetc=0
for /f "delims=" %%a in ('findstr /C:"/Height " %1') do (
set "line=%%a"
set "line=!line:*/Height =!"
for /f "delims=/ " %%b in ("!line!") do set "hval=!hval! %%b"
)
for %%a in (1650,3300,6600) do #(
echo " %hval% " | find " %%a " >nul && set /a resdetc=%%a/11
)
if %resdetc%==0 SET resDefault=3
if %resdetc%==150 SET resDefault=1
if %resdetc%==300 SET resDefault=3
if %resdetc%==600 SET resDefault=6
ECHO.
ECHO Choose your resolution
ECHO ----------------------
ECHO 1. 150 4. 400
ECHO 2. 200 5. 500
ECHO 3. 300 6. 600
ECHO.
IF NOT %RESDETC%==0 ECHO 7. Custom (%resdetc% DPI input detected)
IF %RESDETC%==0 ECHO 7. Custom
ECHO ----------------------
choice /c 1234567 /T 3 /D %resDefault% /N /M "Enter 1-7 (defaults to %resDefault% after 3 sec.): "
IF errorlevel==7 goto choice7
IF errorlevel==6 set reschoice=600 & goto convert
IF errorlevel==5 set reschoice=500 & goto convert
[...]
Thanks everyone for the help!

search and replace string using batch commands

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

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

reg query a key value based on another key value

What I'm trying to do is have a batch script return the uninstall link for a program. So basically I want something like this:
Select UninstallString from HKLM\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall where DisplayName='Sublime Text 1.0"
I'm using
reg query HKLM\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall /S^|find " DisplayName"
to initially get a list of programs, which then get put in a menu, then I select the program to uninstall and it's supposed to go to that program's registry in HKLM\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall and get it's UninstallString value
Try this:
#echo off&setlocal enabledelayedexpansion
set "regroot=HKLM\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall"
set "file=%~dpn0.txt"
set /a fcount=0
for /f "delims==" %%i in ('set $ 2^>nul') do set "%%i="
if exist "%file%" (
for /f "usebackqtokens=1*delims=|" %%i in ("%file%") do (
set /a fcount+=1
set "$d%%j=%%j"
set "$u%%j=%%i"
)
goto:menu
)
echo(building "%file%", please wait
for /f "delims=" %%i in ('reg query "%regroot%"') do (
set "DN="& set "US="
for /f "tokens=2*" %%j in ('reg query "%regroot%\%%~ni" /v DisplayName 2^>nul^|find /i "DisplayName"') do set "DN=%%~k"
for /f "tokens=2*" %%j in ('reg query "%regroot%\%%~ni" /v UninstallString 2^>nul^|find /i "UninstallString"') do set "US=%%~k"
if not "!DN!"=="" if not "!US!"=="" if not defined $d!DN! (
>>"%file%" echo(!US!^|!DN!
set /a fcount+=1
set "$d!DN!=!DN!"
set "$u!DN!=!US!"
<nul set/p"=."
)
)
echo(
:menu
echo(%fcount% programs with uninstall strings found.
:loop
set /a pcount=0
set "program="
set /p "program=type a program name (q=quit): "
if not defined program goto:loop
if "%program%"=="q" goto:eof
echo(
for /f "tokens=2delims==" %%i in ('set $d ^|findstr !program! 2^>nul') do (
echo(%%i
echo(!$u%%i!
echo(
set /a pcount+=1
)
if %pcount% equ 0 (echo(!program! not found.) else echo(%pcount% program(s^) found.
goto:loop
You can use some of findstr's REGEX capabilities (eg. /i for case insensitive search). Please note: to search for all programs starting with "M" you can use "^$dM" or /b $dM. Searchable strings have always a leading $d.
Try this "two-liner":
for /f "tokens=7 delims=\" %%a in ('reg query HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall /S /F "MySoftware" ^| find "{"') do set ProgramUninstallRegKey=%%a
for /f "skip=1 tokens=3*" %%a in ('reg query HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\%ProgramUninstallRegKey% /V "UninstallString"') do set ProgramUninstallString=%%a %%b

Resources