Batch Script breakline on spaces? - string

I'm using the following piece of code; to change something in a Cmakefile:
for /f %%j in (CMakeLists.txt) do (
if "%%j"=="Extensions_AntTweakBar" (
echo #Extensions_AntTweakBar >> temp.tmp
) else (
if "%%j"=="Extensions_Inspection" (
echo #Extensions_Inspection >> temp.tmp
) else (
if "%%j"=="Extensions_InspectionBar" (
echo #Extensions_InspectionBar >> temp.tmp
) else (
echo %%j >> temp.tmp
)
)
)
)
It seems to work, that is, it does change the selected lines, however, if theres a space on one line, it only gets that line till the space occurs.
Example:
SET( PROJECT_NAME "MyProject")
Only gets the string:
SET(
How am I supposed to get the full string then?

In your code you append a space at each line.
echo %%j[space]>> temp.tmp
Here you can remove it(works only with %%j), but normally it is better to set the redirection as prefix, like
>> temp.tmp echo %%j
With a normal variable the postfix variant could fail
set var=hallo2
echo %var%>temp.tmp
Expands to echo hallo2>temp.tmp or echo hallo 2> temp.tmp, so only the stderr would redirected.
The next problem are the keywords ON OFF /?, if your file contains such a word you get unexpected results, because the echo interprets these words.
[EDIT:] To solve this you can use echo(
>>temp.tmp echo(%%j
You can get empty lines (or lines with only whitespaces), you simply need to prefix them.
for /f "delims=" %%a in ('findstr /n ".*" qut.bat') do (
set var=%%a
setlocal EnableDelayedExpansion
echo(!var:*:=!
endlocal
)
The toggling of the DelayedExpansion is neccessary to preserve "!" and "^" characters

The default delimiters are space and tab. If you override the default delimiter, it should read the entire line with spaces in between
for /f "delims=#" %%j in (CMakeLists.txt) do
I set it to #, and it ignores space as delimiter and reads the entire line. You can set it a unique character that you know will not be in the text file.

Related

Command line how to search a string into a %% variable

I have a text file including filename specifications formatted as following, filename-yyyymmdd
source.txt
IMG-20190601
IMG-20190602
IMG-20190603
...
I want to read this file in order to compare the dates with a reference date and do some action depending the result. IMG is always the same, only the date is changing.
For this purpose I am trying to find the filename date into each line I am reading to compare it with today.
I did not succeed to find the right syntax, I found that extracting a substring can be done with
set SUBSTRING=%VAR:~POSITION,SIZE%
but it is not working with %%variable type.
Any help is welcome.
My code:
set comparedate=20190702
set /A i=0
for /F "usebackq delims=" %%a in (source.txt) do (
set /A i+=1
rem call echo %%i%%
rem call echo %%a
set datefile=%%a:~4,8 # the line that is not working
if %datefile% geq %comparedate% (goto here) else (goto there)
:here
echo do something
:there
echo do something else
)
Implemented my suggestions from the comments to your code. Also avoided delayed expansion by using the tokens directly (together with another method to get the date string from the filenames (by splitting at the hyphen)):
#echo off
set comparedate=20190702
set /A i=0
for /F "tokens=1,* delims=-" %%a in (source.txt) do (
ECHO FileDate=%%b
ECHO FileName=%%a-%%b [in case you need it]
if "%%b" geq "%comparedate%" (
echo do something
) else (
echo do something else
)
)

replace unneeded spaces with commas in txt using batch

I have a text file that contains some information and looks like this:
7253 198760.294 533963.581
7373 198752.213 533954.046
739CT 198751.288 533952.902
In every line there are parameters that has spaces between them but the spaces (not tabs) are for ease or reading only.
I need it to look like this:
1550,168040.682,630305.751,
1575,168023.241,630287.837,
15964TS,168008.317,630272.508,
Here is my code:
#echo off
setlocal EnableDelayedExpansion
set LF=^
set "content="
for /f "delims=" %%x in (input.txt) do (
set "content=!content!%%x!LF!"
)
:loop
if defined content (
set "new=!content: = !"
if "!new!" neq "!content!" (
set "content=!new!"
goto :loop
)
)
if defined content if "!str:~0,1!" equ " " set "content=!str:~1!"
if defined content if "!str:~-1!" equ " " set "content=!str:~0,-1!"
echo(!content!
set string=!content! & echo !string: =,! > output.txt
endlocal
pause > null
It turns everything in one line and connects between everything without spaces.
Concatenation to a single string is dangerous, because of limited max string length. Better process each line on it's own:
(for /f "tokens=1-3" %%a in (infile.txt) do (
echo %%a,%%b,%%c,
))>outfile.txt
note: empty lines will be ignored (will get lost)

Parsing sets of variables from a string in a bat file

I have a situation where I'm trying to keep a static list of related items in a string and parse them out as sets in a bat file.
SET RootPath=C:\Users\woodh\test\
SET FromPath=StuffFrom\
SET ToPath=StuffTo\
SET CTLNames='text1.txt,red_text1:text2.txt,white_text2:text3.txt,blue_text3:'
With CTLNames containing pairs of entries to be parsed and consumed in the job.
I did the following
:Step20
rem -----------------------------------------------------------------
rem loop thru all files in the control list processing each pair at a time
rem -----------------------------------------------------------------
FOR /F "delims=:" %%f IN (%CTLNames%) DO (
IF NOT "%%f" == "" (
CALL:BreakEntry "%%f"
)
)
:Finish
rem ----------------------------------------------------------------
rem -- Finish
rem ----------------------------------------------------------------
goto end
:BreakEntry
rem -----------------------------------------------------------------
rem loop thru all files in the control list processing each entry one at a time
rem -----------------------------------------------------------------
Set EntryLine=%~1
IF NOT "%EntryLine%" == "" (
ECHO %EntryLine%
FOR /F "tokens=1,2 delims=," %%a IN ("%EntryLine%") DO (
ECHO %%a
ECHO %%b
CALL:MoveThisFile %%a, %%b
)
)
goto:eof
But It's only processing the first pair of names and not continuing through the rest of the list.
Your question is confusing. You didn't explained what exactly is the purpose of your code nor the expected output, so we can only guess. So I guess that you have a series of pairs of values separated by colon, and that each pair of values is separated by comma. This way, the problem with your code is that for /F command does not iterate over several values when just one string is processed: the string is divided accordingly to "tokens and delims" options and the command is executed just one time. You need to use a different method to process all substring in the string.
This is the way I would do it:
#echo off
setlocal
SET "CTLNames=text1.txt,red_text1:text2.txt,white_text2:text3.txt,blue_text3:"
for %%f in ("%CTLNames::=" "%") do (
for /F "tokens=1,2 delims=," %%a in (%%f) do (
echo %%a
echo %%b
echo CALL :MoveThisFile %%a, %%b
)
)
I suggest you to remove the #echo off line and execute the program, so you may review what exactly is executed.
The reason why it doesn't work as expected (it only prints the 1st pair), is because for /f works on lines; CTLNames only consists of a line so a single iteration is needed.
The confusing part is that it still printed the 1st pair...that is because it actually did the split (on the 1st :) but by default for only cares about the 1st token (before the delim) and drops the rest. You can convince yourself by changing the line to:
FOR /F "tokens=* delims=:" %%f IN (%CTLNames%) DO (
you'll see that the value of %%f (because we instructed it to take all the tokens into account) is the whole line.
The reason why I asked if the COLON(:) is mandatory as a separator between pairs, is because you can also iterate over a non numeric list - no /f flag, but here you can't specify the delimiter so you must use a regular one: SPACE( ), COMMA(,), SEMICOLON(;), TAB, and maybe others (anyway COLON is not one of them) - so this loop:
for %%f in (text1.txt:red_text1 text2.txt:white_text2 text3.txt:blue_text3;) do (
echo %%f
)
- note that I used 3 separators: TAB, SPACE and SEMICOLON in the for loop (not sure how visible it is) -
would yield:
text1.txt:red_text1
text2.txt:white_text2
text3.txt:blue_text3
Or you could use regular separators everywhere, and give up at the pair concept altogether, but I don't know if this is what you want.
I wasn't able to solve the problem using COLON as a separator from a single for loop, but I was able to find a way. Here's your script (slightly modified):
#ECHO OFF
rem ECHO %CTLNames%
CALL :Step20 "%CTLNames%"
GOTO :eof
:Step20
rem -----------------------------------------------------------------
rem loop thru all files in the control list processing each pair at a time
rem -----------------------------------------------------------------
IF "" == "%~1" GOTO :eof
FOR /F "tokens=1* delims=:" %%f IN ("%~1") DO (
rem echo f: %%f
CALL :BreakEntry "%%f"
CALL :Step20 "%%g%
)
GOTO :eof
:BreakEntry
rem -----------------------------------------------------------------
rem loop thru all files in the control list processing each entry one at a time
rem -----------------------------------------------------------------
Set EntryLine=%~1
ECHO %EntryLine%
FOR /F "tokens=1,2 delims=," %%a IN ("%EntryLine%") DO (
ECHO %%a
ECHO %%b
rem CALL :MoveThisFile %%a, %%b
)
GOTO :eof
The main thing is (besides other small changes) that Step20 is a recursive function (label), and it uses the for loop to split the line, it processes the 1st token, then it calls itself on the remaining tokens (until there are no more left).
Note: the single quotes surrounding CTLNames should be removed.

BATCH - Working with string(< , >) instead of redirection

The last word in every texts in testing.txt is "< /a>", I echo out the the word and it seems to be no problem, but when I echo out in the for loop, cmd gave me this error : "The system cannot find the file specified."
I know the problem is on the "<" and ">" sign, it stands for redirection, that's how the error created. How am I going to make cmd think I'm working with a string instead of redirection?
#echo off
setlocal EnableDelayedExpansion
set "remove_char=< /a>"
echo !remove_char!
for /f "skip=2 tokens=6*" %%a in (testing.txt) do (
set "string=%%a %%b"
set string=!string:%remove_char%=!
echo !string!
)
pause >nul
If you want to use < and > symbols as variables you have to change them to ^< or ^>
Otherwise they will be treated as Input or Output!
Maybe you can replace this line
set string=!string:%remove_char%=!
with
for %%i in (!remove_char!) do (set string=!string:%%i=!)

Write batch variable into specific line in a text file

I have a batch file where I need to write a variable into a specific line of a text file and override what is all ready in that line. I have the code to read specific lines from the file maybe I could switch it around to also write?
Reading lines code:
setLocal EnableDelayedExpansion
for /f "tokens=* delims= " %%a in (variables.txt) do (
set /a N+=1
set v!N!=%%a
)
set variable1=!v1!
set variable2=!v2!
set variable3=!v3!
set variable4=!v4!
I've tried to add echo %variable1% > !v4! something like that but it doesn't work.
I figured it out!! Here is the code for anyone else who might ever need it.
#echo off
setlocal enableextensions enabledelayedexpansion
set inputfile=variables.txt
set tempfile=%random%-%random%.tmp
copy /y nul %tempfile%
set line=0
for /f "delims=" %%l in (%inputfile%) do (
set /a line+=1
if !line!==4 (
echo WORDS YOU REPLACE IT WITH>>%tempfile%
) else (
echo %%l>>%tempfile%
)
)
del %inputfile%
ren %tempfile% %inputfile%
endlocal
Another option might be to overwrite the file entirely. Here's the part to do that:
:saveVars
(
ECHO %v1%
ECHO %v2%
ECHO %v3%
ECHO %v4%
ECHO %v5%
) >variables.txt
GOTO :EOF
That is, if the number of lines is fixed and known beforehand. If not, you might want to store the last value of the increment in your example code and, when saving the variables, use it like this:
:saveVars
SETLOCAL EnableDelayedExpansion
(
FOR /L %%i IN (1,1,%N%) DO (ECHO !v%%i!)
) >variables.txt
ENDLOCAL
GOTO :EOF
I'm assuming here that the v1/v2 etc. variables would be used only for synchronising with the file: when it is read, the lines are stored in those variables, and when any of them (variables) gets changed, you just call the saveVars subroutine immediately. Here's an example how you would use it:
…
SET v2=something
CALL :saveVars
…
SET v4=%somevar%
CALL :saveVars
…
If the file is small, the rewriting should be fast enough.
Not absolutely sure I've understood everything correctly, but if you want to substitute something for an existing part of a text file with a batch script, you'll need to write everything (including the changed part) to a new file first, then delete the original and rename the new file to the original name.
I can't really see a point of reading everything into variables, unless I'm missing something. You could simply iterate over the lines writing them one by one into the new file and replacing the specific line's contents with the substitute text along the way:
setLocal EnableDelayedExpansion
>newFile.txt (
for /f "tokens=* delims= " %%a in (variables.txt) do (
set /a N+=1
if !N! == 4 (ECHO substitute text) ELSE ECHO %%a
)
)
del variables.txt
rename newFile.txt variables.txt
If the substitute text must, in turn, be derived from one of the lines, you could do something like this:
setLocal EnableDelayedExpansion
>newFile.txt (
for /f "tokens=* delims= " %%a in (variables.txt) do (
set /a N+=1
if !N! == 1 SET subst_text=%%a
if !N! == 4 (ECHO !subst_text!) ELSE ECHO %%a
)
)
del variables.txt
rename newFile.txt variables.txt

Resources