Как правильно проверить, является ли параметр пустым в командном файле?

149

Мне нужно проверить, установлена ​​ли переменная или нет. Я пробовал несколько методов, но они, кажется, терпят неудачу, когда %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 имеет нечетное число двойных кавычек.
  • 0
    @SusamPal Интересно. Попробуйте версию в скобках под ним и посмотрите, работает ли это. Тот, который я проверял больше. Я только что обновил принятый ответ пару дней назад.
Показать ещё 3 комментария
Теги:
batch-file
cmd

16 ответов

227
Лучший ответ

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

IF [%1] == [] GOTO MyLabel

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

  • 9
    скобки не являются безопасными! Контент типа & в %1 нарушит черту
  • 10
    Использование других символов, например, if #%1#==## или if [%1]==[] хорошо, если в аргументе нет пробелов, в противном случае вы получите …was unexpected at this time ошибкой …was unexpected at this time .
Показать ещё 7 комментариев
95

Вы можете использовать:

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

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

  • 2
    +1 Я этого не пробовал. Но это здорово знать.
  • 8
    Это действительно хороший способ сделать это. Используя ~ , вы удаляете внешние кавычки, если они присутствуют, но затем добавляете их обратно вручную (обеспечивая только один набор). Более того, вы должны использовать кавычки, если аргумент содержит пробелы (я научился этому нелегко, когда моя предыдущая версия использования # или скобок вместо кавычек приводила к тому, что аргументы с пробелами для броска …was unexpected at this time ошибкой …was unexpected at this time .)
Показать ещё 4 комментария
27

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

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 "&"^&

Если вы хотите получить 99% доказательство пули, вы можете прочитать Как получить даже самые странные параметры командной строки?

14

От IF/?:

Если расширения команд включены, ЕСЛИ изменяется следующим образом:

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

......

Условные работы DEFINED как EXISTS, за исключением того, что требуется имя переменной среды и возвращает true, если переменная окружения определены.

  • 0
    Да, я на самом деле попробовал этот подход и из того, что я мог сказать, это работает только с переменными ОКРУЖАЮЩЕЙ СРЕДЫ. Поэтому не работал с% 1 или переменной, определенной внутри пакетного файла.
  • 1
    Это верно только для %1 и лайков. «Переменные, определенные внутри пакетного файла» на самом деле являются переменными среды во время работы пакетного файла, и вы можете использовать IF DEFINED для них.
4

Используйте команду "IF DEFINED variable" для проверки переменной в пакетном файле.

Но если вы хотите проверить параметры партии, попробуйте использовать коды ниже, чтобы избежать сложного ввода (например, "1 2" или ab ^ > cd)

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

Пустая строка - это пара 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

Вот пакет script, с которым вы можете играть. Я думаю, что он правильно ловит пустую строку.

Это просто пример, вам просто нужно настроить 2 (или 3?) шага выше в соответствии с вашим script.

@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
    Это неправильно, пустая строка не является строкой с двумя двойными кавычками "" пустая строка является пустой строкой ``, а в пакетном режиме пустая переменная является неопределенной переменной. Вы можете определить, что для ваших аргументов внешние кавычки будут удалены, но тогда строка все еще пуста с длиной 0
  • 0
    В этом контексте (аргументы win cmd) вы не можете обозначать пустую строку любым другим способом, даже с двойной одинарной кавычкой, которая одинаково пуста в оболочке unix.
Показать ещё 3 комментария
1

К сожалению, у меня недостаточно репутации для комментариев или голосования по текущим ответам, которые я должен был написать самостоятельно.

Первоначально в вопросе OP говорилось "переменная", а не "параметр", которая очень запуталась, тем более что это была ссылка номер один в google для поиска, как тестировать пустые переменные. Начиная с моего первоначального ответа, Stephan отредактировал исходный вопрос, чтобы использовать правильную терминологию, но вместо того, чтобы удалять мой ответ, я решил оставить его, чтобы помочь устранить любую путаницу, особенно в том случае, если google по-прежнему отправляет сюда и сюда переменные:

% 1 НЕ РАЗЛИЧНО! Это ПАРАМЕТР КОМАНДНОЙ ЛИНИИ.

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

Переменные задаются с помощью команды set и вызывается с использованием знаков 2 процента - один до и один за другим. Например,% myvar%

Чтобы проверить пустую переменную, вы используете синтаксис "if not defined" (явно для команд для переменных не требуются знаки процента), например:

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.)

  • 0
    вы правы. Но правильным способом было бы просто исправить заголовок, if variable is empty if parameter is empty . Я только что это сделал. (рискуя лишить законной силы некоторые ответы, которые проверяли переменные вместо параметров и поэтому в любом случае были недействительными, поскольку они не ответили на вопрос)
  • 0
    Хорошо, спасибо Стефан, не понимал, что ты можешь это сделать. Я отредактировал свой ответ, чтобы отразить обновление.
