對 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

為什麼這兩件事做的不是同一件事?

這是因為我沒有將 goto 部分放在括號中嗎?

我確實讓它工作(第一種方式),但這與我的選單進入的順序不同,我只是希望它全部按照上面第二個(非工作)範例中的佈局方式運行。

乾杯。

編輯:

這些是實際的命令。以這種方式放置時,儘管是嵌套的,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

我在這裡變成了一個瘋子,哈哈,好吧,如果我只使用這個,它就會起作用(並直接進入非作品菜單):

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

您的批次文件從上到下執行。

在第二個範例中,即使設定了foo2or foo1,它也總是會轉到:another_menu。批次檔越過這兩個語句的唯一方法是同時設定foo1和。foo2

您本質上是在創建一個邏輯“或”情況。

如果 foo1 或 foo2 未設置,請前往 another_menu

別的

如果設定了 foo1 或 foo2 則到 foobar_menu

別的

沒做什麼

而第一個例子,

如果設定了 foo1 或 foo2 則到 foobar_menu

別的

如果 foo1 或 foo2 未設置,請前往 another_menu

別的

沒做什麼

您具體需要的是邏輯「與」。批次檔 IF 語句不支援 AND 或 OR。因此,我們將它們嵌套或連結起來,如下所示:

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

這表示,如果 foo1 未設置,則如果 foo2 未設置,請轉到 :another_menu

或者,更簡單的是,如果 foo1 和 foo2 未設置,請轉到 another_menu

答案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

您已經檢查過bar1bar2。因此,無需再次檢查它是否不是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開關 withif來忽略大小寫
if "foo"=="FOO"為 false,if /i "foo"=="FOO"為 true)

相關內容