Як перевірити параметр командного рядка у файлі ".bat"?


103

Моя ОС - це 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!

Якщо ви додаєте дужки (як у GOTO BLANKрядку) до двох інших IFвисловлювань, чи це вирішує проблему?
Єремія Вілкок

Відповіді:


141

Потрібно перевірити, чи не пустий параметр: if "%~1"=="" goto blank

Після цього зробіть перемикач if / else на -b: if "%~1"=="-b" (goto specific) else goto unknown

Оточення параметрів лапками полегшує перевірку таких параметрів, як пусті / порожні / відсутні параметри. "~" гарантує, що подвійні лапки позбавлені, якщо вони були в аргументі командного рядка


Це працює !! Тільки "інше" не приймається. Я отримую помилку: 'else' не розпізнається як внутрішня чи зовнішня команда, функціонуюча програма чи пакетний файл. Тому я додав ще ІЧ для випадку "не рівний -b". Дякую за швидку відповідь.
javauser71

7
ELSE повинні знаходитись на тій же лінії, що і IF, або це має бути безпосередньо після дужки
jeb

4
Здається, це не працює для мене, якщо% 1 містить пробіли, що може бути випадком, якщо це повний шлях до виконуваного файлу. Дивіться відповідь Ієремії Вілкока щодо рішення, яке працює навіть для параметрів з пробілами у їх значеннях.
Марк А. Фіцджеральд

він не буде прийнятий, якщо ваш аргумент є 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"=="". Мені доводиться детальніше розглянути це у власній відповіді.
Томаш Гандор

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.

Бум Це не оцінювало як істинне, а також не оцінювало хибне. Сценарій DIED. Якщо ви повинні були вимкнути реактор десь вниз по лінії, добре - удача. Тепер ти помреш, як Гаррі Дагліан.

Ви можете подумати - Гаразд, аргументи не можуть містити лапок. Якщо вони це роблять, це відбувається. Неправильно Ось якесь втіху:

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.

NICE - Сподіваюся, ви дізналися щось про те, як.bat файли розділяють аргументи командного рядка (Підказка: * Це не зовсім так, як у bash). Вищенаведений аргумент містить пробіл. Але котирування не знімаються автоматично.

І argq? Як він реагує на це? Передбачувано:

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

Так що - подумайте, перш ніж сказати: "Знайте, що? Просто використовуйте цитати. [Тому що, на мене, це виглядає приємніше]".

Редагувати

Нещодавно з’явились коментарі щодо цієї відповіді - ну, дужки sqare "не можуть впоратися", передаючи цитовані аргументи і трактують їх так, як ніби їх не цитують.

Синтаксис:

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є лише виправданням квадратних дужок. Вбудовані подвійні цитати - це рецепт катастрофи - просто скажіть
Пропустіть R

@SkipR - саме тому у файлових системах Windows не можна мати цих спеціальних символів у іменах. У мене немає математичного підтвердження, але я думаю, що просто НЕ все може бути процитоване (в сенсі - зроблено дослівно через деяку послідовність втечі тощо) в cmdоболонці. В інших системах іноді можна цитувати все, включаючи символ NUL. ( stackoverflow.com/questions/2730732/… ) - це питання лише показує, вам потрібно скористатися деякою зовнішньою програмою.
Томаш Гандор

8

Окрім інших відповідей, які я підписав, ви можете розглянути можливість використання /Iперемикача IFкоманди.

... перемикач / я, якщо зазначено, каже, що "строка" нечутливого рядка порівнює.

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

IF /I "%1"=="-b" GOTO SPECIFIC

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)

1
Це не кінець квадратних дужок, ви бачите: IF [%~1]==[] - це працює, і він навіть справляється "-b". Вам просто потрібно вміти мислити всередині поля, erm, квадрата [дужки].
Томаш Гандор

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 має ключове слово ВИЗНАЧЕНО для цього.

IF DEFINED %~1 foo
IF NOT DEFINED %~1 bar

Дякую тобі, Девіде Я не знаю, чому не вдалося повернути вагон та нову лінію між IF та IF NOT. Я навіть не помітив.
Чарльз
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.