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

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

Related

For /F: Spaces in both filename and parameter [duplicate]

This question already has answers here:
windows cmd: problems with for /f with a quoted command with quoted parameters
(2 answers)
Closed 5 years ago.
In a batch file I want to set a variable to the one-line output of a program - a task explained in multiple questions and internet ressources.
In my specific task I want to execute the command
"D:\__My Program\___My Program\Folder1\Folder2\..\..\FileVersion\FileVersion\bin\Release\FileVersion.exe" /n "D:\__My Program\___My Program\Folder1\Folder2\bin\Deploy\My Program.exe"
As you can see, the path for the program I want to execute, FileVersion.exe contains spaces, and the second parameter handed to FileVersion.exe contains a full path with spaces as well.
When I call the above command either directly at the command line or by using CALL in the batch file it correctly executes the program prints out the expected output.
Now, to capture the output of executing the program I use the follow batch command
FOR /F "usebackq tokens=* delims=" %%i IN (`"D:\__My Program\___My Program\Folder1\Folder2\..\..\FileVersion\FileVersion\bin\Release\FileVersion.exe" /n "D:\__My Program\___My Program\Folder1\Folder2\bin\Deploy\My Program.exe"`) DO (
echo %%i
)
The FOR documentation says
usebackq Use the alternate quoting style:
- Use double quotes for long file names in "filenameset".
- Use single quotes for 'Text string to process'
- Use back quotes for `command to process`
I think I did this correctly by using back quotes around the command, and using quotes around the filenames.
However, the call fails with the message (translated from German)
The command "D:\My" is either incorrect or couldn't be found.
I think this points to a problem with escaping the spaces.
The weird part: If I either replace the path of the exe to call, or the parameter with a path sans spaces, it works. So both
FOR /F "usebackq tokens=* delims=" %%i IN (`FileVersion.exe /n "D:\__My Program\___My Program\Folder1\Folder2\bin\Deploy\My Program.exe"`) DO (
echo %%i
)
and
FOR /F "usebackq tokens=* delims=" %%i IN (`"D:\__My Program\___My Program\Folder1\Folder2\..\..\FileVersion\FileVersion\bin\Release\FileVersion.exe" /n Test.exe`) DO (
echo %%i
)
work.
Why don't two quote-escaped strings work in the same command and how can I fix it?
I wouldn't use usebackq and first resolve the complex path:
#Echo off
Pushd "D:\__My Program\___My Program\Folder1\Folder2\..\..\FileVersion\FileVersion\bin\Release"
FOR /F "tokens=*" %%i IN (
' FileVersion.exe /n "D:\__My Program\___My Program\Folder1\Folder2\bin\Deploy\My Program.exe" '
) DO echo %%i
PopD

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

Troubles with double quotes and for /f

I am working on a batch-script and trying to make it work in directories containing spaces. In a particular line I do the following loop:
for /f "tokens=*" %%A in ('%~dp0fciv\fciv.exe -md5 %~dp1%FN%') do ...
If the current directory contains spaces the loop will fail to call the executable. Now I put it double quotes to fix it:
for /f "tokens=*" %%A in ('"%~dp0fciv\fciv.exe" -md5 %~dp1%FN%') do ...
This works fine until the parameter doesn't have spaces. Thus I need to put it in the double quotes too:
for /f "tokens=*" %%A in ('"%~dp0fciv\fciv.exe" -md5 "%~dp1%FN%"') do ...
But this doesn't work as expected. I made additional tests straight in the cmd:
for /F "tokens=* usebackq" %A in (`"c:\Test Folder\fciv\fciv.exe" -md5 "d:\Somefile"`) do echo %A
for /F "tokens=*" %A in ('"c:\Test Folder\fciv\fciv.exe" -md5 "d:\Somefile"') do echo %A
The error is: "c:\Test" not recognized as an internal or external command, operable program or batch file.
I also tried to leave the second double quotes out again:
for /F "tokens=*" %A in ('"c:\Test Folder\fciv\fciv.exe" -md5 d:\Somefile') do echo %A
That command does surprisingly what it should.
Why does the error happening and how to achieve the desired functionality?
Enclose entire command, within the backquotes, in quotes.
C:\Users\User>for /F "usebackq tokens=*" %A in (`""C:\Users\Use r\Desktop\Editor\UEd\UEd.exe" -md5 "d:\Somefile""`) do echo %A
Removing the last backquote may have worked if no parameters.
I recently had this issue and the accepted answer did not work for me. I ended up wrapping the command and its functionality into another CMD file and then calling it from the FOR /F. Here is an example of the command:
wmic fsdir where name="C:\\some\\path\\to\\a\\folder" get creationdate
The path was extracted and passed in as a variable and the output captured and set in the DO section for the FOR /F of the calling script.
Hopes this helps someone in the future.

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

How do you loop through each line in a text file using a windows batch file?

