How to replace substrings in windows batch file - batch-file

Can anyone tell me using batch file in windows ...how to read from a file and replace string=bath from file containing=bath Abath Bbath XYZbathABC with string hello so that the output is like hello Ahello Bhello XYZhelloABC

Expanding from Andriy M, and yes you can do this from a file, even one with multiple lines
#echo off
setlocal EnableExtensions EnableDelayedExpansion
set "INTEXTFILE=test.txt"
set "OUTTEXTFILE=test_out.txt"
set "SEARCHTEXT=bath"
set "REPLACETEXT=hello"
for /f "delims=" %%A in ('type "%INTEXTFILE%"') do (
set "string=%%A"
set "modified=!string:%SEARCHTEXT%=%REPLACETEXT%!"
echo !modified!>>"%OUTTEXTFILE%"
)
del "%INTEXTFILE%"
rename "%OUTTEXTFILE%" "%INTEXTFILE%"
endlocal
EDIT
Thanks David Nelson, I have updated the script so it doesn't have the hard coded values anymore.

SET string=bath Abath Bbath XYZbathABC
SET modified=%string:bath=hello%
ECHO %string%
ECHO %modified%
EDIT
Didn't see at first that you wanted the replacement to be preceded by reading the string from a file.
Well, with a batch file you don't have much facility of working on files. In this particular case, you'd have to read a line, perform the replacement, then output the modified line, and then... What then? If you need to replace all the ocurrences of 'bath' in all the file, then you'll have to use a loop:
#ECHO OFF
SETLOCAL DISABLEDELAYEDEXPANSION
FOR /F %%L IN (file.txt) DO (
SET "line=%%L"
SETLOCAL ENABLEDELAYEDEXPANSION
ECHO !line:bath=hello!
ENDLOCAL
)
ENDLOCAL
You can add a redirection to a file:
ECHO !line:bath=hello!>>file2.txt
Or you can apply the redirection to the batch file. It must be a different file.
EDIT 2
Added proper toggling of delayed expansion for correct processing of some characters that have special meaning with batch script syntax, like !, ^ et al. (Thanks, jeb!)

To avoid blank line skipping (give readability in conf file) I combine aflat and jeb answer (here) to something like this:
#echo off
setlocal enabledelayedexpansion
set INTEXTFILE=test.txt
set OUTTEXTFILE=test_out.txt
set SEARCHTEXT=bath
set REPLACETEXT=hello
set OUTPUTLINE=
for /f "tokens=1,* delims=¶" %%A in ( '"findstr /n ^^ %INTEXTFILE%"') do (
SET string=%%A
for /f "delims=: tokens=1,*" %%a in ("!string!") do set "string=%%b"
if "!string!" == "" (
echo.>>%OUTTEXTFILE%
) else (
SET modified=!string:%SEARCHTEXT%=%REPLACETEXT%!
echo !modified! >> %OUTTEXTFILE%
)
)
del %INTEXTFILE%
rename %OUTTEXTFILE% %INTEXTFILE%

