Який правильний спосіб перевірити, чи параметр порожній у пакетному файлі?


213

Мені потрібно перевірити, встановлена ​​чи ні змінна. Я спробував кілька прийомів, але вони, здається, не вдається, коли %1оточені цитатами, такими як випадок, коли %1є "c:\some path with spaces".

IF NOT %1 GOTO MyLabel // This is invalid syntax
IF "%1" == "" GOTO MyLabel // Works unless %1 has double quotes which fatally kills bat execution
IF %1 == GOTO MyLabel // Gives an unexpected GOTO error.

За даними цього сайту , це підтримувані IFтипи синтаксису. Отже, я не бачу способу це зробити.

IF [NOT] ERRORLEVEL number command
IF [NOT] string1==string2 command
IF [NOT] EXIST filename command

1
У моїх системах (Windows 2003, а також Windows 7) if "%1" == "" GOTO MyLabelне знищує фатально виконання сценарію до тих пір, поки %1має парне число подвійних лапок. Я бачу, що непарна кількість подвійних лапок %1вбиває виконання сценарію з цією помилкою: The syntax of the command is incorrect.Рішення нижче, яке використовує квадратні дужки для вирішення проблеми, було позначене як правильну відповідь, але це, здається, не робить нічого кращого . Це рішення також виходить з тієї ж помилки, коли %1має непарне число подвійних лапок.
Сусам Пал

@SusamPal Цікаво. Спробуйте версію дужок під нею і подивіться, чи працює вона. Та, яку я тестував більше. Я щойно оновив прийняту відповідь пару днів тому.
blak3r

Відповідь Dan Story, здається, справді працює добре. Я використовував версію за допомогою квадратних дужок.
Сусам Пал,

хороший приклад "зловити всіх": stackoverflow.com/questions/830565/…, що охоплює як аргумент файлу / каталогів, так і загальний рядок / числовий мікс в аргументі.

Так засмучує - IF DEFINED лише робота над змінними середовища замість змінних скриптів є такою тратою потенціалу!
kayleeFrye_onDeck

Відповіді:


290

Використовуйте квадратні дужки замість лапок:

IF [%1] == [] GOTO MyLabel

Дужки є безпечними : використовуйте лише квадратні дужки.


11
дужки не захищені! Вміст, як &у %1,
перерве

14
Використання інших символів, таких як if #%1#==##або if [%1]==[]добре, доки в аргументі немає пробілів, інакше ви отримаєте …was unexpected at this timeпомилку.
Synetech

12
І використання "%~1"- це дійсно кращий підхід, як я вже згадував у своїй відповіді.
jamesdlin

8
Хлопці, @jamesdlin вірно. Цей підхід не буде працювати, якщо текст змінної має пробіли або є ==. Використовуйте замість його відповідь.
Джеймс Ко

4
Ви цього не даєте зрозуміти it DOES NOT work with spaces. Використовуйте натомість відповідь @jamesdlin.
JB. З Монікою.

153

Ви можете використовувати:

IF "%~1" == "" GOTO MyLabel

зняти зовнішній набір лапок. Взагалі, це більш надійний метод, ніж використання квадратних дужок, оскільки він буде працювати, навіть якщо в змінній є пробіли.


