Double quotes in delims=? - for-loop

I'm very new to batch scripting, but in my last question I was trying to extract a link from a line of text, specifically:
83: href="https://beepbeep.maxresdefault.rar"><img
What I want out of it is this:
https://beepbeep.maxresdefault.rar
Someone suggested using for /f to separate the string, and I'd like to separate it every " mark, taking only the second token, as what I want is trapped between the two "".
Here is what I've got:
for /f "delims=^" tokens=^2" %%G in (output2.txt) do #echo %%G %%H >> output3.txt
The batch crashes at this point, I'm guessing it's the wrong syntax, but I'm not sure where the issue is, maybe in the " part?

See how we delimit on double quotes, without surrounding quotes. We have already assigned the variable between the quotes to %%a but if we did not, then to remove the double quotes from the string we expand the variable %%a to %%~a (see for /? on variable expansion):
#for /f delims^=^"^ tokens^=2 %%a in (output2.txt) do #echo %%~a

Neat problem.
I'd do it this way:
SETLOCAL ENABLEDELAYEDEXPANSION
for /F "tokens=2 delims=^>=" %%i in (output2.txt) do (
set x=%%i
set x=!x:"=!
echo !x! >> output3.txt
)
Notes:
Instead of tokenising on the quote, I've tokenised on = (before) and > (after). Because, as you already know, quotes are hard
I always do the delims last. Otherwise it might think the space between delims and tokens is a delimeter.
Then it uses the SET syntax that allows you to substitute one character for another to replace all occurances of the double quote with nothing.
The SETLOCAL ENABLEDELAYEDEXPANSION is necessary because otherwise, each evaluation of the %x% in the loop uses the original value of %x% which is probably wrong. I always have this as the second line in my batch file.
Judging by how much you've already got, I'm guessing you've seen it, but if you haven't, I've found ss64.com to be the best resource.
https://ss64.com/nt/syntax-dequote.html

Related

Batch script to read the last word of a sentence

I want to get last word from a sentence or file path
I tried solutions from other articles and forums but can't seem to figure it out. here is what I have so far
#echo off
set a="C:\Some\Random\File\Path.txt"
echo %a%
set b=%a:\= %
echo %b%
for /f "tokens=*" %%a in (%b%) do #echo %%a %%b %%c
pause
All I need is the last word of what ever file path I put in %a%
Just to answer specifically on your question:
#echo off
set "a=C:\Some\Random\File\Path.txt"
for %%i in (%a%) do echo %%~nxi
pause
Also see how I used the double quotes on the setting of the variable, This allows us to get rid of any wanted whitespace after the value, and also if we add the quotes after the equal, they become part of the value, which is not what we really want.
To understand the variable references, for from cmdline for /? I suggest you also see set /?
Additionally, based on your comment, if you want to set it as a viarble, simply do it :)
#echo off
set "a=C:\Some\Random\File\Path.txt"
for %%i in (%a%) do set variablename=%%~nxi
echo %variablename%
pause
While Gerhards solution IS preferable (for path), your approach wasn't that bad.
You just have to use a simple for,
so it iterates over the space seperated elements which therefor have to be unquoted.
Repeatedly setting the same variable will have the last value/word persisting.
:: Q:\Test\2019\01\18\SO_54246604.cmd
#echo off
set "a=C:\Some\Random\File\Path.txt"
echo %a%
for %%a in (%a:\= %) do Set "b=%%a"
echo %b%
pause
> SO_54246604.cmd
C:\Some\Random\File\Path.txt
Path.txt

Batch file mangling a string with special chars and quotes inside a FOR loop