To avoid problems with the batch parser (e.g. exclamation point), look at Problem with search and replace batch file.
Following modification of aflat's script will include special characters like exclamation points.
#echo off
setlocal DisableDelayedExpansion
set INTEXTFILE=test.txt
set OUTTEXTFILE=test_out.txt
set SEARCHTEXT=bath
set REPLACETEXT=hello
set OUTPUTLINE=
for /f "tokens=1,* delims=¶" %%A in ( '"type %INTEXTFILE%"') do (
SET string=%%A
setlocal EnableDelayedExpansion
SET modified=!string:%SEARCHTEXT%=%REPLACETEXT%!
>> %OUTTEXTFILE% echo(!modified!
endlocal
)
del %INTEXTFILE%
rename %OUTTEXTFILE% %INTEXTFILE%

I have made a function for that, you only call it in a batch program within needing to code more.
The working is basically the same as the others, as it's the best way to do it.
Here's the link where I have that function

To avoid blank line skipping just replace this:
echo !modified! >> %OUTTEXTFILE%
with this:
echo.!modified! >> %OUTTEXTFILE%

If you have Ruby for Windows,
C:\>more file
bath Abath Bbath XYZbathABC
C:\>ruby -pne "$_.gsub!(/bath/,\"hello\")" file
hello Ahello Bhello XYZhelloABC

Related

How to exit from .loop in .batch file when it find at first time after replace it from .c file

The code is used to search a string from .c file and replace it.The size of file is too long so I just want to exit the loop when it find the string and replace it.
#echo on
setlocal enabledelayedexpansion
cd D:\abc
set INTEXTFILE=rev.c
set OUTTEXTFILE=test_out.txt
set SEARCHTEXT=BNE1.9
set REPLACETEXT=BNE1.8
set OUTPUTLINE=
for /f "tokens=1,* delims=¶" %%A in ( '"findstr /n ^^ %INTEXTFILE%"') do (
SET string=%%A
for /f "delims=: tokens=1,*" %%a in ("!string!") do set "string=%%b"
if "!string!" == "" (
echo.>>%OUTTEXTFILE%
) else (
SET modified=!string:%SEARCHTEXT%=%REPLACETEXT%!
echo.!modified! >> %OUTTEXTFILE%
exit /b
)
)
del %INTEXTFILE%
rename %OUTTEXTFILE% %INTEXTFILE%
As your code is reading each line one by one and writing it to a resulting file, then using your batch file methodology there is unfortunately no way to stop at the first replacement, without losing each line below that replaced string line.
To do that you would need to use a scripting language or utility which can edit files as opposed to read them bit by bit and rewrite them entirely. I strongly advise that you consider a find and replace utility, or perform this task using the built-in WSH or PowerShell scripting languages instead.
As a side note, this is how I might have tackled the script you posted, which may perform the task a little more speedily:
#Echo Off
SetLocal EnableExtensions DisableDelayedExpansion
CD /D "D:\abc" 2>NUL || Exit /B
Set "INTEXTFILE=rev.c"
Set "OUTTEXTFILE=test_out.txt"
Set "SEARCHTEXT=BNE1.9"
Set "REPLACETEXT=BNE1.8"
If Not Exist "%INTEXTFILE%" Exit /B
Copy /Y "%INTEXTFILE%" "%OUTTEXTFILE%" 1>NUL
(
For /F "Delims=" %%G In (
'%SystemRoot%\System32\find.exe /I /N /V "" 0^<"%OUTTEXTFILE%"'
) Do (
Set "NumberedLine=%%G"
SetLocal EnableDelayedExpansion
Set NumberedLine | %SystemRoot%\System32\find.exe "%SEARCHTEXT%" 1>NUL
If Not ErrorLevel 1 (
Set "NumberedLine=!NumberedLine:%SEARCHTEXT%=%REPLACETEXT%!"
)
Echo(!NumberedLine:*]=!
EndLocal
)
) 1>"%INTEXTFILE%"
Rem Del "%OUTTEXTFILE%"
Feel free to remove the Remark on the last line, if you are sure you do not want a copy of the original file content.
The main issue with your chosen method is that multiple joined delimiters are considered as only one. That means any line which began with a colon, :, that would be lost here "delims=: tokens=1,*".
Additionally, this version opens the file for writing only once, whereas yours opened the file for writing, for each line, then closed it again before repeating for the next.

Batch get filename from path

Hi I don't have much experience in batch-programming and have a problem. I have a .bat script that reads a file with a list of paths and i want to get the filename of these paths. I use the script in cygwin.
My code in the Script:
for /F %%a in (error1.txt) do (
set value=%%a
FOR /F %%I IN ("%value%") DO SET MYPATHFILE=%%~nxI
)
When i run the Script %value% is empty.
Value of error1.txt:
a/b/c/d/TextIWant
you need delayed expansion or you can directly use %%a:
for /F %%a in (error1.txt) do (
FOR /F %%I IN ("%%a") DO SET MYPATHFILE=%%~nxI
)
or
setlocal enableDelayedExpansion
for /F %%a in (error1.txt) do (
set value=%%a
FOR /F %%I IN ("!value!") DO SET MYPATHFILE=%%~nxI
)
It looks like you will need Delayed Expansion.
The current problem is, that you want to use a variable in the same set of brackets where you changed the value in (the surrounding For-Loop).
Add setlocal EnableDelayedExpansion to your code at the top and change the %value% to !value!
You can test the problem yourself with this code:
#echo off
setlocal EnableDelayedExpansion
set foo=bar
For /L %%a (1,2,1) do (
set foo=foobar
echo.old value %foo%
echo.new value !foo!
)
I hope it helped :)
Greetings
geisterfurz007

Batch file replace line in text file with new line

I want to be able to replace a line in a properties file but i only know part of the line string at any one time
Heres the line i want to replace: mb.datasource.password=ENC(8dF45fdD)
with this: mb.datasource.password=apassword
What i have just now is this
#echo off &setlocal
set "search=mb.datasource.password="
set "replace=mb.datasource.password=apassword"
set "textfile=mb.properties"
set "newfile=mb-new.properties"
(for /f "delims=" %%i in (%textfile%) do (
set "line=%%i"
setlocal enabledelayedexpansion
set "line=!line:%search%=%replace%!"
echo(!line!
endlocal
))>"%newfile%"
This ends up giving me mb.datasource.password=apassword=ENC(8fFdeUdK)
I can't just find the full string it needs to only be mb.datasource.password= because the part after the equals changes
Any help would be greatly appreciated?
You can do it with batch. I put together a quick script and it worked for me:
#ECHO OFF
SETLOCAL EnableExtensions
SET SourceFile="mb.properties"
SET OutputFile="mb-new.properties"
SET "FindKey=mb.datasource.password"
SET "NewValue=apassword"
REM Basic parse for INI file format.
(FOR /F "usebackq eol= tokens=1,* delims==" %%A IN (`TYPE %SourceFile%`) DO (
REM If the key value matches, build the line with the new value.
REM Otherwise write out the existing value.
IF /I "%%A"=="%FindKey%" (
ECHO %%A=%NewValue%
) ELSE (
ECHO %%A=%%B
)
)) > %OutputFile%
REM Replace old with new.
DEL %SourceFile%
MOVE %OutputFile% %SourceFile%
ENDLOCAL
A few notes about the above:
I assumed basic INI file format.
The FOR loop will skip blank lines so they would be removed from the new output file. There are ways around this using tricks with the FIND command if the blanks are needed.
If you have special chars (% or ! especially) - this may cause some problems, but if you have just "normal" text then it should be fine.

Issue With Delayed Expansion In Batch Code

I am running into an issue where I have a complete directory listing of a computer (located in the text file shown below).
The issue appears in cases where the directory listing contains special characters such as "! or &". When that issue occurrs, the filename is parsed such that those special characters are omitted (thus causing issues with leveraging those variables to compute other sub-tasks). Below is a snapshot of the code. Please advise as to how I might proceed.
Note that within the text file might be paths such as:
C:\Windows!temp!\file.txt
C:\Windows\file.txt
This will parse as:
C:\Windows\temp\file.txt (without quotes)
C:\Windows\file.txt
code snip
for /f "delims=?" %%a in (dir.txt) do (
setlocal enabledelayedexpansion
set filepath=%%a
)
call :subproc1
)
goto :proc2
:subproc1
echo !filepath!
endlocal
goto :eof
:proc2
continue with script here
You are toggling delayed expansion on too early, and there is no need for the subroutine.
for /f "delims=?" %%a in (dir.txt) do (
set filepath=%%a
setlocal enabledelayedexpansion
echo !filepath!
endlocal
)
#echo off
setlocal enableDelayedExpansion
for /f "delims=?" %%a in (dir.txt) do (
setlocal disableDelayedExpansion
(echo(%%a)
endlocal
)
endlocal
goto :proc2
:proc2
echo -------end
the Jeb's trick...

Issue with environment variable

I just want to echo a variable which is defined with ENABLEDELAYEDEXPANSION. It doesn't work.
Here's a small part of my long script on the issue
#echo off&setlocal enabledelayedexpansion
for /f "tokens=*" %%x in (%1) do (
set "D=%%x"
echo %%~nD
)
I have also written echo !~nD! but it doesn't work either.
my file (%1) only contains relative paths as so:
VENDOR\ford1.car
VENDOR\bmw.car
and my goal is to echoing 'ford1.car' or 'bmw.car' because I have to use them in the next steps of my script, that is only the file complete name.
Please some help and explanations. Thanks
Try:
#echo off&setlocal enabledelayedexpansion
for /f "tokens=*" %%a in (%1) do (
echo %%~nxa
)
For only does substitution on the variable used in the for. You can't set a variable within and use substitution on it.
%%~na would only give you the file name without the extension. You have to use %%~nxa to get the file name and the extension.
If you want to set the file name to a variable and do something with each file, you have to use DelayedExpansion like this:
#echo off&setlocal enabledelayedexpansion
for /f "tokens=*" %%a in (%1) do (
set d=%%~nxa
echo !d!
Do something with !d!
)
Or you could create a subroutine and not have to use a variable at all
#echo off&setlocal enabledelayedexpansion
for /f "tokens=*" %%a in (%1) do (
call :sub %%~nxa
)
goto :eof
:sub
%1 = your file name so do some processing on it.

Resources