3

I’m trying to add some optional paramters to a batch file but am having trouble because the SHIFT command does not affect the all-arguments variable %*.

Does anyone know how I can allow for optional batch-file arguments if I have to use %*?

For example, a simple example that merely prints the arguments to the screen with and without a new-line, using an optional argument to determine which:

@echo off
if (%1)==()   goto usage
if (%1)==(/n) goto noeol
goto eol

:eol
  echo %*
  goto :eof

:noeol
  shift
  call showline %*
  goto :eof

:usage
  echo Prints text to the screen
  echo > %0 [/n] TEXT
  echo /n to NOT print a new-line at the end of the text
  goto :eof
Synetech
  • 9,643
  • 9
  • 64
  • 96

2 Answers2

6

As you know, shift has no effect on %*, but you can construct a %* equivalent.

We'll call the following line.bat :

@echo off
set line=%1
:loop
shift
if not "%1"=="" (
  set line=%line% %1
  goto :loop
)

echo   %%* = %*
echo line = %line%

If you type in the following command (Notice the double space between 3 and 4) :

line 1 2 3  4 bla dee dah

You will get the following output :

  %* = 1 2 3  4 bla dee dah
line = 1 2 3 4 bla dee dah

Note that %* retains multiple spaces, while using the %n notation does not.


Using something like this, you can allow your users to put their parameters in any order.

:loop
  :: Single variable parameters
  if "%1"=="something" set something=true
  :: Multi variable parameters 
  if "%~1"=="/source" shift & set source=%1
  shift
if not "%~1"=="" goto :loop

Notice that in the Multi-variable parameter statement I include one shift statement and one set statement separated by an ampersand (&). The & tells the command processor that a separate command to be executed follows.


EDIT:

FYI: I recommend double quotes when checking the contents of variables. Usually you can use any character, and you don't even need to use two because they are just there to insure that an empty variable does not cause an error. For instance, when %1 is empty and you do if not hello==%1 call :sub the command processor will see this if not hello== call :sub and compare hello to call then try to execute :sub, and throw an error. In that specific case if not xhello==x%1 call :sub is just as good as if not "hello"=="%1" call :sub, because an empty %1 will cause the command processor to see if not xhello==x call :sub.

BUT using characters other than double-quotes will cause problems if the variable contains any special characters.

Using brackets as variable delimiters like (%1) can cause problems. For instance, the (special) piping characters don't play nice inside brackets, and the escape character just seems to disappear, neither acting as a normal character, nor as the escape-character.

Also brackets are special characters in and of themselves designed to group and/or separate different lines of code and may not always act as anticipated.

Lastly, double quotes themselves are special characters specifically designed to surround other special characters, allowing them to act as normal characters. This is why you may see variables unquoted, then quoted again, like so.

set var="%~1"  & REM This sort of thing is used to insure that a variable is quoted.
                 REM %~1 unquotes %1 if it is already quoted, and leaves it alone if
                 REM %1 is not quoted.

set "var=%~1"  & REM This code assumes that `%1` contains special characters and
                 REM like before unquotes a quoted %1, but leaves the variable itself
                 REM unquoted. The double-quotes surrounding the variable and data
                 REM protects the command processor from any special characters that
                 REM exist in the data. Remember that anytime you reference `%var%`,
                 REM you will need to also surround the variable and data with
                 REM double-quotes.

A quick check for quotes is if exist %1 if %1==%~1 echo Unquoted.

James K
  • 4,005
  • 4
  • 20
  • 28
0

I like James’ solution because it doesn’t require anything special from the users (which is always preferable), but I just thought of another way; put the arguments in quotes and strip them at runtime:

Print.bat:

@echo off
if (%1)==()   goto usage
if (%1)==(/n) goto noeol
goto eol

:eol
            :: Use %~1 to 
    echo %~1
    goto :eof

:noeol
    shift
    call showline %~1
    goto :eof

:usage
    echo Prints text to the screen
    echo > %0 [/n] TEXT
    echo /n to NOT print a new-line at the end of the text
    goto :eof



Results:

    C:\>print.bat "foo bar baz"
    foo bar baz

    C:\>print.bat /n "foo bar baz"
    foo bar baz
    C:\>
Synetech
  • 9,643
  • 9
  • 64
  • 96
  • FYI: I recommend double quotes `""`when checking the contents of variables, rather than brackets `()`. See the last edit of my answer for why. – James K Oct 21 '12 at 20:05
  • @JamesK, I generally use parentheses for my DOS and simpler Windows batch-files because they cause less trouble for quoted arguments and have the “enclosing” sense to them. However, for compatibility and safety, it is [best to use brackets or braces](http://stackoverflow.com/questions/2541767/what-is-the-proper-way-to-test-is-variable-is-empty-in-a-batch-file-if-not-1/2541820#comment17636634_2541820) since the command-interpreter does not assign any special meaning to them like it does for quotes and parentheses. – Synetech Oct 21 '12 at 21:50