How to make SHIFT work with %* in batch files

That´s easy:

setlocal ENABLEDELAYEDEXPANSION
  set "_args=%*"
  set "_args=!_args:*%1 =!"

  echo/%_args%
endlocal

Same thing with comments:

:: Enable use of ! operator for variables (! works as % after % has been processed)
setlocal ENABLEDELAYEDEXPANSION
  set "_args=%*"
  :: Remove %1 from %*
  set "_args=!_args:*%1 =!"
  :: The %_args% must be used here, before 'endlocal', as it is a local variable
  echo/%_args%
endlocal

Example:

lets say %* is "1 2 3 4":

setlocal ENABLEDELAYEDEXPANSION
  set "_args=%*"             --> _args=1 2 3 4
  set "_args=!_args:*%1 =!"  --> _args=2 3 4

  echo/%_args%
endlocal

Remarks:

  • Does not work if any argument contains the ! or & char
  • Any extra spaces in between arguments will NOT be removed
  • %_args% must be used before endlocal, because it is a local variable
  • If no arguments entered, %_args% returns * =
  • Does not shift if only 1 argument entered

Don't think there's a simple way to do so. You could try playing with the following workaround instead:

@ECHO OFF
>tmp ECHO(%*
SET /P t=<tmp
SETLOCAL EnableDelayedExpansion
IF DEFINED t SET "t=!t:%1 =!"
ECHO(!t!

Example:

test.bat 1 2 3=4

Output:

2 3=4

Wouldn't it be wonderful if CMD.EXE worked that way! Unfortunately there is not a good syntax that will do what you want. The best you can do is parse the command line yourself and build a new argument list.

Something like this can work.

@echo off
setlocal
echo %*
shift
set "args="
:parse
if "%~1" neq "" (
  set args=%args% %1
  shift
  goto :parse
)
if defined args set args=%args:~1%
echo(%args%

But the above has problems if an argument contains special characters like ^, &, >, <, | that were escaped instead of quoted.

Argument handling is one of many weak aspects of Windows batch programming. For just about every solution, there exists an exception that causes problems.