I would like to know how to loop through each line in a text file using a Windows batch file and process each line of text in succession.
I needed to process the entire line as a whole. Here is what I found to work.
for /F "tokens=*" %%A in (myfile.txt) do [process] %%A
The tokens keyword with an asterisk (*) will pull all text for the entire line. If you don't put in the asterisk it will only pull the first word on the line. I assume it has to do with spaces.
For Command on TechNet
If there are spaces in your file path, you need to use usebackq. For example.
for /F "usebackq tokens=*" %%A in ("my file.txt") do [process] %%A
From the Windows command line reference:
To parse a file, ignoring commented lines, type:
for /F "eol=; tokens=2,3* delims=," %i in (myfile.txt) do #echo %i %j %k
This command parses each line in Myfile.txt, ignoring lines that begin with a semicolon and passing the second and third token from each line to the FOR body (tokens are delimited by commas or spaces). The body of the FOR statement references %i to get the second token, %j to get the third token, and %k to get all of the remaining tokens.
If the file names that you supply contain spaces, use quotation marks around the text (for example, "File Name"). To use quotation marks, you must use usebackq. Otherwise, the quotation marks are interpreted as defining a literal string to parse.
By the way, you can find the command-line help file on most Windows systems at:
"C:\WINDOWS\Help\ntcmds.chm"
In a Batch File you MUST use %% instead of % : (Type help for)
for /F "tokens=1,2,3" %%i in (myfile.txt) do call :process %%i %%j %%k
goto thenextstep
:process
set VAR1=%1
set VAR2=%2
set VAR3=%3
COMMANDS TO PROCESS INFORMATION
goto :EOF
What this does:
The "do call :process %%i %%j %%k" at the end of the for command passes the information acquired in the for command from myfile.txt to the "process" 'subroutine'.
When you're using the for command in a batch program, you need to use double % signs for the variables.
The following lines pass those variables from the for command to the process 'sub routine' and allow you to process this information.
set VAR1=%1
set VAR2=%2
set VAR3=%3
I have some pretty advanced uses of this exact setup that I would be willing to share if further examples are needed. Add in your EOL or Delims as needed of course.
Improving the first "FOR /F.." answer:
What I had to do was to call execute every script listed in MyList.txt, so it worked for me:
for /F "tokens=*" %A in (MyList.txt) do CALL %A ARG1
--OR, if you wish to do it over the multiple line:
for /F "tokens=*" %A in (MuList.txt) do (
ECHO Processing %A....
CALL %A ARG1
)
Edit: The example given above is for executing FOR loop from command-prompt; from a batch-script, an extra % needs to be added, as shown below:
---START of MyScript.bat---
#echo off
for /F "tokens=*" %%A in ( MyList.TXT) do (
ECHO Processing %%A....
CALL %%A ARG1
)
#echo on
;---END of MyScript.bat---
#MrKraus's answer is instructive. Further, let me add that if you want to load a file located in the same directory as the batch file, prefix the file name with %~dp0. Here is an example:
cd /d %~dp0
for /F "tokens=*" %%A in (myfile.txt) do [process] %%A
NB:: If your file name or directory (e.g. myfile.txt in the above example) has a space (e.g. 'my file.txt' or 'c:\Program Files'), use:
for /F "tokens=*" %%A in ('type "my file.txt"') do [process] %%A
, with the type keyword calling the type program, which displays the contents of a text file. If you don't want to suffer the overhead of calling the type command you should change the directory to the text file's directory. Note that type is still required for file names with spaces.
I hope this helps someone!
The accepted answer is good, but has two limitations.
It drops empty lines and lines beginning with ;
To read lines of any content, you need the delayed expansion toggling technic.
#echo off
SETLOCAL DisableDelayedExpansion
FOR /F "usebackq delims=" %%a in (`"findstr /n ^^ text.txt"`) do (
set "var=%%a"
SETLOCAL EnableDelayedExpansion
set "var=!var:*:=!"
echo(!var!
ENDLOCAL
)
Findstr is used to prefix each line with the line number and a colon, so empty lines aren't empty anymore.
DelayedExpansion needs to be disabled, when accessing the %%a parameter, else exclamation marks ! and carets ^ will be lost, as they have special meanings in that mode.
But to remove the line number from the line, the delayed expansion needs to be enabled.
set "var=!var:*:=!" removes all up to the first colon (using delims=: would remove also all colons at the beginning of a line, not only the one from findstr).
The endlocal disables the delayed expansion again for the next line.
The only limitation is now the line length limit of ~8191, but there seems no way to overcome this.
Or, you may exclude the options in quotes:
FOR /F %%i IN (myfile.txt) DO ECHO %%i
Here's a bat file I wrote to execute all SQL scripts in a folder:
REM ******************************************************************
REM Runs all *.sql scripts sorted by filename in the current folder.
REM To use integrated auth change -U <user> -P <password> to -E
REM ******************************************************************
dir /B /O:n *.sql > RunSqlScripts.tmp
for /F %%A in (RunSqlScripts.tmp) do osql -S (local) -d DEFAULT_DATABASE_NAME -U USERNAME_GOES_HERE -P PASSWORD_GOES_HERE -i %%A
del RunSqlScripts.tmp
If you have an NT-family Windows (one with cmd.exe as the shell), try the FOR /F command.
The accepted anwser using cmd.exe and
for /F "tokens=*" %F in (file.txt) do whatever "%F" ...
works only for "normal" files. It fails miserably with huge files.
For big files, you may need to use Powershell and something like this:
[IO.File]::ReadLines("file.txt") | ForEach-Object { whatever "$_" }
or if you have enough memory:
foreach($line in [System.IO.File]::ReadLines("file.txt")) { whatever "$line" }
This worked for me with a 250 MB file containing over 2 million lines, where the for /F ... command got stuck after a few thousand lines.
For the differences between foreach and ForEach-Object, see Getting to Know ForEach and ForEach-Object.
(credits: Read file line by line in PowerShell )
Modded examples here to list our Rails apps on Heroku - thanks!
cmd /C "heroku list > heroku_apps.txt"
find /v "=" heroku_apps.txt | find /v ".TXT" | findstr /r /v /c:"^$" > heroku_apps_list.txt
for /F "tokens=1" %%i in (heroku_apps_list.txt) do heroku run bundle show rails --app %%i
Full code here.
To print all lines in text file from command line (with delayedExpansion):
set input="path/to/file.txt"
for /f "tokens=* delims=[" %i in ('type "%input%" ^| find /v /n ""') do (
set a=%i
set a=!a:*]=]!
echo:!a:~1!)
Works with leading whitespace, blank lines, whitespace lines.
Tested on Win 10 CMD

Resources