web-dev-qa-db-ja.com

SHIFTをバッチファイルの%*で機能させる方法

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

どうすれば望ましい結果を達成できますか?ありがとう!

36
barfuin

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バッチプログラミングの多くの弱点の1つです。ほぼすべてのソリューションについて、問題を引き起こす例外が存在します。

20
dbenham

それは簡単です:

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

備考:

  • 引数に!が含まれている場合は機能しません。または&char
  • 引数間の余分なスペースは削除されません
4
cyberponk

そうする簡単な方法があるとは思わないでください。代わりに、次の回避策を試してみてください。

@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
3
Andriy M

DOS/Windowsバッチプログラミングのさらに別の厄介な欠点...

これが実際により良いここにある他のいくつかの答えよりも正しいかどうかはわかりませんが、私のために働いているように見える何かを共有したいと思いました。このソリューションは、gotoではなくFORループを使用し、再利用可能なバッチスクリプトに含まれています。

別のバッチスクリプト「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 

おそらく、他の誰かがこのソリューションのいくつかの側面を利用することができます(または改善のための提案を提供することができます)。

1

私は最近これをしなければならなかった、そしてこれを思いついた:

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
beatcracker

これを行う別の簡単な方法は次のとおりです。

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

echo/%_args%

備考:

  • 最初の引数(%1)が「引用符で囲まれている」または「二重引用符で囲まれている」場合は機能しません
  • 引数に&charが含まれている場合は機能しません
  • 引数間の余分なスペースは削除されません
0
cyberponk

すべてを再開し、すべての問題を修正します。

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

引数間のスペースをサポートしない:1 2 3 41 2 3 4になります