在 Windows XP 上的批处理文件中,我想使用
%*
扩展到除第一个之外的所有参数。@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
怎样才能达到想要的效果?谢谢!!
如果 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 批处理编程的众多薄弱环节之一。几乎每个解决方案都存在导致问题的异常。
这很简单:
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%
返回 * =
不认为有简单的方法可以做到这一点。您可以尝试使用以下解决方法:
@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
我最近不得不这样做并想出了这个:
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
请注意,上面的代码将为新参数添加前导空格。可以这样删除:
另一种简单的方法是:
set "_args=%*"
set "_args=%_args:* =%"
echo/%_args%
备注:
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
也许其他人可以利用此解决方案的某些方面(或提供改进建议)。
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
实现:
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
可以处理
!
?
、*
、&
、|
、,
、;
字符。可以调用内置命令。像
&
|
这样的控制字符仍然必须转义。要处理 ?
*
字符,您必须在转义符前添加前缀:^?
、^*
。无法处理=