This code snippet below is stripped of all the extra junk, down to just the error-generating code,
)"" was unexpected at this time.
#echo off
SETLOCAL ENABLEDELAYEDEXPANSION ENABLEEXTENSIONS
Set "regex="(Test_Health=(?!100))""
echo Regex is: %regex%
FOR /L %%I IN (1,1,5) DO (
Set "to_call=call crv.exe "%%I" %regex%"
echo About to call: !to_call!
)
Basically, in the real script, I'm trying to call a command-line tool that takes a complex string with potentially special chars in it, as well as a regex.
I figured out a workaround, which was to add a single caret (^) before %%I's last quote:
Set "to_call=call crv.exe "%%I^" %regex%"
But that feels like a dirty hack. What am I doing wrong, and what should I do to get the desired behavior without a dirty hack?
To fix your problem without a hack:
Make sure that the ! char. in your regex variable value is recognized as a literal:
Set "regex=(Test_Health=(?^!100))"
Due to setlocal enabledelayedexpansion, literal ! chars. inside "..." must be escaped as ^!.
Note that the <name>=<value> token is double-quoted as a whole, to prevent additional interpretation of the value.
Reference variable regex delayed inside the for loop body:
Use !regex! instead of %regex%.
To make the resulting command line more robust - even though it's not needed in this specific case - ensure that the value of regex is enclosed in double quotes (note that %%I - as a mere number - does not need quoting):
Set "to_call=call crv.exe %%I "!regex!""
To put it all together:
#echo off
setlocal enabledelayedexpansion enableextensions
Set "regex=(Test_Health=(?^!100))"
echo Regex is: %regex%
FOR /L %%I IN (1,1,5) DO (
Set "to_call=call crv.exe %%I "!regex!""
echo About to call: !to_call!
)
yields:
Regex is: (Test_Health=(?100))
call crv.exe 1 "(Test_Health=(?!100))"
call crv.exe 2 "(Test_Health=(?!100))"
call crv.exe 3 "(Test_Health=(?!100))"
call crv.exe 4 "(Test_Health=(?!100))"
call crv.exe 5 "(Test_Health=(?!100))"
As for what you did wrong:
%<name>%-style variable references - except for the loop variable (%%I in this case) - are expanded inside the loop body ((...)) before the loop is even parsed, so the values of such variable references can break the loop.
Here's a minimal example that demonstrates the problem:
#echo off
Set "regex=))"
FOR %%I IN ("dummy") DO (
rem !! breaks, because the up-front %regex% expansion causes a syntax error.
echo %regex%
)
Delaying the expansion - by enclosing the variable name in !...!, assuming setlocal enabledelayedexpansion is in effect - bypasses this problem:
#echo off
setlocal enabledelayedexpansion
Set "regex=))"
FOR %%I IN ("dummy") DO (
rem OK - outputs "))"
echo !regex!
)
#ECHO OFF
SETLOCAL
Set "regex="(Test_Health=(?^^^^!100^^)^^)""
SETLOCAL ENABLEDELAYEDEXPANSION ENABLEEXTENSIONS
echo Regex is: %regex%
FOR /L %%I IN (1,1,5) DO (
Set "to_call=call crv.exe "%%I" %regex%"
echo About to call: !to_call!
)
GOTO :EOF
Sort of depends on what your "desired behaviour" is. Unfortunately, you don't specify.
It's a matter of understanding how cmd works - by substitution, using escape characters and the sequence that this occurs.
The echo reporting the regex won't yield the correct result. Within the for however, each pair of carets is interpreted as a single caret, so the required escapes are as required for the expected output, presumably call crv.exe "5" "(Test_Health=(?!100))" and the like...

Reading a variable in a for loop in a bat file