9
Це дійсно хороший спосіб зробити це. Використовуючи ~, ви зніміть зовнішні лапки, якщо вони є, але потім додайте їх вручну (забезпечивши лише один набір). Більше того, ви повинні використовувати лапки, якщо аргумент містить пробіли (я дізнався це важким способом, коли моя попередня версія використання #або дужки замість лапок викликала аргументи з пробілами, щоб кинути …was unexpected at this timeпомилку.)
Synetech,

4
це також застосовується для загальних змінних, таких як% MYVAR%, а не аргументів типу% 1?
simpleuser

4
@simpleuser На жаль, ви неправі, він не працює із загальними змінними середовища.
jamesdlin

1
слідкуйте за рядками, які використовують подвійний "" "як послідовність втечі - скрипт завершиться збою при спробі порівняння. Наприклад, ""this string will crash the comparison""подвійний" "" - це правильна послідовність втечі, і заміна на подвійний "" "не вдасться, якщо рядок порожній.
Тидей

1
@Amalgovinus Ви, ймовірно, можете передати змінну як аргумент підпрограмі і дозволити підпрограмі використовувати "%~1".
jamesdlin

38

Одне з найкращих напіврозв’язків - скопіювати %1в змінну, а потім використовувати уповільнене розширення, як delaedExp. завжди безпечний від будь-якого вмісту.

set "param1=%~1"
setlocal EnableDelayedExpansion
if "!param1!"=="" ( echo it is empty )
rem ... or use the DEFINED keyword now
if defined param1 echo There is something

Перевагою цього є те, що поводження з param1 абсолютно безпечно.

І налаштування param1 спрацює у багатьох випадках, як

test.bat hello"this is"a"test
test.bat you^&me

Але це все ще не вдається з таким дивним вмістом, як

test.bat ^&"&

Вміти отримати 100% правильну відповідь на існування

Він визначає, чи %1порожній, але для деякого вмісту він не може отримати вміст.
Це також може бути корисним для розрізнення порожнього %1та одного з "".
Він використовує здатність CALLкоманди відмовитися, не перериваючи пакетний файл.

@echo off
setlocal EnableDelayedExpansion
set "arg1="
call set "arg1=%%1"

if defined arg1 goto :arg_exists

set "arg1=#"
call set "arg1=%%1"
if "!arg1!" EQU "#" (
    echo arg1 exists, but can't assigned to a variable
    REM Try to fetch it a second time without quotes
    (call set arg1=%%1)
    goto :arg_exists
)

echo arg1 is missing
exit /b

:arg_exists
echo arg1 exists, perhaps the content is '!arg1!'

Якщо ви хочете отримати 100% куленепробиву для отримання вмісту, ви можете прочитати Як отримати навіть найдивніші параметри командного рядка?


18

Від ІФ / ?:

Якщо ввімкнено розширення команд, якщо змінюються такі дії:

IF [/I] string1 compare-op string2 command
IF CMDEXTVERSION number command
IF DEFINED variable command

......

ВИЗНАЧЕННЯ умовна працює так само, як ІСНУЄТЬСЯ, за винятком того, що вона має назву змінної середовища та повертає істину, якщо визначена змінна середовище.


1
Так, я фактично спробував такий підхід, і з того, що я міг сказати, це працює лише зі змінними ЕКОЛОГІЧНОГО середовища. Тому не працював із% 1 або змінною, визначеною у пакетному файлі.
blak3r

2
Це справедливо лише для %1подібних. "Змінні, визначені у пакетному файлі" насправді є змінними середовища, коли працює пакетний файл, і ви можете використовувати IF DEFINEDїх.
zb226

8

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

Спочатку питання ОП зазначало "змінну", а не "параметр", що стало дуже заплутаним, тим більше, що це посилання номер один в google для пошуку тестування пустих змінних. З моєї оригінальної відповіді Стефан відредагував оригінальне запитання, щоб використовувати правильну термінологію, але замість того, щоб видалити свою відповідь, я вирішив залишити його, щоб допомогти усунути будь-яку плутанину, особливо у випадку, якщо Google все ще надсилає людей сюди також для змінних:

% 1 НЕ ЗМІН! Це КОМАНДАЛЬНИЙ ПАРАМЕТР.

Дуже важлива відмінність. Одиничний знак відсотка з цифрою після того, як він відноситься до параметра командного рядка, а не до змінної.

Змінні встановлюються за допомогою команди set і відкликаються за допомогою 2-відсоткових знаків - один до і один після. Наприклад,% myvar%

Для перевірки порожньої змінної ви використовуєте синтаксис "якщо не визначено" (команди, явно для змінних, не вимагають жодних знаків відсотків), наприклад:

set myvar1=foo  
if not defined myvar1 echo You won't see this because %myvar1% is defined.  
if not defined myvar2 echo You will see this because %myvar2% isn't defined.

(Якщо ви хочете перевірити параметри командного рядка, то рекомендую звернутися до відповіді jamesdlin.)


1
ти правий. Але правильний шлях був би просто виправити назву від if variable is emptyдо if parameter is empty. Я просто це зробив. (ризикуючи визнати недійсними деякі відповіді, які перевіряли змінні замість параметрів і так чи інакше є недійсними, оскільки вони не відповіли на запитання)
Stephan

1
Добре дякую Стефане, не зрозумів, що ти можеш це зробити. Я відредагував свою відповідь, щоб відобразити оновлення.
AutoMattTick

6

Використовуйте "IF DEFINED команда змінної" для тестування змінної у пакетному файлі.

Але якщо ви хочете перевірити параметри партії, спробуйте нижче коди, щоб уникнути хитромудрих даних (наприклад, "1 2" або ab ^> cd)

set tmp="%1"
if "%tmp:"=.%"==".." (
    echo empty
) else (
    echo not empty
)