1

Подводя итог:

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

Этот код выведет "Пустую строку", если% 1 "или" или "Пусто". Добавил его к принятому ответу, который в настоящее время неверен.

1

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

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
1

Script 1:

Вход ( "Удалить 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):


Запустить ( "Удалить Quotes.cmd" ) без каких-либо параметров с указанным выше script 1

Выход (% 1 пуст, пуст или NULL):

Welcome!

Press any key to continue . . .

Примечание. Если вы установите переменную внутри оператора IF ( ) ELSE ( ), она не будет доступна для ОПРЕДЕЛЕНА до тех пор, пока она не выйдет из оператора "IF" (если не включена опция "Отсроченное расширение переменной", после включения используйте восклицательный знак "!" вместо символа процента "%" }.

Например:

Script 2:

Вход ( "Удалить 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>  

Примечание. Он также удалит кавы изнутри строки.

Пример (с использованием script 1 или 2):   C:\Users\Test\Documents\Batch Files > "Удалить Quotes.cmd" "Это" Тест "

Выход (Script 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" ) без каких-либо параметров в script 2:

Вывод:

Welcome!

Press any key to continue . . .
1

Я обычно использую это:

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

Если% 1 пуст, IF сравнивает ".". к "." который будет оцениваться как истинный.

  • 4
    Это неверно Это то же самое, что: ЕСЛИ "% 1" == "" причина этого сообщения была, если у самого% 1 есть кавычки, это терпит неудачу.
  • 0
    Вы пытаетесь проверить, является ли% 1 пустым или имеет кавычки? Вопрос неясен. Мой ответ работает, если в командной строке для% 1 ничего не указано.
Показать ещё 2 комментария
0

Я попал чуть меньше месяца (хотя это было спрошено 8 лет назад)... Надеюсь, он/она переместился за рамки пакетных файлов. ;-) Я делал это все время. Я не уверен, какова конечная цель. Если он ленив, как я, мой go.bat работает так. (См. Ниже) Но, 1, команда в OP может быть недействительной, если вы непосредственно используете ввод в качестве команды. т.е.

"C:/Users/Me"

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

C:
cd /Users/Me

И, 2, что означает "определенное" или "неопределенное"? GIGO. Я использую значение по умолчанию для обнаружения ошибок. Если вход не попадает, он падает, чтобы помочь (или по умолчанию). Таким образом, вход не является ошибкой. Вы можете попробовать cd на вход и поймать ошибку, если она есть. (Хорошо, используя go "загрузки (только один паз), пойман DOS. (Harsh!))

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
  • 0
    есть причина для cd «ы /d переключателя: cd /d "C:\Users\Me" (and the proper path delimeter for Windows is `, а не / ).
0

Я тестирую код ниже, и это нормально.

@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
)
  • 0
    Ваше решение терпит неудачу, когда переменная содержит кавычку. Кстати, существует синтаксис IF DEFINED var по причине
0

Вы можете использовать

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

Использование! вместо "для проверки пустой строки

@echo off
SET a=
SET b=Hello
IF !%a%! == !! echo String a is empty
IF !%b%! == !! echo String b is empty
  • 1
    Совет действительно плохой. Кавычки могут содержать как минимум пробелы и специальные символы, а восклицательные знаки - нет. И восклицательные знаки становятся очень неприятными, когда включено отложенное расширение
0

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

Вот решение, с которым я доволен, сообщите мне, если вы найдете угловой случай, в котором он не будет работать.

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

Если эта подпрограмма либо в вашем script, либо в ней собственном .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)
  • 0
    Нашел дело; Если вы попробуете синтаксис if с else, и последняя команда в блоке then завершится неудачно, else выполнится: (Call ifSet.bat YES && (Echo true & Echo x | findstr y)) || Echo , эхо true и false
  • 0
    На самом деле, если это проблема, и вы можете справиться с дополнительной строкой, вы можете смягчить ее, вызвав ifSet самостоятельно, а затем, используя If %errorlevel% EQU 0 (x) Else (y)
Показать ещё 3 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню