I am trying to read a file using enabledelayedexpansion .File contains special character.Because of enabledelayedexpansion ! and text after that is ignored .Please suggests some way by which this issue can be resolved .
note :- i have to use enabledelayedexpansion .
`
#echo off
set "search1='"
set "search2=""
set "search3=&"
set "search4=<"
set "search5=>"
set "search6=!"
set "replace1='"
set "replace2=""
set "replace3=&"
set "replace4=<"
set "replace5=>"
set "replace6=^!"
setlocal enabledelayedexpansion
set "textfile=!input!"
set "newfile=!input!1"
echo !textfile!
echo !newfile!
break>"!newfile!"
(for /f "delims=" %%i in (!textfile!) do (
setlocal enabledelayedexpansion
set "line=%%i"
for /f "usebackq tokens=1,2 delims=$" %%a in ('"!search3!"$"!replace3!"') do set "line=!line:%%~a=%%~b!"
for /f "usebackq tokens=1,2 delims=$" %%a in ('"!search4!"$"!replace4!"') do set "line=!line:%%~a=%%~b!"
for /f "usebackq tokens=1,2 delims=$" %%a in ('"!search5!"$"!replace5!"') do set "line=!line:%%~a=%%~b!"
for /f "usebackq tokens=1,2 delims=$" %%a in ('"!search2!"$"!replace2!"') do set "line=!line:%%~a=%%~b!"
for /f "usebackq tokens=1,2 delims=$" %%a in ('"!search1!"$"!replace1!"') do set "line=!line:%%~a=%%~b!"
setlocal enabledelayedexpansion
echo(!line!
endlocal
))>>"!newfile!"
Above is just part of script. textfile will contain file path.rest all substitution are working fine only in case of ! its causing issue
To read content from a file without destroying it you need to use the delayed toggling technic or reading it with set /p.
setlocal DisableDelayedExpansion
(
for /f "delims=" %%i in (textfile.txt) do (
set "line=%%i" -- This must be done while delayed expansion is disabled
setlocal EnableDelayedExpansion
set "line=!line:<=<!"
echo(!line!
endlocal
)
) > outfile.txt
The toggeling is necessary, because the expansion of a FOR loop variable is only safe in the disabled delayed expansion mode, else exclamation marks are removed/interpreted.
Reading a file via SET /P is another way to avoid the problems related to Delayed Expansion that may be simpler than FOR /F. I also show you a simpler way to define the set of replacements via an array
#echo off
setlocal EnableDelayedExpansion
rem Define the set of replacements
set "replacA[&]=&"
set "replace[']='"
set replace["]="
set "replace[<]=<"
set "replace[>]=>"
REM set "replace[!]=^!" // Not needed
set "textfile=!input!"
set "newfile=!input!1"
echo !textfile!
echo !newfile!
call :ProcessFile < "!textfile!" > "!newfile!"
goto :EOF
:ProcessFile
set empty=0
set "line="
:emptyLine
set /P line=
if not defined line (
set /A empty+=1
if !empty! gtr 2 exit /B
echo/
goto emptyLine
)
for /F "tokens=2,3 delims=[]=" %%a in ('set replac') do set "line=!line:%%a=%%b!"
echo !line!
goto ProcessFile
The most complex part in :ProcessFile subroutine is just used to preserve a maximum of 2 empty lines together (that may easily be increased to more lines, if needed).
Edit: completely overwritten. I could either keep an ! exclamation mark in output or replace it by ^^! (or ^^^^!, ^^^^^^! etc.) with even number of ^^ carets as follows:
#ECHO OFF >NUL
SETLOCAL enableextensions enabledelayedexpansion
set "textfile=files\31130282textfile.txt"
set "newfile=files\31130282textfileNew.txt"
set "line="
set "quote=""
setlocal DisableDelayedExpansion
set "exclamation=!"
set "exclamationNew=%~1!"
(for /f "delims=" %%i in (%textfile%) do (
set "line=%%i"
SETLOCAL enabledelayedexpansion
set "line=!line:&=&!"
set "line=!line:<=<!"
set "line=!line:>=>!"
call set "line=%%line:!quote!="%%"
set "line=!line:'='!"
call set "line=%%line:!exclamation!=!exclamationNew!%%"
echo(!line!
ENDLOCAL
))>"%newfile%"
endlocal
type "%newfile%"
Output:
==>type files\31130282textfile.txt"
<'abc'>&"cde"T
"<x!y!z!>"
==>D:\bat\SO\31130282.bat ""
<'abc'>&"cde"T
"<x!y!z!>"
==>D:\bat\SO\31130282.bat "^"
<'abc'>&"cde"T
"<x^^!y^^!z^^!>"
==>D:\bat\SO\31130282.bat "^^"
<'abc'>&"cde"T
"<x^^^^!y^^^^!z^^^^!>"
Related
I want to put a batch file to modify a line in a file in a GPO.
The problem I have is the path is different for each user.
So, I tried to use a wildcard in my path but it doesnt work.
This bat is working:
#echo off &setlocal
setlocal enabledelayedexpansion
set "search=test"
set "replace=test2"
set "textfile=%appdata%\Thunderbird\Profiles\5xu9scdm.default\prefs.js"
set "newfile=%appdata%\Thunderbird\Profiles\5xu9scdm.default\prefs2.js"
(for /f "delims=" %%i in (%textfile%) do (
set "line=%%i"
set "line=!line:%search%=%replace%!"
echo(!line!
))>"%newfile%"
del %textfile%
rename %newfile% prefs.js
endlocal
But if I use a wildcard in the set, it doesnt work anymore.
#echo off &setlocal
setlocal enabledelayedexpansion
set "search=test"
set "replace=test2"
set "textfile=%appdata%\Thunderbird\Profiles\*.default\prefs.js"
set "newfile=%appdata%\Thunderbird\Profiles\*.default\prefs2.js"
(for /f "delims=" %%i in (%textfile%) do (
set "line=%%i"
set "line=!line:%search%=%replace%!"
echo(!line!
))>"%newfile%"
del %textfile%
rename %newfile% prefs.js
endlocal
How can I fix this ?
You approach does not work, because wild-cards can only occur in the last element of a path. In addition, for /F is not capable of handling wild-cards. So you need to wrap around a for /D loop to resolve the wild-cards, like this (supposing there is only a single matching directory *.default):
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "search=test"
set "replace=test2"
set "rootdir=%appdata%\Thunderbird\Profiles\*.default"
set "textfile=prefs.js"
set "newfile=prefs2.js"
for /D %%j in ("%rootdir%") do (
> "%%~j\%newfile%" (
for /F "usebackq delims=" %%i in ("%%~j\%textfile%") do (
set "line=%%i"
setlocal EnableDelayedExpansion
set "line=!line:%search%=%replace%!"
echo(!line!
endlocal
)
)
> nul move /Y "%%~j\%newfile%" "%%~j\%textfile%"
)
endlocal
exit /B
What I changed besides inserting the for /D loop:
delayed expansion is toggled within the loop, so exclamation marks in the text files are not lost;
all paths are properly quoted; to use a quoted file path in for /F, usebackq is required;
the replacement of the original file by the modified one is done by a single move command rather than del plus rename;
I have a text file with text on each line. I would like to be able to put each line in one long line along with a space. So, if the text file has:
Bob
Jack
Sam
I want the result to be
Bob Jack Sam
Below are two methods that I am working on but I am stuck. Anything in brackets [] means that I know the syntax is completely wrong; I only put it there to show my thought process. The commented sections are just me experimenting and I have left them in case anyone wants to comment on what they would do / why they do what they do.
Method 1:
#echo off
SETLOCAL EnableDelayedExpansion
SET count=1
FOR /F "tokens=* delims= usebackq" %%x IN ("afile.txt") DO (
SET var!count!=%%x
for %%a in (!count!) do (
!var%%a! = !var%%a! & " "
echo !var%%a!
)
SET /a count=!count!+1
echo !count!
)
::echo !var1! !var2! !var3!
start "" firefox.exe !var%%a!-1
ENDLOCAL
::echo "endlocal" %var1% %var2% %var3%
Method 2:
#echo off
SETLOCAL EnableDelayedExpansion
SET count=1
FOR /F "tokens=* delims= usebackq" %%x IN ("afile.txt") DO (
SET var!count!=%%x
call echo %%var!count!%%
SET /a count=!count!+1
echo !count!
)
::echo !var1! !var2! !var3!
start "" firefox.exe ^
[i = 1]
[for i to !count! do (]
call echo %%var!count!%% & " " & " "^
ENDLOCAL
::echo "endlocal" %var1% %var2% %var3%
If you only have three values, you can directly retrieve them from the file
< input.txt (
set /p "line1="
set /p "line2="
set /p "line3="
)
set "var=%line1% %line2% %line3%"
echo("%var%"
If you don't know the number of values, use a for /f command to read the lines and concatenate the contents into a variable.
#echo off
setlocal enableextensions enabledelayedexpansion
set "var="
for /f "usebackq delims=" %%a in ("input.txt") do set "var=!var!%%a "
echo("%var%"
But if the data can contain exclamation signs, the delayed expansion state will remove them (and the text surounded by them). To avoid it, this can be used
#echo off
setlocal enableextensions disabledelayedexpansion
set "var="
for /f "usebackq delims=" %%a in ("input.txt") do (
setlocal enabledelayedexpansion
for /f "tokens=* delims=¬" %%b in ("¬!var!") do endlocal & set "var=%%b%%a "
)
echo("%var%"
where the setlocal/endlocal and the inner for are used to avoid problems with ! character
Or you can try something like this
#echo off
setlocal enableextensions disabledelayedexpansion
for /f "delims=" %%a in ('
"<nul cmd /q /c "for /f "usebackq delims=" %%z in ("input.txt"^) do (set /p ".=%%z "^)""
') do set "var=%%a"
echo("%var%"
It runs a cmd instance to output the input lines as only one output line (<nul set /p is used to ouput the data without line feeds, so all data is in the same line). This is wrapped in a for to retrieve the output inside a variable
Would this work for you?
#echo off
SET var=
SETLOCAL EnableDelayedExpansion
FOR /f %%i in (afile.txt) DO (
SET var=!var!%%i
)
echo !var!
ENDLOCAL
Notice there is a space after the SET var=!var!%%i[Space Here] to separate each word in each row
EDIT:
If you want to display the current value in the loop just print %%i with NO concatenation. After the FOR loop finishes it will print the last value assigned to the variable
#echo off
SET var=
SETLOCAL EnableDelayedExpansion
for /f %%i in (input.txt) do (
SET var=%%i
echo !var!
)
echo %var%
Will print:
Bob
Jack
Sam
Sam
Try this: Post Edited.
#Echo off
Set "File=Recent_Log.txt"
Set "Output=My_Log.txt"
(
For /F %%F in (%File%) Do (
Set /p ".=%%~F "
)
) > "%Output%" < Nul
Goto :Eof
Because this is the first link after a Google search, I post my solution(Windows 7/10 .bat):
for %%f in (h:\blaba\*.*) do (type "%%f" & echo.) >> h:\sfsdf\dd.txt
NOTE: When your directory/filename contains spaces use double quotes.
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
Here is my .bat suffering from the adversity. Lets name it b.bat.
set loopnum=%1
set url=%2
del "%TEMP%\selectortemp.txt"
del "%TEMP%\selectortemp2.txt"
for /r %loopnum% %%i in (\*.*) do echo %%~ni%%~xi>>"%TEMP%\selectortemp.txt"
echo %loopnum%
pause
set count=0
for /f "usebackq delims=" %%a in (%TEMP%\selectortemp.txt) do set /a count+=1
set /a count2=1
:looping
for /f "tokens=1,2 delims==" %%a in (%config%) do (if %%a==url set url=%%b)
set /p firstline=<"%TEMP%\selectortemp.txt"
del "%url%\%firstline%"
echo "%firstline%"
pause
for /f "skip=1 tokens=*" %%A in (%TEMP%\selectortemp.txt) do echo %%A>>"%TEMP%\selectortemp2.txt"
del "%TEMP%\selectortemp.txt"
rename "%TEMP%\selectortemp2.txt" "selectortemp.txt"
if %count2%==%count% goto endlooping
set /a count2+=1
goto looping
:endlooping
At first, I call it by this:
for /l %%i in (0,1,3) do (call b.bat %%i C:\testing)
You are not very specific with your question.
I asume that you mean that your variables lose their content in the for loops.
You need to write !a! instead of %a%. But you can't do this with the variable used in the for loop. !!a is not possible.
Be sure to enable delayed expansion.
Here's some information about enabledelayedexpansion: SS64
I am referring to below threat Batch files: How to read a file?. For retrieving the line by line from a text file. I am using the below script:
#echo off
SETLOCAL DisableDelayedExpansion
FOR /F "usebackq delims=" %%a in (`"findstr /n ^^ paths.txt"`) do (
set "var=%%a"
SETLOCAL EnableDelayedExpansion
set "var=!var:*:=!"
echo !var!
ENDLOCAL
)
Code is working fine! The values in !var! can not assign to any variable. :( I struct there, Please anyone help to read line by line and I wish to assign to some variable and want to manipulate that variable. Please help to solve this situation.
Update:
#ECHO off
CLS
SET PROJ_DIR=D:\workspace\proj
SET PROMO_DIR=D:\TEST
SET SOURCE_CODE=\Source Code
SETLOCAL DisableDelayedExpansion
for /f %%a in (paths.txt) do (
SET "var=%%a"
SETLOCAL EnableDelayedExpansion
set "var=!var:*:=!"
set FILE_PATH=!var://www.domain.com/path/dir=!
SET FILE_PATH=!FILE_PATH:/=\!
SET PROMO_FILE_PATH=!PROMO_DIR!!SOURCE_CODE!!FILE_PATH!
FOR %%i IN ("!PROMO_FILE_PATH!") DO SET FOLDER_PATH=%%~dpi
FOR %%i IN ("!PROMO_FILE_PATH!") DO SET FILE_NAME=%%~nxi
IF EXIST "!FOLDER_PATH!" GOTO F3
MKDIR "!FOLDER_PATH!"
:F3
IF NOT EXIST "!PROJ_DIR!!FILE_PATH!" GOTO F4
COPY "!PROJ_DIR!!FILE_PATH!" "!FOLDER_PATH!"
:F4
ECHO Cannot find the file under "!PROJ_DIR!!FILE_PATH!"
ENDLOCAL
)
SET CLOSE_CONFIRM=
SET /P CLOSE_CONFIRM=Press any key to close the window...%=%
paths.txt
//www.domain.com/path/dir/dir1/dir2/file1.txt
//www.domain.com/path/dir/dir1/dir2/file2.txt
//www.domain.com/path/dir/dir1/dir2/file3.txt
//www.domain.com/path/dir/dir1/dir2/file4.txt
//www.domain.com/path/dir/dir1/dir3/file1.txt
Command Output
1 file(s) copied.
Cannot find the file under "D:\workspace\proj\dir1\dir2\file1.txt"
1 file(s) copied.
Cannot find the file under "D:\workspace\proj\dir1\dir2\file2.txt"
Press any key to close the window...
thanks..
The key is the delayed expansion, expand your variables inside of parenthesis always with ! not with %.
A sample that changes X with Y
#echo off
SETLOCAL DisableDelayedExpansion
FOR /F "usebackq delims=" %%a in (`"findstr /n ^^ paths.txt"`) do (
set "var=%%a"
SETLOCAL EnableDelayedExpansion
set "var=!var:*:=!"
set "myVar=!var!"
set "myVar=!myVar:X=Y!"
echo X replaced with Y =!myVar!
ENDLOCAL
)
In your updated version the goto :label stops the for-loop immediatly
Better rewrite it to IF-Blocks
IF NOT EXIST "!FOLDER_PATH!" (
MKDIR "!FOLDER_PATH!"
)
IF EXIST "!PROJ_DIR!!FILE_PATH!" (
COPY "!PROJ_DIR!!FILE_PATH!" "!FOLDER_PATH!"
) ELSE
(
ECHO Cannot find the file under "!PROJ_DIR!!FILE_PATH!"
)
The other answers here cover the tricky bits of delayed expansion in this code. I want to add that you can often avoid most delayed expansion problems by rolling the parentheses out into a subroutine.
FOR /F "usebackq delims=" %%a in (`"findstr /n ^^ paths.txt"`) do call :HandlePath %%a
goto :eof
================
:HandlePath
set "var=%*"
set "var=%var:*:=%"
echo %var%
goto :eof
I find this code easier to maintain because each line is parsed an executed exactly when you would expect.
If you want to read each line and manipulate it:
SETLOCAL EnableDelayedExpansion
FOR /F "tokens=*" %%a IN (paths.txt) DO (
set var=%%a
ECHO %var%
PAUSE
)
ENDLOCAL
If you are trying to search a string from a file and manipulate it:
SETLOCAL EnableDelayedExpansion
FOR /F "tokens=* usebackq" %%a IN (`FIND /I 'string to search for' "C:\folder\paths.txt"`) DO (
set var=%%a
ECHO %var%
PAUSE
)
ENDLOCAL
If you are trying to search a string and manipulate each word in the string:
SETLOCAL EnableDelayedExpansion
FOR /F "usebackq tokens=1-999 delims= " %%a IN (`FIND /I 'string to search for' "C:\folder\paths.txt"`) DO (
REM %%a = first word %%b = second word etc. through the alphabet
set var1=%%a%%b%%c
set var2=%%d
ser var3=%%e
ECHO %var1% %var2% %var3%
PAUSE
)
ENDLOCAL
This works for me:
#echo off
SETLOCAL EnableDelayedExpansion
FOR /F "usebackq delims=" %%a in (`"findstr /n ^^ paths.txt"`) do (
set var=%%a
set var=!var:*:=!
echo !var!
)
ENDLOCAL