5

Я тестую з кодом нижче, і це добре.

@echo off

set varEmpty=
if not "%varEmpty%"=="" (
    echo varEmpty is not empty
) else (
    echo varEmpty is empty
)
set varNotEmpty=hasValue
if not "%varNotEmpty%"=="" (
    echo varNotEmpty is not empty
) else (
    echo varNotEmpty is empty
)

Ваше рішення не працює, коли змінна містить лапки. До речі, синтаксис існує з IF DEFINED varпричини
jeb

4

Я зазвичай використовую це:

IF "%1."=="." GOTO MyLabel

Якщо% 1 порожній, IF порівнює ". до "." який оцінить до істини.


4
Це неправильно. Це те саме, що: ЯКЩО "% 1" == "" причиною цієї публікації було, якщо сам% 1 має лапки, це не вдалося.
blak3r

Ви намагаєтеся перевірити, чи% 1 порожній чи в ньому є лапки? Питання незрозуміле. Моя відповідь працює, якщо в командному рядку для% 1 нічого не вказано.
афорія

> Ви намагаєтеся перевірити, чи% 1 порожній чи в ньому є лапки? @aphoria, вона повинна вміти впоратися з обома.
Synetech

Я використовував це для розробки, якщо% 1% було встановлено, добре працювало для мене. Дякую, хороша відповідь!
Чарлі А

4

Я створив цей невеликий пакетний сценарій на основі відповідей тут, оскільки існує багато дійсних. Не соромтеся додавати до цього, якщо ви дотримуєтесь того самого формату:

REM Parameter-testing

Setlocal EnableDelayedExpansion EnableExtensions

IF NOT "%~1"=="" (echo Percent Tilde 1 failed with quotes) ELSE (echo SUCCESS)
IF NOT [%~1]==[] (echo Percent Tilde 1 failed with brackets) ELSE (echo SUCCESS)
IF NOT  "%1"=="" (echo Quotes one failed) ELSE (echo SUCCESS)
IF NOT [%1]==[] (echo Brackets one failed) ELSE (echo SUCCESS)
IF NOT "%1."=="." (echo Appended dot quotes one failed) ELSE (echo SUCCESS)
IF NOT [%1.]==[.] (echo Appended dot brackets one failed) ELSE (echo SUCCESS)

pause

4

Порожній рядок - це пара double-quotes/ "", ми можемо просто перевірити довжину:

set ARG=%1
if not defined ARG goto nomore

set CHAR=%ARG:~2,1%
if defined CHAR goto goon

потім протестуйте це 2 символи на double-quotes:

if ^%ARG:~1,1% == ^" if ^%ARG:~0,1% == ^" goto blank
::else
goto goon

Ось пакетний сценарій, з яким можна грати. Я думаю, що це належним чином вловлює порожню рядок.

Це лише приклад, вам просто потрібно налаштувати 2 (або 3?) Кроки вище, відповідно до вашого сценарію.

@echo off
if not "%OS%"=="Windows_NT" goto EOF
:: I guess we need enableExtensions, CMIIW
setLocal enableExtensions
set i=0
set script=%0

:LOOP
set /a i=%i%+1

set A1=%1
if not defined A1 goto nomore

:: Assumption:
:: Empty string is (exactly) a pair of double-quotes ("")

:: Step out if str length is more than 2
set C3=%A1:~2,1%
if defined C3 goto goon

:: Check the first and second char for double-quotes
:: Any characters will do fine since we test it *literally*
if ^%A1:~1,1% == ^" if ^%A1:~0,1% == ^" goto blank
goto goon

:goon
echo.args[%i%]: [%1]
shift
goto LOOP

:blank
echo.args[%i%]: [%1] is empty string
shift
goto LOOP

:nomore
echo.
echo.command line:
echo.%script% %*

:EOF

Цей результат випробування на катування:

.test.bat :: ""  ">"""bl" " "< "">"  (")(") "" :: ""-"  " "( )"">\>" ""
args[1]: [::]
args[2]: [""] is empty string
args[3]: [">"""bl" "]
args[4]: ["< "">"]
args[5]: [(")(")]
args[6]: [""] is empty string
args[7]: [::]
args[8]: [""-"  "]
args[9]: ["( )"">\>"]
args[10]: [""] is empty string

command line:
.test.bat :: ""  ">"""bl" " "< "">"  (")(") "" :: ""-"  " "( )"">\>" ""

Це неправильно, порожня рядок не є рядком з двома подвійними лапками "", порожня рядок - це порожня рядок ``, а в пакеті порожня змінна - невизначена змінна. Ви можете визначити, що для ваших аргументів зовнішні лапки будуть видалені, але тоді рядок все ще порожній довжиною 0
jeb

У цьому контексті (win cmd аргументи) ви не можете позначати порожній рядок будь-яким іншим способом, навіть не з подвійною одноцитатою, яка однаково порожня під оболонкою unix.
користувач6801759

Так, ""використовуються і для порожніх рядків, але це досить просто %~1для видалення зовнішніх лапок. не потрібно використовувати таке складне рішення
jeb

Ви маєте рацію, я можу неправильно зазначити, що це не лише для порожнього рядка, але й безпечного способу перерахування аргументів. Інші способи, такі як "%~1"==""не вдасться з аргументом, наприклад, "Long File Name".txtщо є коректним аргументом. редагувати : І це, безумовно, не складно, як ви сказали. Лише на 2 етапи вище для тестування, решта - багатослівний приклад.
user6801759

"якщо не визначено ARG", здається, працює чудово (моя змінна не надходить із командного рядка)
GrayFace

4

Можна використовувати

if defined (variable) echo That's defined!
if not defined (variable) echo Nope. Undefined.

1
Ласкаво просимо до SO! Ваша відповідь здається гарною відповіддю на питання. Як тільки у вас буде достатня [репутація] ( stackoverflow.com/help/whats-reputation ), ви зможете коментувати будь-яку публікацію. Перевірте також, що я можу зробити замість цього .
thewaywewere

3

Сценарій 1:

Input ("Видалити Quotes.cmd" "Це тест")

@ECHO OFF

REM Set "string" variable to "first" command line parameter
SET STRING=%1

REM Remove Quotes [Only Remove Quotes if NOT Null]
IF DEFINED STRING SET STRING=%STRING:"=%

REM IF %1 [or String] is NULL GOTO MyLabel
IF NOT DEFINED STRING GOTO MyLabel


REM   OR   IF "." equals "." GOTO MyLabel
IF "%STRING%." == "." GOTO MyLabel

REM GOTO End of File
GOTO :EOF

:MyLabel
ECHO Welcome!

PAUSE

Вихід (немає,% 1 НЕ було порожнім, порожнім або NULL):


Запустіть ("Видалити квоти.cmd") без будь-яких параметрів із вищевказаним сценарієм 1

Вихід (% 1 порожній, порожній або NULL):

Welcome!

Press any key to continue . . .

Примітка. Якщо ви встановите змінну всередині IF ( ) ELSE ( ) оператора, вона буде недоступною для DEFINED до того моменту, поки вона не закриє оператор "IF" (якщо не ввімкнено "Затримка змінного розширення"; після ввімкнення використовується знак оклику "!" Замість відсоток "%" символ}.

Наприклад:

Сценарій 2:

Input ("Видалити Quotes.cmd" "Це тест")

@ECHO OFF

SETLOCAL EnableDelayedExpansion

SET STRING=%0
IF 1==1 (
  SET STRING=%1
  ECHO String in IF Statement='%STRING%'
  ECHO String in IF Statement [delayed expansion]='!STRING!'
) 

ECHO String out of IF Statement='%STRING%'

REM Remove Quotes [Only Remove Quotes if NOT Null]
IF DEFINED STRING SET STRING=%STRING:"=%

