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


214

Мне нужно проверить, установлена ​​ли переменная или нет. Я пробовал несколько методов, но они, кажется, терпят неудачу всякий раз, когда %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

Кажется, ответ Дана Стори действительно работает нормально. Я использовал версию, используя квадратные скобки.
Сусам Пал

хороший пример «поймать все»: stackoverflow.com/questions/830565/… охватывающий как файл / каталог, так и общее сочетание строк / чисел в аргументе.

Так расстраивает - IF DEFINEDтолько работа с переменными окружения вместо скриптовых переменных - такая трата потенциала!
kayleeFrye_onDeck

Ответы:


292

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

IF [%1] == [] GOTO MyLabel

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


11
скобки не являются безопасными! Контент вроде &in %1сломает черту
jeb

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

12
И использование "%~1"действительно лучший подход, как я уже упоминал в своем ответе.
Джеймсдлин

8
Ребята, @jamesdlin правильно. Этот подход не будет работать, если переменная text имеет пробелы или есть ==. Вместо этого используйте его ответ.
Джеймс Ко

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 Упс, вы правы, он не работает с общими переменными среды.
Джеймсдлин

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

1
@Amalgovinus Вы, вероятно, можете передать переменную в качестве аргумента подпрограмме и разрешить использование подпрограммы "%~1".
Джеймсдлин

38

Одним из лучших полу решений является копирование %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 ^&"&

Чтобы иметь возможность получить 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 / ?:

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

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

......

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


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. Я только что это сделал. (рискуя лишить законной силы некоторые ответы, которые проверяли переменные вместо параметров и поэтому в любом случае были недействительными, поскольку они не ответили на вопрос)
Стефан,

1
Хорошо, спасибо Стефан, не понимал, что ты можешь это сделать Я отредактировал свой ответ, чтобы отразить обновление.
AutoMattTick

6

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

Но если вы хотите проверить параметры пакета, попробуйте коды ниже, чтобы избежать хитрого ввода (например, «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по причине
Джеб

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

Да, ""они также используются для пустых строк, но их довольно просто %~1удалить из внешних кавычек. нет необходимости использовать такое сложное решение
Джеб

Вы правы, я мог бы неправильно заявить, это не только для пустой строки, но и для безопасного перечисления аргументов. Другие способы, такие как "%~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
Добро пожаловать на ТАК! Ваш ответ кажется хорошим ответом на вопрос. Когда у вас будет достаточно [репутации] ( stackoverflow.com/help/whats-reputation ), вы сможете комментировать любой пост. Также проверьте это, что я могу сделать вместо этого .
thewewewere

3

Сценарий 1:

Ввод («Удалить цитаты. 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 не был пустым, пустым или пустым):


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

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

Welcome!

Press any key to continue . . .

Примечание. Если вы установите переменную внутри IF ( ) ELSE ( )оператора, она не будет доступна для DEFINED до тех пор, пока она не выйдет из оператора «IF» (если только «Delayed Variable Expansion» не включен; после включения используйте восклицательный знак «!» Вместо символ процента "%"}.

Например:

Сценарий 2:

Ввод («Удалить цитаты. 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> "Удалить Quotes.cmd" "Это" a "Тест"

Вывод (сценарий 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]), но теперь перепроверка работает. Думаю, единственное, что мне []сейчас не нравится, это то, что он пропускает пустые кавычки, тогда как это не так (на самом деле это зависит от вашего
варианта

/BФлаг останавливает всю партию от выхода, только выход из подпрограммы или call«D партии. Если вы не спросите, что делает вся команда ; он возвращает код ошибки, чтобы позволить вызывающему сценарию узнать результат подпрограммы ( 0pass, 1fail), которую можно использовать с помощью логической логики в ответе или %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, команда в OP может быть недействительной, если вы непосредственно используете ввод как команду. т.е.

"C:/Users/Me"

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

C:
cd /Users/Me

И, 2, что означает «определенный» или «неопределенный»? GIGO. Я использую по умолчанию, чтобы ловить ошибки. Если ввод не перехватывается, он падает, чтобы помочь (или команда по умолчанию). Итак, без ввода не ошибка. Вы можете попробовать перейти на вход и поймать ошибку, если она есть. (Хорошо, использование загрузок go (только один пользователь) перехватывается 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.