Как проверить параметр командной строки в файле «.bat»?

104

Моя ОС - Windows Vista. Мне нужен файл «.bat», в котором мне нужно проверить, вводит ли пользователь какой-либо параметр командной строки или нет. Если да, то если параметр равен, -bто я что-то сделаю, в противном случае я отмечу «Недействительный ввод». Если пользователь не вводит никаких параметров командной строки, я что-то сделаю. Я создал следующий файл .bat. Он работает для случаев -bи не равнозначен -b- но не работает, когда пользователь не передает какой-либо параметр командной строки.

Я всегда получаю ошибку:

GOTO was unexpected at this time.

Может ли кто-нибудь сказать мне, что я здесь делаю не так?


ECHO OFF
CLS
ECHO.

IF [%1]==[/?] GOTO BLANK

IF %1=="-b" GOTO SPECIFIC

IF NOT %1=="-b" GOTO UNKNOWN

:SPECIFIC

ECHO SPECIFIC

GOTO DONE

:BLANK

ECHO No Parameter

GOTO DONE

:UNKNOWN

ECHO Unknown Option

GOTO DONE

:DONE

ECHO Done!
javauser71
источник
Если вы добавите скобки (например, в GOTO BLANKстроку) к двум другим IFоператорам, решит ли это проблему?
Джеремайя Уиллкок,

Ответы:

141

Вам нужно проверить, не заполнен ли параметр: if "%~1"=="" goto blank

Как только вы это сделаете, включите if / else -b: if "%~1"=="-b" (goto specific) else goto unknown

Заключение параметров в кавычки упрощает проверку таких вещей, как пустые / пустые / отсутствующие параметры. «~» гарантирует удаление двойных кавычек, если они были в аргументе командной строки.

истребитель
источник
Это работает!! Только "else" не принимается. Я получаю сообщение об ошибке: «else» не распознается как внутренняя или внешняя команда, работающая программа или командный файл. Поэтому я добавил еще один IF для случая «не равно -b». Спасибо за быстрый ответ.
javauser71
7
ELSE должен быть на той же строке, что и IF, или он должен быть сразу после скобки
jeb
4
Мне кажется, что это не работает, если% 1 содержит пробелы, что может иметь место, если это полный путь к исполняемому файлу. См . Ответ Джереми Уиллкока для решения, которое работает даже для параметров с пробелами в их значениях.
Марк А. Фитцджеральд
он не будет принят, если ваш аргумент - a File, в этом случае вы должны проверять только existили not exist. Вот почему ваши аргументы должны быть четко определены, или просто используйте powershell или vbScript (если вы находитесь в 80-х ...)
1
Это не для run.bat "a b". "%1"==""вылетает, если в аргументе есть пробел. См stackoverflow.com/a/46942471
wisbucky
27

Посмотрите http://ss64.com/nt/if.html для ответа; команда такая IF [%1]==[] GOTO NO_ARGUMENTили похожая.

Джеремайя Уиллкок
источник
1
Мало того, что это ТАКЖЕ работает! Он просто работает, в отличие от "%1"=="". Я должен уточнить это в своем собственном ответе.
Tomasz Gandor
1
это будет нарушено при цитировании% 1, например foo.bat "1st parameter" 2nd_param. См stackoverflow.com/questions/2541767/...
матовый Уилки
Использование [%1]==[-b]не будет соответствовать, если аргумент заключен в кавычки. Пример run.bat "-b". См stackoverflow.com/a/46942471
wisbucky
20

Короткий ответ - используйте квадратные скобки:

if [%1]==[] goto :blank

или (если вам нужно обработать аргументы в кавычках, см. Правка ниже):

if [%~1]==[] goto :blank

Зачем? вы можете спросить. Ну, как сказал Джереми Уиллкок: http://ss64.com/nt/if.html - они это используют! Хорошо, а что не так с цитатами?

И снова короткий ответ: они «волшебные» - иногда двойные (двойные) кавычки преобразуются в одинарные (двойные) кавычки. И для начала они должны совпадать.

Рассмотрим этот небольшой сценарий:

@rem argq.bat
@echo off

:loop 
if "%1"=="" goto :done
echo %1
shift
goto :loop

:done
echo Done.

Давайте протестируем это:

C:\> argq bla bla
bla
bla
Done.

Кажется, работает. А теперь перейдем на вторую передачу:

C:\> argq "bla bla"
bla""=="" was unexpected at this time.

Boom This не оценивается как истина, ни как не оценивается как ложь. Сценарий УМЕР. Если вы должны были выключить реактор где-нибудь в будущем, ну - не повезло. Теперь ты умрешь, как Гарри Даглиан.

Вы можете подумать - хорошо, аргументы не могут содержать кавычек. Если они это сделают, это произойдет. Неправильно Вот какое утешение:

C:\> argq ""bla bla""
""bla
bla""
Done.

О да. Не волнуйтесь - иногда это будет работать.

Попробуем другой сценарий:

@rem args.bat
@echo off

:loop 
if [%1]==[] goto :done
echo %1
shift
goto :loop

:done
echo Done.

