Batch files - number of command line arguments

Viewed 148406

Just converting some shell scripts into batch files and there is one thing I can't seem to find...and that is a simple count of the number of command line arguments.

eg. if you have:

myapp foo bar

In Shell:

  • $# -> 2
  • $* -> foo bar
  • $0 -> myapp
  • $1 -> foo
  • $2 -> bar

In batch

  • ?? -> 2 <---- what command?!
  • %* -> foo bar
  • %0 -> myapp
  • %1 -> foo
  • %2 -> bar

So I've looked around, and either I'm looking in the wrong spot or I'm blind, but I can't seem to find a way to get a count of number of command line arguments passed in.

Is there a command similar to shell's "$#" for batch files?

ps. the closest i've found is to iterate through the %1s and use 'shift', but I need to refernece %1,%2 etc later in the script so that's no good.

8 Answers

A reasonably robust solution is to delegate counting to a subroutine invoked with call; the subroutine uses goto statements to emulate a loop in which shift is used to consume the (subroutine-only) arguments iteratively:

@echo off
setlocal

:: Call the argument-counting subroutine with all arguments received,
:: without interfering with the ability to reference the arguments
:: with %1, ... later.
:: NOTE: See comments re /? below.
call :count_args %* >NUL || (echo Usage: ... & exit /b 0)

:: Print the result.
echo %ReturnValue% argument(s) received.

:: Exit the batch file.
exit /b

:: Subroutine that counts the arguments given.
:: Returns the count in %ReturnValue%
:count_args
  set /a ReturnValue = 0
  :count_args_for
    if %1.==. goto :eof
    set /a ReturnValue += 1
    shift
  goto count_args_for

Limitations:

  • /? among the arguments - except if passed as "/?" - is not supported, because call invariably interprets it as a request to show its command-line help.

    • The code above detects this case (curiously, call signals failure via its exit code after showing its help) and interprets this case as wanting to show the current batch file's help instead of counting arguments.
  • Arguments with metacharacters (special characters) are supported, if enclosed in "..." (as is typical), but character-individual ^-escaping in an unquoted argument does not work (because the ^ is already stripped by the time the batch file sees the arguments, and expanding %* then causes the metacharacters to act as such):

    :: OK - arguments with special chars. are "..."-enclosed.
    :: -> "3 argument(s) received."
    test.cmd hi "you & me" "a<b"
    
    :: !! FAILS
    :: The last argument uses character-individual ^-escaping.
    :: -> error "The system cannot find the file specified."
    test.cmd hi "you & me" a^<b
    
  • A syntactically invalid argument list is not supported (which is arguably not a problem):

    :: !! FAILS
    :: Syntactically invalid argument list
    :: -> error "The syntax of the command is incorrect."
    test.cmd a"
    

The last answer was two years ago now, but I needed a version for more than nine command line arguments. May be another one also does...

@echo off
setlocal

set argc_=1
set arg0_=%0
set argv_=

:_LOOP
set arg_=%1
if defined arg_ (
  set arg%argc_%_=%1
  set argv_=%argv_% %1
  set /a argc_+=1
  shift
  goto _LOOP
)
::dont count arg0
set /a argc_-=1
echo %argc_% arg(s)

for /L %%i in (0,1,%argc_%) do (
  call :_SHOW_ARG arg%%i_ %%arg%%i_%%
)

echo converted to local args
call :_LIST_ARGS %argv_%
exit /b


:_LIST_ARGS
setlocal
set argc_=0
echo arg0=%0

:_LOOP_LIST_ARGS
set arg_=%1
if not defined arg_ exit /b
set /a argc_+=1
call :_SHOW_ARG arg%argc_% %1
shift
goto _LOOP_LIST_ARGS


:_SHOW_ARG
echo %1=%2
exit /b

The solution is the first 19 lines and converts all arguments to variables in a c-like style. All other stuff just probes the result and shows conversion to local args. You can reference arguments by index in any function.

Related