Relatively new to batch scripts here and I have been searching everywhere for the answer only to not find anything.
Here is what I have for a batch script so far..
#echo off
set addtext="text to add includes spaces"
for /f "delims=" %%l in (file.txt) do (
echo %%l %addtext% >> tmpfile.txt
)
I'm looking to add a line of text to every line in the file but my problem comes in with the double quotes. I don't want the quotes to display with the text.
I only have the quotes there because there are spaces in the string of text that I'm looking to add to every line.
#echo off
setlocal enableextensions disabledelayedexpansion
set "addtext=text to add includes spaces"
for /f "delims=" %%l in (file.txt) do (
>> tmpfile.txt echo %%l %addtext%
)
This should work. Just not include the quotes in the value of the variable, but use them to wrap the assignment.
In cases where the string could contain more problematic characters, this is a safer version
#echo off
setlocal enableextensions disabledelayedexpansion
set "addtext=text to add includes spaces, > redirections & more problems !"
(for %%a in ("%addtext%") do for /f "delims=" %%l in (file.txt) do (
echo %%l %%~a
)) >> tmpfile.txt
Quotes are not included in the value, but wraps the assignation
To prevent problem accessing the variable, it is wrapped in quotes, stored in a for replaceable parameter (%%a) and when requested echoed without the quotes (%%~a)
Just to get better performance (should be used also in the first code) instead of open/write/close the output file for each line (redirection for each echo), redirection is handled for the full for command.
Related
I'm writing batch script on Windows, with it's help I would like to sort out information from many files to smaller files.
I got ~3000 long lines in log files, from whom I need get few things, basically there are name and value (example ",INC_LIMI=050,ISO_LIMI=050,INC_MLIM=074,"), and everything is separated with "," symbol. My question how you can read long string line and just read values like:
String LineString[]
LineString = Line.split(,)
String s = "INC_MLIM"
For elem in LineString
if elem.exist(s)
NewLine.append(elem)
and latter on just save to new file.
EDIT:
There is service.log file which contains multiple lines with same variable names, but I don't need all of them so the thing I'm trying to do is
From line :
",INC_MLIM=074,ISO_MLIM=074,LOC_LI_P=050,LOC_LI_L=050,TRI_LI_P=074,TRI_LI_L=074,"
Transform to new line structure with less variables and separate with tabs instead of comma. New line should look something like this:
"INC_MLIM=074 ISO_MLIM=074 LOC_LI_L=050 TRI_LI_L=074"
You don't state which values you want. I'll arbitrarily assume you want INC_LIMI and INC_MLIM.
Like most any text file manipulation, this is a pain to do with pure batch. But it is possible.
I'm assuming your lines are all <8192 characters long. If you have lines that are longer than that, then a pure batch solution is not possible, and you should skip right down to the bottom of this answer for a JREPL solution
Batch does not have a convenient split function that allows splitting at a specific user defined character. The FOR command almost works, but it also splits at ;, =, <tab>, and <space>. So it is not a good choice.
With the correct arcane syntax, you can use variable expansion find/replace to substitute a newline (0x0A) for every comma. This will generate one name=value pair per line, which is very convenient for letting FINDSTR filter out the values that you want.
Here is a solution that relies on a temporary table. This iterates all *.log files, and for each one, it creates output in *.log.new.
#echo off
setlocal enableDelayedExpansion
(set LF=^
%= This creates a newline 0x0A character =%
)
for %%N in ("!LF!") do for %%F in (*.log) do (
(
for /f "usebackq delims=" %%A in ("%%F") do (
set "ln=%%A"
echo(!ln:,=%%~N!
)
)>"%%F.temp"
findstr /b "INC_LIMI= INC_MLIM=" "%%F.temp" >"%%F.new"
del "%%F.temp"
)
type *.log.new
exit /b
Note that the above can fail if your log files contain !. This could be solved by toggling delayed expansion on and off as needed.
Some people don't like to use temp files. In this case, getting rid of the temp file introduces even more arcane batch constructs. But it does eliminate the ! delayed expansion issue, and the code is shorter. This version can also be significantly slower if the source files are very large.
#echo off
setlocal disableDelayedExpansion
(set LF=^
%= This creates a newline 0x0A character =%
)
for %%F in (*.log) do (
for /f "usebackq delims=" %%A in ("%%F") do (
set "ln=%%A"
cmd /v:on /c "for %%N in ("!LF!") do #echo(!ln:,=%%~N!"|findstr /b "INC_LIMI= INC_MLIM="
)
) >"%%F.new"
type *.log.new
exit /b
It is also possible to solve this without using FINDSTR. But this solution assumes the same name never appears more than once on any given line, and all found names have a value:
#echo off
setlocal disableDelayedExpansion
for %%F in (*.log) do (
for /f "usebackq delims=" %%A in ("%%F") do (
set "ln=,%%A"
for %%N in (INC_LIMI INC_MLIM) do call :findName %%N
)
) >"%%F.new"
type *.log.new
exit /b
:findName Name
setlocal enableDelayedExpansion
set "test=!ln!"
:loop
set "test2=!test:*,%1=!"
if "!test2!" equ "!test!" return
if not defined test2 return
if "!test2:~0,1!" neq "=" set "test=,!test2:*,=!" & goto :loop
for /f "delims=," %%V in ("!test2:~1!") do (
endlocal
echo(%1=%%V
)
exit /b
Here is a variation that handles empty values, but can break if a value contains quotes or poison characters:
#echo off
setlocal disableDelayedExpansion
for %%F in (*.log) do (
for /f "usebackq delims=" %%A in ("%%F") do (
set "ln=,%%A"
for %%N in (INC_LIMI INC_MLIM) do call :findName %%N
)
) >"%%F.new"
type *.log.new
exit /b
:findName Name
setlocal enableDelayedExpansion
set "test=!ln!"
:loop
set "test2=!test:*,%1=!"
if "!test2!" equ "!test!" return
if not defined test2 return
if "!test2:~0,1!" neq "=" set "test=,!test2:*,=!" & goto :loop
set "test2=%1!test2!
endlocal&echo(%test2:,=&rem %
exit /b
But I wouldn't use any of the above. In fact, I would never restrict myself to pure batch because text file manipulation is so darn inefficient and inscrutable.
Instead, I would use JREPL.BAT - a regular expression command line text processing utility. JREPL.BAT is pure script (hybrid JScript/batch) that runs natively on any Windows machine from XP onward - no 3rd party exe file required.
With JREPL, the solution is as simple as
#echo off
for %%F in (*.log) do call jrepl "(?:^|,)((?:INC_LIMI|INC_MLIM)=[^,]*)" "$txt=$1" /jmatchq /f "%%F" /o "%%F.new"
type *.log.new
Not only is the code nice and clean, it is much faster than any pure batch solution.
I'm working on a DOS script in order to search a line and replace it into files from a specific folder. Here is what i have already done :
#echo off
setlocal enableextensions disabledelayedexpansion
set "search=#Interceptors({ RuntimeExceptionInterceptor.class }^)"
set "replace=#Interceptors({ RuntimeExceptionInterceptor.class, ReportInterceptor.class, CorrelationIdInterceptor }^)"
set "textFile=C:\Utilisateurs\a669884\Documents\test.txt"
for %%a in (*.txt) do (
echo "%%a"
for /f "Delims=" %%i in (%%a ^& break ^> %%a) do (
set "line=%%i "
setlocal enabledelayedexpansion
>>%%a echo(!line:%search%=%replace%!
endlocal
)
)
Problem is that my first line is not replace by the new one, the new line is added under it like that :
#Interceptors({ RuntimeExceptionInterceptor.class })
#Interceptors({ RuntimeExceptionInterceptor.class, ReportInterceptor.class, CorrelationIdInterceptor })
Do you know why my first line isn't replaced? Thanks a lot
Seb
Not sure what setting textfile has to do with the routine - it's not used.
Your original code produced a complaint that & was not found and created an empty file for me.
Changing the for to
for /f "Delims=" %%i in ('type "%%a" ^& break ^> "%%a"') do (
seemed to make the substitution, given the one line (partial?) of sourcefile you've provided, plus a few dummy lines.
execute the type... with the filenames enclosed in quotes to ensure correct operation with separators, replacing the file; substitute as specified.
With this batch file, I get a trailing space on every line in the output txt file:
#echo off
setlocal enabledelayedexpansion
for /f "delims==" %%A in (trimlist.txt) do set string=%%A & echo !string:,=.!>>trimlist-new.txt
How do I go about removing the trailing spaces? I want to avoid creating a new batch file to do so if possible.
The space between %%A and = is being included in your string. To avoid it, you can either have a multi-line for loop, or simply put quotes around your set statement.
#echo off
setlocal enabledelayedexpansion
for /f "delims==" %%A in (trimlist.txt) do set "string=%%A" & echo !string:,=.!>>trimlist-new.txt
I am trying to get a batch to file read a text file from dropbox and execute it as variables in the batch file.
this is what i am trying, but it does not work, please help!
SetLocal EnableDelayedExpansion
set content=
for /F "delims=" %%i in (DROPBOX-LINK-HERE) do set content=!
content! %%i
%content%
EndLocal
I'm not sure what you mean by DROPBOX-LINK-HERE, but I am using an ordinary text file for content.
You must separate each line with & or else enclose the content in parentheses and separate each line with <linefeed>. The linefeed solution is more complicated, but has fewer limitations on the content.
Any ! characters in the content will be corrupted during expansion of a FOR variable if delayed expansion is enabled. But delayed expansion is needed to preserve unquoted special characters. So delayed expansion needs to be creatively toggled on and off.
Here is code that I think does what you want.
#echo off
setlocal disableDelayedExpansion
::Define a carriage return variable
for /f %%a in ('copy /Z "%~dpf0" nul') do set "CR=%%a"
::Create a newline variable
set LF=^
::The above 2 blank lines are critical - do not remove
::Both CR and LF should be expanded using delayed expansion only.
::Load the content into a variable.
::We want to separate lines with linefeed, but FOR /F won't preserve linefeeds.
::So use carriage return as a place holder for now.
set "content=("
setlocal enableDelayedExpansion
for /f %%C in ("!CR! ") do (
endlocal
for /f "delims=" %%A in (test.txt) do (
setlocal enableDelayedExpansion
for /f "delims=" %%B in ("!content!") do (
endlocal
set "content=%%B%%C%%A"
)
)
)
::Now replace carriage returns with newline and append terminating )
setlocal enableDelayedExpansion
for /f %%C in ("!CR! ") do for %%N in ("!LF!") do set "content=!content:%%C=%%~N!%%~N)"
::Execute the content
endlocal&%content%
The code works, but there are limitations to the type of code that can be executed from a variable.
Variables cannot be expanded by using normal expansion unless you use CALL. For example, a line like echo %var% will not work, but call echo %var% will work. Another option is to use delayed expansion. SETLOCAL EnableDelayedExpansion and ENDLOCAL can be included in the content as needed.
You cannot CALL or GOTO a :LABEL within the content.
That's all I can remember at the moment, but there may be (probably are) other restrictions.
I have one question though:
If the content is already in a text file, then why not simply give the text file a .BAT extension and execute it?
How you can read a file (text or binary) from a batch file? There is a way to read it in a binary mode or text mode?
Under NT-style cmd.exe, you can loop through the lines of a text file with
FOR /F %%i IN (file.txt) DO #echo %%i
Type "help for" on the command prompt for more information. (don't know if that works in whatever "DOS" you are using)
The FOR-LOOP generally works, but there are some issues.
The FOR doesn't accept empty lines and lines with more than ~8190 are problematic.
The expansion works only reliable, if the delayed expansion is disabled.
Detection of CR/LF versus single LF seems also a little bit complicated.
Also NUL characters are problematic, as a FOR-Loop immediatly cancels the reading.
Direct binary reading seems therefore nearly impossible.
The problem with empty lines can be solved with a trick. Prefix each line with a line number, using the findstr command, and after reading, remove the prefix.
#echo off
SETLOCAL DisableDelayedExpansion
FOR /F "usebackq delims=" %%a in (`"findstr /n ^^ t.txt"`) do (
set "var=%%a"
SETLOCAL EnableDelayedExpansion
set "var=!var:*:=!"
echo(!var!
ENDLOCAL
)
Toggling between enable and disabled delayed expansion is neccessary for the safe working with strings, like ! or ^^^xy!z.
That's because the line set "var=%%a" is only safe with DisabledDelayedExpansion, else exclamation marks are removed and the carets are used as (secondary) escape characters and they are removed too.
But using the variable var is only safe with EnabledDelayedExpansion, as even a call %%var%% will fail with content like "&"&.
EDIT: Added set/p variant
There is a second way of reading a file with set /p, the only disadvantages are that it is limited to ~1024 characters per line and it removes control characters at the line end.
But the advantage is, you didn't need the delayed toggling and it's easier to store values in variables
#echo off
setlocal EnableDelayedExpansion
set "file=%~1"
for /f "delims=" %%n in ('find /c /v "" %file%') do set "len=%%n"
set "len=!len:*: =!"
<%file% (
for /l %%l in (1 1 !len!) do (
set "line="
set /p "line="
echo(!line!
)
)
For reading it "binary" into a hex-representation
You could look at SO: converting a binary file to HEX representation using batch file
You can use the for command:
FOR /F "eol=; tokens=2,3* delims=, " %i in (myfile.txt) do #echo %i %j %k
Type
for /?
at the command prompt. Also, you can parse ini files!
One very easy way to do it is use the following command:
set /p mytextfile=< %pathtotextfile%\textfile.txt
echo %mytextfile%
This will only display the first line of text in a text file. The other way you can do it is use the following command:
type %pathtotextfile%\textfile.txt
This will put all the data in the text file on the screen. Hope this helps!
settings.ini
name="John"
lastName="Doe"
script.bat
#echo off
for /f "tokens=1,2 delims==" %%a in (settings.ini) do (
if %%a==name set %%a=%%b
if %%a==lastName set %%a=%%b
)
echo %name% %lastName%
Well theres a lot of different ways but if you only want to DISPLAY the text and not STORE it anywhere then you just use: findstr /v "randomtextthatnoonewilluse" filename.txt
Corrected code :
setlocal enabledelayedexpansion
for /f "usebackq eol= tokens=* delims= " %%a in (`findstr /n ^^^^ "name with spaces.txt"`) do (
set line=%%a
set "line=!line:*:=!"
echo(!line!
)
endlocal
pause