ECHO String without Quotes=%STRING% 

REM IF %1 is NULL GOTO MyLabel
IF NOT DEFINED STRING GOTO MyLabel

REM GOTO End of File
GOTO :EOF

:MyLabel
ECHO Welcome!

ENDLOCAL
PAUSE

Вихід:

C:\Users\Test>"C:\Users\Test\Documents\Batch Files\Remove Quotes.cmd" "This is a Test"  
String in IF Statement='"C:\Users\Test\Documents\Batch Files\Remove Quotes.cmd"'  
String in IF Statement [delayed expansion]='"This is a Test"'  
String out of IF Statement='"This is a Test"'  
String without Quotes=This is a Test  

C:\Users\Test>  

Примітка. Це також видалить лапки з всередині рядка.

Наприклад (за допомогою сценарію 1 або 2): C: \ Users \ Test \ Documents \ Batch Files> "Remove Quotes.cmd" "Це" a "Test"

Вихід (сценарій 2):

String in IF Statement='"C:\Users\Test\Documents\Batch Files\Remove Quotes.cmd"'  
String in IF Statement [delayed expansion]='"This is "a" Test"'  
String out of IF Statement='"This is "a" Test"'  
String without Quotes=This is a Test  

Виконати ("Видалити Quotes.cmd") без будь-яких параметрів у Сценарії 2:

Вихід:

Welcome!

Press any key to continue . . .

3

Підводячи підсумки:

set str=%~1
if not defined str ( echo Empty string )

Цей код виведе "Порожній рядок", якщо% 1 є "" або "або порожнім. Додано його до прийнятої відповіді, яка наразі є невірною.


0

У мене було багато питань з великою кількістю відповідей в мережі. Більшість працює на більшість речей, але завжди є кутовий корпус, який порушує кожну.
Можливо, воно не працює, якщо у нього є цитати, можливо, воно порушується, якщо у нього немає лапок, синтаксична помилка, якщо у варі є пробіл, деякі працюватимуть лише на параметрах (на відміну від змінних оточуючих середовищ), інші методи дозволяють пустувати набір лапок, які пройдуть як "визначені", а деякі складніші не дозволять вам ланцюжокelse згодом .

Ось таке рішення, яким я задоволений, повідомте мене, якщо ви знайдете кутовий корпус, для якого він не буде працювати.

:ifSet
if "%~1"=="" (Exit /B 1) else (Exit /B 0)

Мати цю підпрограму або у вашому сценарії, або у власному .bat, має працювати.
Тож якщо ви хотіли написати (псевдо):

if (var)
then something
else somethingElse

Ви можете написати:

(Call :ifSet %var% && (
    Echo something
)) || (
    Echo something else
)

Він працював для всіх моїх тестів:

(Call :ifSet && ECHO y) || ECHO n
(Call :ifSet a && ECHO y) || ECHO n
(Call :ifSet "" && ECHO y) || ECHO n
(Call :ifSet "a" && ECHO y) || ECHO n
(Call :ifSet "a a" && ECHO y) || ECHO n

Echo'd n, y, n, y,y


Більше прикладів:

  • Хочете просто перевірити if?Call :ifSet %var% && Echo set
  • Тільки якщо ні (лише інше)? Call :ifSet %var% || Echo set
  • Перевірка пройденого аргументу; працює чудово.Call :ifSet %1 && Echo set
  • Не хотіли засмічувати ваші сценарії / код дупу, тому ви помістили його у свій власний ifSet.bat? Нема проблем:((Call ifSet.bat %var%) && Echo set) || (Echo not set)

Знайшов справу; Якщо ви спробуйте , якщо з ще синтаксисі, і остання команда в той блок виходить з ладу, то буде виконуватися: (Call ifSet.bat YES && (Echo true & Echo x | findstr y)) || Echo, вторить true і false
Hashbrown

Насправді, якщо це проблема, і ви можете мати справу з додатковою лінією, ви можете пом'якшити це, зателефонувавши ifSetсамостійно, використовуючиIf %errorlevel% EQU 0 (x) Else (y)
Hashbrown,

У яких випадках не працює прийнята відповідь (використовуйте квадратні дужки)? А ви можете пояснити, що робить Exit / B
blak3r

