multiple quotation marks in for loop (batch file) - for-loop

Having a batch file that uses 7-Zip to "look" into a zip-file if it contains a certain file.
"C:\Program Files\7-Zip\7z.exe" l "FolderName\archive.zip" "file.cmd"
But putting it into a for-loop it produces the error: 'cannot find "C:\Program" '. Writing %ProgramFiles% also makes no difference.
for /F "delims=" %%a in ('"C:\Program Files\7-Zip\7z.exe" l "FolderName\archive.zip" "file.cmd"') do ...
However, it works if I omit the quotation around the zip-file and the file that is searched.
for /F "delims=" %%a in ('"C:\Program Files\7-Zip\7z.exe" l FolderName\archive.zip file.cmd') do ...
Finally I found a solution to put the command in a variable and place it into the for loop.
set command="C:\Program Files\7-Zip\7z.exe" l "FolderName\archive.zip" "file.cmd"
for /F "delims=" %%a in ('"%command%"') do ...
The variable still requires quotation marks. I'd like to understand how that works. How can I have multiple quoted strings that are placed in a quoted variable but cannot pass them directly to the for loop.
It seems to be a similar problem as the operators like &, >, |, ... that need escaping with ^. I tried that too, but with no success. It kept me asking: "more?" thus the closing bracket wasn't found anymore.

Well, you actually answered your own question without looking closely.
Let me show you why:
set command="C:\Program Files\7-Zip\7z.exe" l "FolderName\archive.zip" "file.cmd"
for /F "delims=" %%a in ('"%command%"') do ...
Note that your code translates the value of the set command to:
"C:\Program Files\7-Zip\7z.exe" l "FolderName\archive.zip" "file.cmd"
where you then pass that to the loop in double quotes again, as:
"%command%"
which ends up being:
""C:\Program Files\7-Zip\7z.exe" l "FolderName\archive.zip" "file.cmd""
Which will work exactly in a for loop:
for /f "delims=" %%i in ('""C:\Program Files\7-Zip\7z.exe" l "FolderName\archive.zip" "file.cmd""') do ...
Though that will work as expected in this case, it will fail if your quoted strings contain special characters like & as shown in this example:
for /f "delims=" %%i in ('""C:\Program Files\7-Zip\7z.exe" l "FolderName\archives & backups.zip" "file.cmd""') do ...
So you need to simply escape the outer double quotes to overcome this:
for /f "delims=" %%i in ('^""C:\Program Files\7-Zip\7z.exe" l "FolderName\archives & backups.zip" "file.cmd"^"') do ...
Point 2. from cmd /? seemingly states this behaviour, as per the below screenshot:

Related

Passing Multiple Arguments in a Batch FOR loop using Double Quotes?

I'm using a MediaInfo CLI in a batch script and I don't know what the issue is, but I cannot get this command to work if I use a folder path that has spaces in it. I'm not new to batch scripts and have created hundreds over the years. Normally I would think that using double quotes would solve the issue, but I know it's something else related to using the "for /f" command and passing multiple arguments with double quotes. I've tried everything I could think of but still can't get it to work if I'm using a path with spaces. Without spaces it works just fine, just not with spaces.
Please Note that this is not the full batch script and is only a snippet of the offending code. I also changed the double "%%" variables to single "%" to make it easier for testing on the command line.
Also, in my batch script, instead of using "echo" I am outputting to a variable, which is why I must use the "for" command. All of which is irrelevant to this specific issue.
WORKING EXAMPLES
for /f %g in ('C:\MediaInfo.exe "--Inform=General;%MenuCount%" "D:\Some Folder\filename.mkv"') do echo %g
.
for /f "usebackq delims=" %g in (`C:\MediaInfo.exe "--Inform=General;%MenuCount%" "D:\Some Folder\filename.mkv"`) do echo %g
.
NOT WORKING EXAMPLES
for /f %g in ('"C:\folder with spaces\MediaInfo.exe" "--Inform=General;%MenuCount%" "D:\Some Folder\filename.mkv"') do echo %g
.
for /f "usebackq delims=" %g in (`C:\folder with spaces\MediaInfo.exe "--Inform=General;%MenuCount%" "D:\Some Folder\filename.mkv"`) do echo %g
Both of the "NOT WORKING" commands result in the same error...
'C:\folder' is not recognized as an internal or external command,
operable program or batch file.
The command within the set (that is the parenthesised part before do) of a for /F loop is actually executed by cmd /C, which may remove potential quotes depending on their positions.
For instance, in the command line:
for /f "delims=" %g in ('"C:\folder with spaces\MediaInfo.exe" "--Inform=General;%MenuCount%" "D:\Some Folder\filename.mkv"') do echo %g
the outer pair of quotes is removed, leaving behind the invalid command line:
C:\folder with spaces\MediaInfo.exe" "--Inform=General;%MenuCount%" "D:\Some Folder\filename.mkv
If you now add an additional pair of quotes, it will work. You may even escape these quotes not to have to alter any other escaping in case:
for /f "delims=" %g in ('^""C:\folder with spaces\MediaInfo.exe" "--Inform=General;%MenuCount%" "D:\Some Folder\filename.mkv"^"') do echo %g

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"
)

