Skip to main content

How to Shift Command-Line Arguments in Batch Script

Batch scripts are powerful because they can be made flexible by accepting command-line arguments, the parameters you pass to a script when you run it (e.g., MyScript.bat file1.txt /option). These are accessed inside the script with %1, %2, %3, and so on. But what happens if you need to process a list of arguments and you don't know how many there will be? Trying to access %1 through %9 is limiting and clumsy.

This guide will teach you how to use the built-in SHIFT command, which is the standard and most effective way to process a variable number of arguments. You will learn how to create a simple loop that can handle any number of parameters, making your scripts far more powerful and versatile.

The Core Command: SHIFT

The SHIFT command is a simple but powerful command that manipulates the list of command-line arguments. When you call SHIFT, it does the following:

  1. It discards the current value of the first argument (%1).
  2. It shifts all subsequent arguments down by one position.
    • The value of %2 is moved into %1.
    • The value of %3 is moved into %2.
    • ...and so on.

By putting this command inside a loop, you can process the first argument (%1), discard it with SHIFT, and then the next argument will be waiting in %1 for the next iteration.

The Standard Pattern: A Loop with SHIFT

The most common way to use SHIFT is inside a GOTO loop. This pattern allows you to process arguments one by one until none are left.

Example:

:ProcessLoop
REM 1. Check if there are any arguments left.
IF "%~1"=="" GOTO :EOF

REM 2. Do something with the current argument (%1).
ECHO Processing argument: %~1

REM 3. Shift the list to prepare for the next iteration.
SHIFT

REM 4. Go back to the start of the loop.
GOTO :ProcessLoop

This is the fundamental structure for processing an unknown number of arguments.

Basic Example: Echoing All Arguments

This script will take any number of arguments and print them to the screen, one by one.

ProcessArgs.bat
@ECHO OFF
SETLOCAL

ECHO --- Processing all command-line arguments ---
:Loop
IF "%~1"=="" GOTO :Done

ECHO Argument found: %~1
SHIFT
GOTO :Loop

:Done
ECHO.
ECHO --- No more arguments ---
ENDLOCAL

Example of Usage:

C:\> ProcessArgs.bat apple banana cherry "fourth argument"

and Output:

--- Processing all command-line arguments ---
Argument found: apple
Argument found: banana
Argument found: cherry
Argument found: fourth argument

--- No more arguments ---

Let's exaplain how the SHIFT loop works by tracing the execution of the example above:

  • Start: %1 is apple, %2 is banana, etc.
  • Iteration 1:
    • IF "%~1"=="" is false ("apple" is not "").
    • Prints "Argument found: apple".
    • SHIFT is called. Now %1 becomes banana, %2 becomes cherry, etc.
    • GOTO :Loop.
  • Iteration 2:
    • IF "%~1"=="" is false ("banana" is not "").
    • Prints "Argument found: banana".
    • SHIFT is called. Now %1 becomes cherry, %2 becomes "fourth argument".
    • GOTO :Loop.
  • ...and so on, until...
  • Final Iteration:
    • SHIFT is called after processing "fourth argument". Now there are no arguments left, so %1 becomes an empty string.
    • GOTO :Loop.
  • Exit Condition:
    • IF "%~1"=="" is now true ("" equals "").
    • The script jumps to the :Done label and finishes.

Advanced Usage: Starting the Shift (/n)

The SHIFT command has a rarely used switch, /n, where n is a number starting from 2. This tells SHIFT to start shifting at the nth argument, leaving all arguments before it untouched.

  • SHIFT /2: Discards %2 and shifts %3 into %2, %4 into %3, etc. %0 and %1 are unaffected.
note

This is not typically used in a loop but can be useful for manually manipulating the argument list in complex scripts.

Common Pitfalls and How to Solve Them

Problem: Handling Arguments with Spaces

If a user passes an argument with spaces and doesn't quote it, the command prompt will see it as multiple separate arguments.

Solution: Quote Arguments and Use ~

  1. When Calling: The user must enclose arguments with spaces in double quotes: MyScript.bat "My File.txt".
  2. Inside the Script: Use the tilde modifier (%~1) to get the value of the argument without the surrounding quotes. This gives you a clean string to work with but still handles the spaces correctly. The pattern IF "%~1"=="" is the robust way to check for the end of the list.

Problem: No Arguments are Provided

What happens if the user runs the script with no arguments at all?

Solution: The standard loop pattern handles this perfectly. On the very first check, IF "%~1"=="" will be true, and the script will immediately jump to the :Done label, doing nothing, which is the correct behavior.

Practical Example: A Script to Process Multiple Files

This script accepts a list of text filenames as arguments. It loops through each one, checks if the file exists, and then reports how many lines it contains.

@ECHO OFF
SETLOCAL

ECHO --- Multi-File Line Counter ---
:Loop
IF "%~1"=="" GOTO :End

SET "CurrentFile=%~1"
ECHO.
ECHO Processing: "%CurrentFile%"

IF NOT EXIST "%CurrentFile%" (
ECHO [ERROR] File not found.
) ELSE (
FOR /F %%C IN ('TYPE "%CurrentFile%" ^| FIND /C /V ""') DO (
ECHO [INFO] File contains %%C lines.
)
)

SHIFT
GOTO :Loop

:End
ECHO.
ECHO --- All files processed ---
ENDLOCAL

Conclusion

The SHIFT command is the essential tool for creating flexible batch scripts that can handle a variable number of command-line arguments. It allows you to build a simple, reliable loop to process each argument one at a time.

Key takeaways for using SHIFT:

  • Use SHIFT inside a GOTO loop to iterate through all arguments.
  • The standard exit condition is IF "%~1"=="" GOTO :EndOfLoop.
  • Always use %~1 to correctly handle arguments that may be quoted.

By mastering the SHIFT loop, you can transform your scripts from static commands into versatile tools that can operate on lists of files, servers, or any other user-provided data.