чомусь, коли я тестував, він зламався при використанні setзмінних (наприклад [%bob%], працює лише для аргументів на зразок [%2]), але тепер повторна перевірка працює. Я здогадуюсь, що зараз я можу лише []пропустити порожні котирування, тоді як це звичайно (так, це справді залежить від вашого використання)
Hashbrown,

/BПрапор зупиняє всю партію від виходу, тільки вихід з підпрограми або call«D партії. Якщо ви не запитаєте, що робить вся команда ; це повернення коду помилки, щоб викликати скрипт, що викликає, знати результат підпрограми ( 0пропустити, 1відмовити), застосований за допомогою булевої логіки у відповіді або через %errorlevel%вищезазначені коментарі
Hashbrown

0

Використовуючи! замість "для перевірки порожніх рядків

@echo off
SET a=
SET b=Hello
IF !%a%! == !! echo String a is empty
IF !%b%! == !! echo String b is empty

1
Наконечник справді поганий. Котирування можуть принаймні обробляти пробіли та спеціальні символи, але знаки оклику не можуть. І знаки оклику отримати дуже неприємний тут , коли відкладене розширення включено
Джеб

0

Я зайшов у вік трохи менше місяця (хоча це було запитано 8 років тому) ... Я сподіваюся, що він / він перейшов за межі пакетних файлів. ;-) Я раніше це робив. Я не впевнений, яка кінцева мета. Якщо він / він лінивий, як я, мій go.bat працює на такі речі. (Див. Нижче) Але, 1, команда в ОП може бути недійсною, якщо ви безпосередньо використовуєте вхід як команду. тобто

"C:/Users/Me"

є недійсною командою (або раніше, якщо ви були на іншому диску). Потрібно розбити його на дві частини.

C:
cd /Users/Me

І, 2, що означає "визначене" чи "невизначене"? GIGO. Я використовую за замовчуванням для введення помилок. Якщо вхід не потрапляє, він переходить до довідки (або команди за замовчуванням). Отже, жодне введення не є помилкою. Ви можете спробувати перейти на вхід і зрозуміти помилку, якщо така є. (Гаразд, за допомогою DOS завантаження (лише один батько) потрапляє в DOS. (Суворе!))

cd "%1"
if %errorlevel% neq 0 goto :error

І, 3, лапки потрібні лише навколо шляху, а не команди. тобто

"cd C:\Users" 

було погано (або звикли раніше), якщо ви не були на іншому приводі.

cd "\Users" 

є функціональним.

cd "\Users\Dr Whos infinite storage space"

працює, якщо у вас є пробіли на шляху.

@REM go.bat
@REM The @ sigh prevents echo on the current command
@REM The echo on/off turns on/off the echo command. Turn on for debugging
@REM You can't see this.
@echo off
if "help" == "%1" goto :help

if "c" == "%1" C:
if "c" == "%1" goto :done

if "d" == "%1" D:
if "d" == "%1" goto :done

if "home"=="%1" %homedrive%
if "home"=="%1" cd %homepath%
if "home"=="%1" if %errorlevel% neq 0 goto :error
if "home"=="%1" goto :done

if "docs" == "%1" goto :docs

@REM goto :help
echo Default command
cd %1
if %errorlevel% neq 0 goto :error
goto :done

:help
echo "Type go and a code for a location/directory
echo For example
echo go D
echo will change disks (D:)
echo go home
echo will change directories to the users home directory (%homepath%)
echo go pictures
echo will change directories to %homepath%\pictures
echo Notes
echo @ sigh prevents echo on the current command
echo The echo on/off turns on/off the echo command. Turn on for debugging
echo Paths (only) with folder names with spaces need to be inclosed in         quotes (not the ommand)
goto :done

:docs
echo executing "%homedrive%%homepath%\Documents"
%homedrive%
cd "%homepath%\Documents"\test error\
if %errorlevel% neq 0 goto :error
goto :done

:error
echo Error: Input (%1 %2 %3 %4 %5 %6 %7 %8 %9) or command is invalid
echo go help for help
goto :done

:done

є причина cd«S /dперемикач: cd /d "C:\Users\Me" (and the proper path delimeter for Windows is ` НЕ /).
Стефан
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.