windows cmd: problems with for /f with a quoted command with quoted parameters

for /f "delims=" %%a in ('"%systemRoot%\system32\find.exe" /?') do #echo %%a
Yes, the previous line works. Not much useful but works. But trying write a batch file to answer another question, i faced something like
for /f %%a in ('"%systemRoot%\system32\find.exe" /c /v "" ^< "c:\something.txt"') do #echo %%a
for /f %%a in ('"%systemRoot%\system32\find.exe" /c /v "" "c:\something.txt"') do #echo %%a
Both of the previous lines return The filename, directory name, or volume label syntax is incorrect
for /f %%a in ('"%systemRoot%\system32\find.exe" /c /v "" ^< c:\something.txt' ) do #echo %%a
for /f %%a in ('"%systemRoot%\system32\find.exe" /c /v "" c:\something.txt' ) do #echo %%a
Both of the previous lines return The system cannot find the file specified
I've been unable to make it work, neither scaping the quotes, doubling them, preceding with backslashes, changing to single quotes to backquotes and setting the corresponding option in for command, all the combinations that i tried failed.
If the command to run is quoted and it takes quoted arguments it fails.
And yes, i know the quotes surounding the find are not needed, and if removed, any of the previous four lines will work (ignoring the output, delims, tokens)
But in the case where the quotes surounding the command are really needed (and i know systems where 8dot3name behaviour is disabled), is there any way to make it work? what am i missing here?
Here are two solutions.
1) has surrounding double quotes and removed ^ escape character.
2) uses find as it is on the path.
for /f %%a in ('""%systemRoot%\system32\find.exe" /c /v "" < "c:\something.txt""') do #echo %%a
for /f %%a in (' find.exe /c /v "" ^< "c:\something.txt"') do #echo %%a
It's to do with launching an extra cmd process to run the command-line inside the for command.
Curiously, these three commands fail differently in an even simpler context.
for /f %%a in (' "c:\windows\system32\find.exe" /c /v "" something.txt ') do #echo %%a
The system cannot find the path specified.
for /f %%a in (' "c:\windows\system32\findstr.exe" /n "." something.txt ') do #echo %%a
The directory name is invalid.
for /f %%a in (' "c:\windows\notepad" "something.txt" ') do #echo %%a
'c:\windows\notepad" "something.txt' is not recognized as an internal or external command, operable program or batch file.
This last one gives a clue that the outer quotes are being stripped.
Windows 8.1 32 bit
I think the quote issue is described here in cmd /? when a child process is invoked:
If /C or /K is specified, then the remainder of the command line after
the switch is processed as a command line, where the following logic is
used to process quote (") characters:
1. If all of the following conditions are met, then quote characters
on the command line are preserved:
- no /S switch
- exactly two quote characters
- no special characters between the two quote characters,
where special is one of: &<>()#^|
- there are one or more whitespace characters between the
two quote characters
- the string between the two quote characters is the name
of an executable file.
2. Otherwise, old behavior is to see if the first character is
a quote character and if so, strip the leading character and
remove the last quote character on the command line, preserving
any text after the last quote character.
It is somewhat easier to put the first token from the instruction of the for-loop into a token without quotes.
for /f "delims=" %%a in (
' if defined OS "C:\my folder with spaces\consoleapp.exe" /param1:"value" '
)do #echo %%a

Batch For Loop Escape Asterisk

I am attempting to create a batch for loop (Windows XP and newer command prompts) that iterates through a string containing one or more asterisks. How can I do this? Here is an example:
#FOR %%A IN (A* B) DO #ECHO %%A
The expected output (what I am trying to get) is the following:
A*
B
However, what I am actually getting with the command above is B and only B. For some reason, everything with an asterisk is being ignored by the loop. I have attempted escaping the asterisk with 1-4 carets (^), backslashes (\), percent signs (%), and other asterisks (*), all to no avail. Thanks in advance for illuminating me.
IN CASE YOU WANT MORE INFORMATION:
The purpose of this is to parse a path out of a list of space-separated partial paths. For example, I want to copy C:\Bar\A.txt, C:\Bar\B.txt, and C:\Bar\C*.txt to C:\Foo\ using the following approach:
#SET FILE_LIST=A B C*
#FOR %%A IN (%FILE_LIST%) DO #COPY C:\Bar\%%A.txt C:\Foo\
If there is another alternative way to do this (preferably without typing each and every copy command since there are ~200 files, which is the same reason I don't want to store the full path for every file), I would appreciate the help. Thanks again,
-Jeff
the asterisks works the way its intended, in your case,
#FOR %%A IN (A* B) DO #ECHO %%A
expands A* to all the files that begin with A.
A possible way to do what you want, is just to use this expansion
#ECHO off
PUSHD C:\bar
SET FILE_LIST=A.txt B.txt C*.txt
FOR %%A IN (%FILE_LIST%) DO (
IF EXIST %%A COPY %%A C:\Foo\
)
POPD
This may help:
#echo off
set "it=a*b .txt-b*.txt-c*.txt-d.txt"
set /a i=0,fn=3
:startLoop
set /a i=i+1
for /f "tokens=%i%delims=-" %%m in ("%it%") do echo %%m
if %i% lss %fn% goto:startLoop

Escaping ampersands in Windows batch files

I realise that you can escape ampersands in batch files using the hat character
e.g.
echo a ^& b
a & b
But I'm using the command
for /f "tokens=*" %%A IN ('DIR /B /A-D /S .acl') DO ProcessACL.cmd "%%A"
which is finding all the files named '.acl' in the current directory, or a subdirectory of the current directory.
The problem is, I'm finding path names that include the '&' character (and no, they can't be renamed), and I need a way of automatically escaping the ampersands and calling the second batch file with the escaped path as the parameter.
rem ProcessACL.cmd
echo %1
The problem is not the escaping, it seems to be in the second script.
If there is a line like
echo %1
Then it is expands and fails:
echo You & me.acl
Better to use delayed expansion like
setlocal EnableDelayedExpansion
set "var=%~1"
echo !var!
To avoid also problems with exclamation points ! in the parameter, the first set should be used in a DisableDelayedExpansion context.
setlocal DisableDelayedExpansion
set "var=%~1"
setlocal EnableDelayedExpansion
echo !var!
Your for line should be (note the *.acl)
for /f "tokens=*" %%A IN ('DIR /B /A-D /S *.acl') DO ProcessACL.cmd "%%A"
ProcessACL.cmd can access the path passed to it with %1.
// ProcessACL.cmd
ECHO %1
Whatever is contained by the variable %1 is fully contained. There is no need for escapes. Escapes are for the batch processor to interpret the characters it is parsing.

Resources