Запутался в метке 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

Ваш пакетный файл выполняется сверху вниз.

Во втором примере, даже если установлено foo2или foo1, он всегда перейдет к :another_menu. Единственный способ, которым пакетный файл пройдет мимо этих двух операторов, — это если установлены оба foo1и .foo2

По сути, вы создаете ситуацию логического ИЛИ.

Если 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 не установлены, перейдите в 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

Вы уже проверили bar1и bar2. Поэтому нет необходимости проверять еще раз, НЕ является ли это bar1или bar2(это определенно не является таковым, когда поток кода достигает этой точки, потому что вы уже разветвились в другом месте, когда это произошло).

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переключателя с ifцелью игнорирования заглавных букв
( if "foo"=="FOO"is false, if /i "foo"=="FOO"is true)

Связанный контент