如何使 SHIFT 在批处理文件中与 %* 一起使用

问题描述 投票:0回答:8

在 Windows XP 上的批处理文件中,我想使用

%*
扩展到除第一个之外的所有参数。
测试文件 (foo.bat):

@echo off
echo %*
shift
echo %*

致电:

C:\> foo a b c d e f

实际结果:

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

期望的结果:

a b c d e f
b c d e f

怎样才能达到想要的效果?谢谢!!

batch-file windows-xp
8个回答
22
投票

如果 CMD.EXE 也能这样工作那该多好啊!不幸的是,没有一个好的语法可以满足您的要求。您能做的最好的事情就是自己解析命令行并构建一个新的参数列表。

这样的东西可以工作。

@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%

但是,如果参数包含特殊字符,如

^
&
>
<
|
等被转义而不是引用的特殊字符,上面的方法就会出现问题。

参数处理是 Windows 批处理编程的众多薄弱环节之一。几乎每个解决方案都存在导致问题的异常。


6
投票

这很简单:

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

  echo/%_args%
endlocal

同样的评论:

:: 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

示例:

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

备注:

  • 如果任何参数包含
    !
    &
    字符
  • ,则不起作用
  • 参数之间的任何额外空格都不会被删除
  • %_args%
    必须在
    endlocal
    之前使用,因为它是局部变量
  • 如果未输入参数,则
    %_args%
    返回
    * =
  • 如果仅输入 1 个参数,则不会移动

3
投票

不认为有简单的方法可以做到这一点。您可以尝试使用以下解决方法:

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

示例:

test.bat 1 2 3=4

输出:

2 3=4

2
投票

我最近不得不这样做并想出了这个:

setlocal EnableDelayedExpansion

rem Number of arguments to skip
set skip=1

for %%a in (%*) do (
  if not !position! lss !skip! (
    echo Argument: '%%a'
  ) else (
    set /a "position=!position!+1"
  )
)

endlocal

它使用循环跳过

N
第一个参数。可用于为每个参数执行一些命令或构建新的参数列表:

setlocal EnableDelayedExpansion

rem Number of arguments to skip
set skip=1

for %%a in (%*) do (
  if not !position! lss !skip! (
    set args=!args! %%a
  ) else (
    set /a "position=!position!+1"
  )
)

echo %args%

endlocal

请注意,上面的代码将为新参数添加前导空格。可以这样删除:


1
投票

另一种简单的方法是:

set "_args=%*"
set "_args=%_args:* =%"

echo/%_args%

备注:

  • 如果第一个参数 (%1) 是“引用”或“双引号”,则不起作用
  • 如果任何参数包含 & 字符,则不起作用
  • 参数之间的任何额外空格都不会被删除

1
投票

DOS/Windows 批处理编程的另一个令人讨厌的缺点......

不确定这是否真的比这里的其他一些答案“更好”,但我想我会分享一些似乎对我有用的东西。该解决方案使用 FOR 循环而不是 goto,并且包含在可重用的批处理脚本中。 单独的批处理脚本,“shiftn.bat”:

@echo off setlocal EnableDelayedExpansion set SHIFTN=%1 FOR %%i IN (%*) DO IF !SHIFTN! GEQ 0 ( set /a SHIFTN=!SHIFTN! - 1 ) ELSE ( set SHIFTEDARGS=!SHIFTEDARGS! %%i ) IF "%SHIFTEDARGS%" NEQ "" echo %SHIFTEDARGS:~1%

如何在另一个批处理脚本中使用shiftn.bat;在此示例中,获取第一个(跳过的)参数之后的所有参数:

FOR /f "usebackq delims=" %%i IN (`call shiftn.bat 1 %*`) DO set SHIFTEDARGS=%%i

也许其他人可以利用此解决方案的某些方面(或提供改进建议)。


0
投票

set Args=%1 :Parse shift set First=%1 if not defined First goto :EndParse set Args=%Args% %First% goto :Parse :EndParse

参数之间不支持空格:
1 2 3 4

将是

1 2 3 4
    


0
投票

实现:

https://github.com/andry81/contools/tree/HEAD/Scripts/Tools/std/callshift.bat