I am trying to print lines from a file in the below for loop:
SET my-file="C:\tmp\xxx.txt"
#echo off
for /f "tokens=*" %%a in (%my-file%) do (
echo line=%%a
)
Where:
C:\tmp\xxx.txt contains:
a
b
c
d
But the %my-file% is not expanded. How do I use a variable in the for loop?
By putting quotes around the path, the variable is treated as a string, not a path. So %my-file% will contains the name of the file, not it's content.
you can use the same code without the quotes (if the path allows it), or use type to read the file content :
SET my-file="C:\tmp\xxx.txt"
#echo off
for /f "tokens=*" %%a in ('type %my-file%') do (
echo line=%%a
)
Your code works. If you have problems remove the echo off - which shows you that it is working.
This is your program in it's essense.
for /f "tokens=*" %%a in ("C:\tmp\xxx.txt") do echo line=%%a
And it should print, because someone put it in quotes, C:\tmp\xxx.txt as quotes mean the string is the content. No quote single or double is a filename. Single quote is a command.
If you need quotes you use UseBackQ option to move the single/double/no quote meanings around.
see For /?
Most of your batch is voodoo.
Extra unneeded brackets and sticking literals into variables.

batch rename multiple files in windows?

I wonder what's wrong with my coding, because it's not working
I want to rename all the png files inside Chris.
but it failed
for /f in ('C:/Users/Chris/Downloads/images/*.png')
do ren "C:\Users\Chris\Downloads\images\*.png" "%date:~10,4%-%date:~4,2%-%date:~7,2%_%HR%%time:~3,2%-img.png"
No need for /f in argument, no need for quotes but your missing a variable declaration
The variable should be used in the do-part otherwise the for is not realy helpful
the for will enumerate the full path so you need to strip the filename using ~n
the do-part must be directly behind the for-statement or it needs to be inside round brackets
here's the complete code:
for %%i in (C:/Users/Chris/Downloads/images/*.png) do (
ren "%%i" "%date:~10,4%-%date:~4,2%-%date:~7,2%_%HR%%time:~3,2%-%%~niimg.png"
)
If order to use a for loop, you need to specify a variable to use (even if you don't use a variable in the loop at all), otherwise you'll get a syntax error. While variables can only be one letter, this is pretty much the only time in batch that variables are case-sensitive, so you've got 52 letters, plus a few additional characters that I've seen used, like #. Additionally, do must always be on the same line as the ).
A for /F loop can process strings, text files, and other batch commands.
To process strings, use double quotes: for /F %%A in ("hello world") do echo %%A
To process batch commands, use single quotes: for /F %%A in ('dir /b') do echo %%A
To process text files, do not use any quotes at all: for /F %%A in (C:\Users\Chris\image_list.txt) do echo %%A
You may also want to go into the directory that you're processing just to make things easier.
pushd C:\Users\Chris\Downloads\images
for /F %%A in ('dir /b *.png') do (
REM I'm not sure what the %HR% variable is supposed to be, so I'm ignoring it.
ren "%%A" "%date:~10,4%-%date:~4,2%-%date:~7,2%_%HR%%time:~3,2%-img.png"
)

Ampersand as a delim in a FOR /F statement

I am trying to escape ampersand in a FOR /F statement in windows command line script, as follows:
FOR /F "tokens=1,2 delims=^&" %%A IN ("%Var%") DO (...
Result from running the script is still:
& was unexpected at this time
What is the correct way to use & as a delimeter? Or should it be replaced with something else in the string to be parsed?
The ampersand is already escaped by double quotes. So more escaping is not necessary and successful:
#echo OFF &SETLOCAL
for /f "delims=&" %%i in (file) do echo %%i
As Endoro has already stated, you don't need to escape the & within your delims specification.
Your error is probably occurring with the expansion of "%Var%". If your value contains both quotes and & in such a way that the & is not quoted after expansion, then that is precicely the error you will get. Remember that the quotes in your statement can be canceled by quotes within the value.
You could probably solve the problem using delayed expansion
setlocal enableDelayedExpansion
FOR /F "tokens=1,2 delims=&" %%A IN ("!Var!") DO (...
But if your value also contains !, then you need to disable the delayed expansion before you you expand your FOR variables, otherwise the expanded values will be corrupted.
setlocal enableDelayedExpansion
FOR /F "tokens=1,2 delims=&" %%A IN ("!Var!") DO (
endlocal
...
)

Resources