goto ラベル (バッチファイル) について混乱しています Windows

goto ラベル (バッチファイル) について混乱しています Windows

これらのコマンドをこのように使用すると、期待どおりに動作します。

もしfoo だった以前に何らかの設定をした場合、foobar_menu

foo以前にない同じものとして設定すると、another_menu

rem Check if foo was previously set as bar1 or bar2...
if "%foo%"=="bar1" goto :foobar_menu
if "%foo%"=="bar2" goto :foobar_menu

rem Check if foo was NOT previously set as bar1 or bar2...
if not "%foo%"=="bar1" goto :another_menu
if not "%foo%"=="bar2" goto :another_menu

これが私を混乱させる理由です。以下に示すようにこれらを入れ替えると、正しく動作せず、間違ったラベルに移動しますが、なぜでしょうか?

rem Check if foo was NOT previously set as bar1 or bar2...
if not "%foo%"=="bar1" goto :another_menu
if not "%foo%"=="bar2" goto :another_menu

rem Check if foo was previously set as bar1 or bar2...
if "%foo%"=="bar1" goto :foobar_menu
if "%foo%"=="bar2" goto :foobar_menu

なぜこれら 2 つは同じことを行わないのでしょうか?

これは、goto 部分を括弧で囲んでいないためでしょうか?

私はこれを(最初の方法で)動作させていますが、これはメニューの順序と同じではありません。私は、すべてを上記の 2 番目の(動作しない)例のレイアウトどおりに実行させたいだけです。

乾杯。

編集:

choose_audio_sample_rateこれらは実際のコマンドです。このように記述すると、ネストされていても、変数の下に opus または libopus が設定されていても、ラベルに移動します。

if not "%audio_codec%"=="libopus" if not "%audio_codec%"=="opus" goto :choose_audio_sample_rate
if "%audio_codec%"=="libopus" if "%audio_codec%"=="opus" goto :choose_audio_sample_rate_opus

実際、スワップされたバージョンも機能せず、choose_audio_sample_rate変数の下に opus または libopus が設定されていても機能します。

if "%audio_codec%"=="libopus" if "%audio_codec%"=="opus" goto :choose_audio_sample_rate_opus
if not "%audio_codec%"=="libopus" if not "%audio_codec%"=="opus" goto :choose_audio_sample_rate

私はここで狂人になりつつあります(笑)、OK、これだけを使えばうまくいきます(そして非 Opus メニューに直接進みます):

if "%audio_codec%"=="libopus" (goto :choose_audio_sample_rate_opus)
if "%audio_codec%"=="opus" (goto :choose_audio_sample_rate_opus)

libopus の場合は、正しいラベルに移動します。libopus でない場合は、次の行が処理され、opus の場合は、正しいラベルに移動します。

それを過ぎると、libopus も opus もなくなり、一般メニューに進みます。

答え1

バッチ ファイルは上から下に実行されます。

2 番目の例では、 またはfoo2foo1設定されていても、常に に移動します:another_menu。バッチ ファイルがこれら 2 つのステートメントを通過できるのは、 とfoo1の両方foo2が設定されている場合のみです。

本質的には、論理 OR 状況を作り出していることになります。

foo1またはfoo2が設定されていない場合はanother_menuに進みます

それ以外

foo1またはfoo2が設定されている場合はfoobar_menuに移動します

それ以外

何もしない

最初の例では、

foo1またはfoo2が設定されている場合はfoobar_menuに移動します

それ以外

foo1またはfoo2が設定されていない場合はanother_menuに進みます

それ以外

何もしない

必要なのは、具体的には論理 AND です。バッチ ファイルの IF ステートメントは、AND も OR もサポートしていません。そのため、次のようにネストまたは連結します。

if not "%foo1%"=="bar1" if not "%foo2%"=="bar2" goto :another_menu

これは、foo1が設定されていない場合、foo2が設定されていない場合は:another_menuに移動します。

または、もっと簡単に言うと、foo1とfoo2が設定されていない場合は別のメニューに移動します

答え2

findstrを使用するとロジックを少し簡素化できます

 Echo("%foo%"|Findstr /C:"bar1" /C:"bar2" > nul && Goto :FooBarMenu || Goto :AnotherMenu

ロジック: Findstr は文字列%foo%を bar1 および bar2 と比較します。一致した場合、コマンドは正常に完了し、条件演算子は&&次のコマンドを実行します。一致しない場合は、||前のコマンドが正常に実行されなかったため、条件演算子がトリガーされ、次のコマンドが実行されます。

例:

@Echo off
 Set "foo=notbar"

:loop
 Echo("%foo%"|Findstr /C:"bar1" /C:"bar2" > nul ^
 && Call :fooBarMenu foobarMenu || Call :AnotherMenu Anothermenu
 If not defined foo Exit /B 0
Goto :loop

:foobarmenu
 Echo(@ %~1 foo = %foo%
 Set "foo="
Exit /B 0

:Anothermenu
 Echo(@ %~1 foo = %foo%
 Set "foo=bar2"
Exit /B 0

答え3

bar1とはすでにチェック済みです。したがって、 または でないかどうかbar2を再度チェックする必要はありません(コード フローがこの時点に到達したときには、すでに別の場所に分岐しているため、確実に ではありません)。bar1bar2

rem Check if foo was previously set as bar1 or bar2...
if "%foo%"=="bar1" goto :foobar_menu
if "%foo%"=="bar2" goto :foobar_menu
rem no need to check if foo was NOT previously set as bar1 or bar2
rem if FOO is anything other than the previously checked values, 
rem your code will continue here anyway.
echo FOO isn't bar1 or bar2.
rem Don't forget to end this branch of your code or it will just continue to run:
goto :eof
:foobar_menu
echo reached foobar.

大文字小文字を無視するに/iは、スイッチの使用を検討してください (is false、is true)if
if "foo"=="FOO"if /i "foo"=="FOO"

関連情報