Вы можете проверить себя, что он работает нормально для вышеуказанных случаев. Это логично - кавычки не имеют отношения к скобкам, так что никакой магии здесь нет. Но как насчет того, чтобы приправить аргументы скобками?

D:\>args ]bla bla[
]bla
bla[
Done.

D:\>args [bla bla]
[bla
bla]
Done.

Не повезло. Скобки просто не могут заглушить cmd.exeпарсер.

Вернемся на минутку к злым цитатам. Проблема была там, когда спор закончился цитатой:

D:\>argq "bla1 bla2"
bla2""=="" was unexpected at this time.

Что, если я пройду только:

D:\>argq bla2"
The syntax of the command is incorrect.

Скрипт вообще не запускается. То же самое для args.bat:

D:\>args bla2"
The syntax of the command is incorrect.

Но что я получаю, когда количество "-символов "совпадает" (то есть - четно), в таком случае:

D:\>args bla2" "bla3
bla2" "bla3
Done.

ПРИЯТНО - Надеюсь, вы узнали кое-что о том, как .batфайлы разделяют аргументы командной строки (ПОДСКАЗКА: * Это не совсем так, как в bash). Приведенный выше аргумент содержит пробел. Но кавычки не удаляются автоматически.

А argq? Как он на это реагирует? Как и ожидалось:

D:\>argq bla2" "bla3
"bla3"=="" was unexpected at this time.

Так что подумайте, прежде чем говорить: «Знаете что? Просто используйте кавычки. [Потому что, на мой взгляд, это выглядит лучше]».

редактировать

Недавно были комментарии по поводу этого ответа - ну, квадратные скобки «не могут обрабатывать» передачу цитируемых аргументов и обработку их так, как если бы они не цитировались.

Синтаксис:

if "%~1"=="" (...)

Это не недавно обнаруженное достоинство двойных кавычек, а отображение изящной функции удаления кавычек из переменной аргумента, если первый и последний символы являются двойными кавычками.

Эта «технология» работает и с квадратными скобками:

if [%~1]==[] (...)

Было полезно указать на это, поэтому я также поддержал новый ответ.

Наконец, любители двойных кавычек, ""существует ли в вашей книге аргумент такой формы или он пустой? Просто спрашиваю;)

Томаш Гандор
источник
1
Квадратные скобки [%1]==[-b]не подходят, если аргумент заключен в кавычки run.bat "-b". См stackoverflow.com/a/46942471
wisbucky
Историческое примечание: [%1]==[-b]и "%1"=="-b"были одинаковыми для сценариев пакетной обработки систем Win 98 и более ранних систем MS / PC-DOS. Поскольку в win 2000 / NT появился синтаксис, в if "%~1"=="-b"котором двойные кавычки имеют особое значение, именно так вы должны кодировать сценарии, поскольку он обеспечивает более надежную защиту. Двойные кавычки лишают смысла специальные символы (попробуйте & | и% chars в командной строке). 99,9% примеров работают с синтаксисом двойных кавычек - ваш пример argq bla2" "bla3является единственным случаем, чтобы оправдать квадратные скобки. Встроенные двойные кавычки - это рецепт катастрофы - просто скажи
Skip R
@SkipR - вот почему в файловых системах Windows вы не можете использовать эти специальные символы в именах. У меня нет математического доказательства, но я думаю, что просто НЕ все можно цитировать (в смысле - дословно с помощью некоторой escape-последовательности и т.д.) в cmdоболочке. В других системах вы можете иногда цитировать все, включая символ NUL. ( stackoverflow.com/questions/2730732/… ) - этот вопрос просто показывает, что вам нужно использовать какую-то внешнюю программу.
Томаш Гандор
8

В дополнение к другим ответам, на которые я подписываюсь, вы можете рассмотреть возможность использования /Iпереключателя IFкоманды.

... переключатель / I, если он указан, говорит о необходимости сравнения строк без учета регистра.

это может быть полезно, если вы хотите дать пользователям гибкость при указании параметров без учета регистра.

IF /I "%1"=="-b" GOTO SPECIFIC
PA.
источник
5

Вы сравниваете строки. Если аргументы опущены, %1расширяется до пустого значения, поэтому команды становятся, IF =="-b" GOTO SPECIFICнапример, (что является синтаксической ошибкой). Заключите строки в кавычки (или квадратные скобки).

REM this is ok
IF [%1]==[/?] GOTO BLANK

REM I'd recommend using quotes exclusively
IF "%1"=="-b" GOTO SPECIFIC

IF NOT "%1"=="-b" GOTO UNKNOWN
Джефф Меркадо
источник
ЕСЛИ [% 1] == [/?] Не работает, а я делаю IF [% 1] == [] или "% 1" == "", то это работает. В любом случае, теперь я могу идти. Спасибо за ваш быстрый ответ.
javauser71
5

Собственно, во всех остальных ответах есть недостатки. Самый надежный способ:

IF "%~1"=="-b" (GOTO SPECIFIC) ELSE (GOTO UNKNOWN)

Детальное объяснение:

Использование "%1"=="-b"приведет к сбою, если передать аргумент с пробелами и кавычками. Это наименее надежный метод.

IF "%1"=="-b" (GOTO SPECIFIC) ELSE (GOTO UNKNOWN)

C:\> run.bat "a b"

b""=="-b" was unexpected at this time.

Использование [%1]==[-b]лучше, потому что оно не приведет к сбою из-за пробелов и кавычек, но не будет соответствовать, если аргумент заключен в кавычки.

IF [%1]==[-b] (GOTO SPECIFIC) ELSE (GOTO UNKNOWN)

C:\> run.bat "-b"

(does not match, and jumps to UNKNOWN instead of SPECIFIC)

Использование "%~1"=="-b"- самое надежное. %~1удалит окружающие кавычки, если они существуют. Таким образом, он работает с кавычками и без них, а также без аргументов.

IF "%~1"=="-b" (GOTO SPECIFIC) ELSE (GOTO UNKNOWN)

C:\> run.bat
C:\> run.bat -b
C:\> run.bat "-b"
C:\> run.bat "a b"

(all of the above tests work correctly)
Wisbucky
источник
1
Понимаете, это не конец квадратных скобок: IF [%~1]==[]- это работает, и даже обрабатывает "-b". Вам просто нужно уметь мыслить внутри коробки, эээ… квадратных [скобок].
Томаш Гандор
3

В последнее время я боролся с реализацией сложных переключателей параметров в пакетном файле, поэтому вот результат моего исследования. Ни один из предоставленных ответов не является полностью безопасным, примеры:

"%1"=="-?" не будет соответствовать, если параметр заключен в кавычки (необходим для имен файлов и т. д.), или будет аварийно завершен, если параметр заключен в кавычки и имеет пробелы (снова часто встречается в именах файлов)

@ECHO OFF
SETLOCAL
echo.
echo starting parameter test...
echo.
rem echo First parameter is %1
if "%1"=="-?" (echo Condition is true, param=%1) else (echo Condition is false, param=%1)
C:\>test.bat -?

starting parameter test...

Condition is true, param=-?

C:\>test.bat "-?"

starting parameter test...

Condition is false, param="-?"

Любая комбинация с квадратными скобками [%1]==[-?]или [%~1]==[-?]не удастся, если в параметре есть пробелы в кавычках:

@ECHO OFF
SETLOCAL 
echo.
echo starting parameter test...
echo.
echo First parameter is %1
if [%~1]==[-?] (echo Condition is true, param=%1) else (echo Condition is false, param=%1)

C:\>test.bat "long file name"

starting parameter test...

First parameter is "long file name"
file was unexpected at this time.

Предлагаемое самое безопасное решение "%~1"=="-?"приведет к сбою со сложным параметром, который включает текст вне кавычек и текст с пробелами внутри кавычек:

@ECHO OFF
SETLOCAL 
echo.
echo starting parameter test...
echo.
echo First parameter is %1
if "%~1"=="-?" (echo Condition is true, param=%1) else (echo Condition is false, param=%1)

C:\>test.bat -source:"long file name"

starting parameter test...

First parameter is -source:"long file name"
file was unexpected at this time.

Единственный способ обеспечить охват всех вышеупомянутых сценариев - использовать EnableDelayedExpansion и передавать параметры по ссылке (а не по значению) с использованием переменных. Тогда даже самый сложный сценарий будет работать нормально:

@ECHO OFF
SETLOCAL EnableDelayedExpansion
echo.
echo starting parameter test...
echo.
echo First parameter is %1
:: we assign the parameter to a variable to pass by reference with delayed expansion
set "var1=%~1"
echo var1 is !var1!
:: we assign the value to compare with to a second variable to pass by reference with delayed expansion
set "var2=-source:"c:\app images"\image.png"
echo var2 is !var2!
if "!var1!"=="!var2!" (echo Condition is true, param=!var1!) else (echo Condition is false, param=!var1!)
C:\>test.bat -source:"c:\app images"\image.png

starting parameter test...

First parameter is -source:"c:\app images"\image.png
var1 is -source:"c:\app images"\image.png
var2 is -source:"c:\app images"\image.png
Condition is true, param=-source:"c:\app images"\image.png

C:\>test.bat -source:"c:\app images"\image1.png

starting parameter test...

First parameter is -source:"c:\app images"\image1.png
var1 is -source:"c:\app images"\image1.png
var2 is -source:"c:\app images"\image.png
Condition is false, param=-source:"c:\app images"\image1.png

C:\>test.bat -source:"c:\app images\image.png"

starting parameter test...

First parameter is -source:"c:\app images\image.png"
var1 is -source:"c:\app images\image.png"
var2 is -source:"c:\app images"\image.png
Condition is false, param=-source:"c:\app images\image.png"
Д. Барев
источник
0

В пакете Windows для этого есть ключевое слово DEFINED.

IF DEFINED %~1 foo
IF NOT DEFINED %~1 bar
Чарльз
источник
Спасибо, Дэвид. Я не знаю, почему не было возврата каретки и новой строки между IF и IF NOT. Я даже не заметил.
Чарльз