Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make SHIFT work with %* in batch files

In my batch file on Windows XP, I want to use %* to expand to all parameters except the first.
Test file (foo.bat):

@echo off
echo %*
shift
echo %*

Call:

C:\> foo a b c d e f

Actual result:

a b c d e f
a b c d e f

Desired result:

a b c d e f
b c d e f

How can I achieve the desired result? Thanks!!

like image 650
barfuin Avatar asked Feb 20 '12 14:02

barfuin


People also ask

What does %* mean in batch?

%* expands to the complete list of arguments passed to the script. You typically use it when you want to call some other program or script and pass the same arguments that were passed to your script.

What is shift in batch file?

The shift command changes the values of the batch parameters %0 through %9 by copying each parameter into the previous one—the value of %1 is copied to %0, the value of %2 is copied to %1, and so on. This is useful for writing a batch file that performs the same operation on any number of parameters.

What does %1 mean in a batch file?

When used in a command line, script, or batch file, %1 is used to represent a variable or matched string. For example, in a Microsoft batch file, %1 can print what is entered after the batch file name.


3 Answers

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.

like image 116
dbenham Avatar answered Sep 20 '22 04:09

dbenham


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
like image 25
cyberponk Avatar answered Sep 21 '22 04:09

cyberponk


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
like image 22
Andriy M Avatar answered Sep 20 '22 04:09

Andriy M