3

I have a batch script which needs to perform an action on each of its arguments. Each argument is a file name (there are not switches), and of course file names may contain spaces. The batch script is run either by dragging files into the .bat icon in Explorer or by entering the files at the command line, enclosing arguments with spaces in quotes.

Within the batch script, there are problems with handling arguments with spaces. If I use %* as follows, the quotations are ignored and each 'word' between spaces is treated as an argument.

for %%x in (%*) do (
    echo %%x
)

I have also tried using shift, which doesn't seem to work right either, choking on files with spaces in their name:

:next
if not %1 == "" (
    echo %1

    shift /1
    goto next
)

What is the ideal way to iterate through all arguments?

In Bash, one would simply use "$@" and everything Just Works™, but of course that doesn't seem to be the case with Windows batch scripts.

2 Answers 2

3

The substitution modifiers for for variable references also allow for using the ~ expansions. See for command reference.

By using "%%~x" you should get a properly quoted parameter, similar to how bash handles "$@".

@echo off

setlocal enableextensions

for %%x in (%*) do (
    echo "%%~x"
)

The characters , and ; can be used to separate command parameters. See command shell overview. Thus you have to put quotes around file names that contain these characters.

If you drag a file from the Explorer onto the .bat, Explorer will only quote the file correctly if it has a white space character in its path. E.g., D:\a,b,c.exe will not be quoted by Explorer and thus will be parsed as three separate arguments by cmd.exe.

To make the script work with drag and drop from the Explorer for these freak cases, you can use the following (ugly) work-around:

@echo off

setlocal enableextensions enabledelayedexpansion

set "args=%*"
set "args=%args:,=:comma:%"
set "args=%args:;=:semicolon:%"

for %%x in (%args%) do (
    set "filepath=%%~x"
    set "filepath=!filepath::comma:=,!"
    set "filepath=!filepath::semicolon:=;!"
    echo "!filepath!"
)

The script introduces a helper variable args, where each occurrence of a troublesome character is replaced with a placeholder (note that the colon character itself cannot be used in a file name under Windows).

The body of the for loop uses another helper variable filepath which undos the transformation to produce the original path.

Sign up to request clarification or add additional context in comments.

2 Comments

Odd; Explorer doesn't seem to quote files with commas in their name, so the .bat has problems. This script functions just like my solution, except I guess it's a bit more robust.
@strager I have updated my solution to include a work-around for Explorer not quoting file names with ; , correctly.
0

I had a similar issue with file names that contain equal signs (=), which causes the file name to be split into multiple arguments. I solved it by using "%*".

If you have a file with spaces, e.g. foo bar baz.txt, this will be quoted twice: ""foo bar baz.txt"". Now the double double-quotes are escaped: foo bar baz.txt, resulting in %1 = foo, %2 = bar, and %3 = baz.txt. So this does not work.

If you have a file with spaces AND/OR equal signs, you can use:

set input=""%*""
set input=%input:"=%
your_program "%input%"

Now, foo bar=baz.txt will be quoted thrice: """foo bar=baz.txt""". Two quotes will be escaped and input becomes "foo bar=baz.txt". With the second line, double-quotes are replaced by nothing (removed). You need to put the quotes around input again when you enter it into your_program, otherwise it will see spaces as separate input!

If you only have equal signs, then ""%*"" makes foo=bar=baz.txt into ""foo=bar=baz.txt"", which enters your program as %1 = foo=bar=baz.txt.

2 Comments

Does this line put ALL args into a variable? set input=""%*""
@johnywhy, correct. %* is all the arguments, and then there are double double-quotes around them and then it's set to the input variable. My usecase was also dropping files onto .bat files, so I only had one argument, but cases with multiple arguments may face difficulties.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.