@echo off rem Description: rem Script calls second argument and passes to it all arguments beginning from %3 plus index from %1 rem Command arguments: rem %1 - shift index rem %2 - command rem %3-... - command line arguments rem Examples: rem 1. callshift.bat 2 echo "1 2" "3 4" "5 6" 7 8 rem 2. callshift.bat 0 echo."1 2" rem Drop last error level call; setlocal set "CMDLINE_TEMP_FILE=%TEMP%\callshift.%RANDOM%-%RANDOM%.txt" rem redirect command line into temporary file to print it correcly for %%i in (1) do ( set "PROMPT=$_" echo on for %%b in (1) do rem %* @echo off ) > "%CMDLINE_TEMP_FILE%" for /F "usebackq eol= tokens=* delims=" %%i in ("%CMDLINE_TEMP_FILE%") do set "LINE=%%i" del /F /Q "%CMDLINE_TEMP_FILE%" >nul 2>nul set "SHIFT=%~1" set "COMMAND=" set "CMDLINE=" set /A SHIFT+=2 if %SHIFT% LSS 2 set SHIFT=2 rem Escape specific separator characters by sequence of `$NN` characters: rem 1. `?` and `*` - globbing characters in the `for %%i in (...)` expression rem 2. `,`, `;` - separator characters in the `for %%i in (...)` expression setlocal ENABLEDELAYEDEXPANSION & for /F "eol= tokens=* delims=" %%i in ("!LINE:$=$00!") do endlocal & set "LINE=%%i" setlocal ENABLEDELAYEDEXPANSION & for /F "eol= tokens=* delims=" %%i in ("!LINE:^*=$01!") do endlocal & set "LINE=%%i" setlocal ENABLEDELAYEDEXPANSION & for /F "eol= tokens=* delims=" %%i in ("!LINE:^?=$02!") do endlocal & set "LINE=%%i" setlocal ENABLEDELAYEDEXPANSION & for /F "eol= tokens=* delims=" %%i in ("!LINE:,=$03!") do endlocal & set "LINE=%%i" setlocal ENABLEDELAYEDEXPANSION & for /F "eol= tokens=* delims=" %%i in ("!LINE:;=$04!") do endlocal & set "LINE=%%i" set INDEX=-1 for /F "eol= tokens=* delims=" %%i in ("%LINE%") do for %%j in (%%i) do ( setlocal ENABLEDELAYEDEXPANSION if !INDEX! GEQ !SHIFT! ( if defined CMDLINE ( for /F "eol= tokens=* delims=" %%v in ("!CMDLINE!") do endlocal & set "CMDLINE=%%v %%j" ) else endlocal & set "CMDLINE=%%j" ) else if !INDEX! EQU 1 ( endlocal & set "COMMAND=%%j" ) else endlocal set /A INDEX+=1 ) call; setlocal ENABLEDELAYEDEXPANSION for /F "eol= tokens=* delims=" %%i in ("!COMMAND!") do ( if defined CMDLINE ( for /F "eol= tokens=* delims=" %%v in ("!CMDLINE:$04=;!") do endlocal & set "CMDLINE=%%v" setlocal ENABLEDELAYEDEXPANSION & for /F "eol= tokens=* delims=" %%v in ("!CMDLINE:$03=,!") do endlocal & set "CMDLINE=%%v" setlocal ENABLEDELAYEDEXPANSION & for /F "eol= tokens=* delims=" %%v in ("!CMDLINE:$02=?!") do endlocal & set "CMDLINE=%%v" setlocal ENABLEDELAYEDEXPANSION & for /F "eol= tokens=* delims=" %%v in ("!CMDLINE:$01=*!") do endlocal & set "CMDLINE=%%v" setlocal ENABLEDELAYEDEXPANSION & for /F "eol= tokens=* delims=" %%v in ("!CMDLINE:$00=$!") do endlocal & set "CMDLINE=%%v" setlocal ENABLEDELAYEDEXPANSION & for /F "eol= tokens=* delims=" %%v in ("!CMDLINE!") do endlocal & endlocal & %%i %%v ) else endlocal & endlocal & %%i )

示例:

>callshift.bat 0 echo "1 2" ! ^^? ^^* ^& ^| , ; = 3 "1 2" ! ? * & | , ; 3 >callshift.bat 2 echo."1 2" 3 4 5 "1 2" 5 >callshift.bat . set | sort

优点:

可以处理
    !
  • ?
    *
    &
    |
    ,
    ;
    字符。
    可以调用内置命令。
  • 不向外部泄漏变量。
缺点:

    &
  • |
    这样的控制字符仍然必须转义。
    要处理 
  • ?
  • *
    字符,您必须在转义符前添加前缀:
    ^?
    ^*
    无法处理
  • =
  • 字符。
    写入临时文件以按原样保存命令行。
© www.soinside.com 2019 - 2024. All rights reserved.