%1
行が解析されるときに が展開され、括弧で囲まれた IF 構造全体がすべて 1 回のパスで解析されるため、これは予想される動作です。したがって、新しい行が解析されるまで SHIFT の結果を見ることはできません。これは、括弧で囲まれたブロックを離れるまで発生しません。
を使用して環境変数を展開すると、同じ問題が発生します%var%
。SETLOCAL EnableDelayedExpansion
環境変数を使用すると、 を使用して遅延展開を有効にし、次に を使用して問題を回避できます!var!
。しかし、遅延拡張を使用してパラメーターを拡張する同等の方法はありません。
EDIT 2013-06-21 - 同等の方法はありませんが、比較的遅い単純な方法があります。
CALL を使用して%
.
@echo off
if "%1"=="/p" (
echo %1
shift
echo "shifted"
call echo %%1
)
EDIT 2016-07-15 Vladislav の回答
のコードは、GOTO を使用してコード ブロックを終了した後、コード ブロック内でジャンプして戻ることができることを意味するため、悪い習慣です。それは単に機能しません。GOTO は、解析されたコード ブロックを即座に削除します。Vladislav のコードを次のように書いた方がよいかもしれません。
@echo off
if "%1"=="/p" (
goto :true
:true
echo "%1"
shift
echo shifted
echo "%1"
)
条件が FALSE の場合、ブロック全体がスキップされます。条件が TRUE の場合、GOTO はすぐにブロックを強制終了し、実行は :true ラベル (ブロック コンテキストなし) で正常に開始されます。最後のエクストラ)
は単純に無視されます。
この構文では ELSE を追加できないことに注意してください。以下では、望ましい結果が得られません。
@echo off
if "%1"=="/p" (
goto :true
:true
echo "%1"
shift
echo shifted
echo "%1"
) else (
echo This will execute regardless whether arg1 is /p or not
)
FALSE の場合、ELSE ブロックのみが実行されます。TRUE の場合、一番上のブロックが実行され、すぐに強制終了されます。コードの残りの部分が実行され、パーサーがコマンドを予期し、スタックにアクティブな括弧ブロックがない場合、REM として機能する) else (
ため、行は無視されます。)
上で示したように (または Vladislav が行ったように)、括弧で囲まれたコード ブロック内のラベルに GOTO しないことを強くお勧めします。
以下は、同じことを行うためのより良い (より単純で誤解を招かない) 方法です。
@echo off
if not "%1"=="/p" goto :skip
echo "%1"
shift
echo shifted
echo "%1"
:skip
追加のラベルと GOTO を使用して、IF/THEN/ELSE の概念をサポートできます。
@echo off
if not "%1"=="/p" goto :notP
echo "%1"
shift
echo shifted
echo "%1"
goto :endIf
:notP
echo not /p
:endIf