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

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

Related

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.

All commands error when running in my for /f loop "not recognised as an internal or external command"

I have a bizarre issue which I hope someone can help me with. I have a batch script that uses a FOR /F loop to read from a file and set variables accordingly. The command is written as follows:
FOR /F "skip=1 tokens=1-3 delims=," %%A in ('type "C:\ReconfigureSettingsFile.csv"') do (commands)
The error is:
'type "C:\ReconfigureSettingsFile.csv"' is not recognized as an internal or external command, operable program or batch file.
It happens even if I run this:
for /f "usebackq delims==" %i in (`set`) do #echo %i
'set' is not recognized as an internal or external command,
operable program or batch file.
Anyone any ideas?
There are several problems:
If you use /f, you tell the for-loop to read a file. Don't mix that with commands.
If you use backticks (`), you tell the for-loop to execute a command. You have used straight ticks (')
If you want to use quotation marks for the file name, use usebackq
So either use
FOR /F "skip=1 tokens=1-3 delims=," %%A in (C:\ReconfigureSettingsFile.csv) do (commands)
without type and without quotes or
FOR /F "usebackq skip=1 tokens=1-3 delims=," %%A in ("C:\ReconfigureSettingsFile.csv") do (commands)
without type but with quotes or
FOR "usebackq skip=1 tokens=1-3 delims=," %%A in (`type "C:\ReconfigureSettingsFile.csv"`) do (commands)
with type but without /F.
Don't forget to use %%A, %%B and %%C in the commands.
If the value of the %COMSPEC% environment variable is wrong, FOR /F with a command will report the "not recognized as an internal or external command" error.
In the registry, HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment\ComSpec should have a type of REG_EXPAND_SZ and be set to %SystemRoot%\system32\cmd.exe (at least on Windows 7).

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 to store the output of batch (CALL) command to a variable

I have the batch file which has the command to call second.bat file. It will produce single line of output when it called. I want to store that line into variable.
CALL second.bat
I have tried using the following lines of commands but no use
FOR /F "tokens=* USEBACKQ" %%F IN ('COMMAND') do SET result=%%F
FOR /F "tokens=1 delims= " %%A IN ('COMMAND') DO SET NumDocs=%%A
I don't know what to replace with COMMAND
As the help will tell you, COMMAND should be the command you want to run and get the output of. So in your case second.bat. At least it works for me:
#echo off
FOR /F "tokens=*" %%F IN ('second.bat') do SET result=%%F
echo %result%
Note that you cannot use the usebackq option if you're using ' to delimit your command.
tl;dr
To complement Joey's helpful answer (which fixes the problem with your 1st command) with a fixed version of both your commands:
:: 'usebackq' requires enclosing the command in `...` (back quotes aka backticks)
FOR /F "tokens=* usebackq" %%F IN (`second.bat`) do SET result=%%F
:: No characters must follow "delims="; 'tokens=1' is redundant
FOR /F "delims=" %%F IN ('second.bat') DO SET result=%%F
Note that in this case there's no need for call in order to invoke second.bat (which you normally need in order to continue execution of the calling batch file), because any command inside (...) is run in a child cmd.exe process.
The only thing needed to make your 2nd command work is to remove the space after delims=:
FOR /F "tokens=1 delims=" %%F IN ('second.bat') DO SET result=%%F
delims= - i.e., specifying no delimiters (separators) - must be placed at the very end of the options string, because the very next character is invariably interpreted as a delimiter, which is what happened in your case: a space became the delimiter.
Also, you can simplify the command by removing tokens=1, because with delims= you by definition only get 1 token (per line), namely the entire input (line), as-is:
FOR /F "delims=" %%F IN ('second.bat') DO SET result=%%F
Finally, it's worth noting that there's a subtle difference between tokens=* and delims=:
delims= (at the very end of the options string) returns the input / each input line as-is.
tokens=* strips leading delimiter instances from the input; with the default set of delimiters - tabs and spaces - leading whitespace is trimmed.

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