Как проверить, установлена ли переменная в Bash?

Как узнать, установлена ли переменная в Bash?

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

function a {
    # if  is set ?
}

30 ответов


(обычно) правильный путь

if [ -z ${var+x} ]; then echo "var is unset"; else echo "var is set to '$var'"; fi

здесь ${var+x} это расширения параметр который ничего не оценивает, если var не установлен и заменяет строку x иначе.

Котировки Отступление

цитаты могут быть опущены (так что мы можем сказать ${var+x} вместо "${var+x}"), потому что этот синтаксис и использование гарантирует, что это будет расширяться только до того, что не требует кавычек (так как он либо расширяется до x (который содержит нет разрывов слов, поэтому ему не нужны кавычки), или ни к чему (что приводит к [ -z ], который удобно оценивает то же значение (true), что [ -z "" ] пока)).

однако, в то время как цитаты можно смело опустить, и это не было сразу очевидно для всех (это даже не было очевидно для первый автор этого цитаты объяснение который также является основным кодером Bash), иногда было бы лучше написать решение с кавычками как [ -z "${var+x}" ], на очень малом возможном стоимость штрафа за скорость O(1). Первый автор также добавил Это в качестве комментария рядом с кодом, используя это решение, давая URL-адрес этого ответа, который теперь также включает объяснение того, почему кавычки можно безопасно опустить.

(часто) неправильно

if [ -z "$var" ]; then echo "var is blank"; else echo "var is set to '$var'"; fi

это часто неправильно, потому что он не различает переменную, которая не установлена, и переменную, которая установлена в пустую строку. То есть, если var='', тогда вышеуказанное решение выведет наружу "VAR является пустым".

различие между unset и" set to the empty string " имеет важное значение в ситуациях, когда пользователь должен указать расширение или дополнительный список свойств, а не указывать их по умолчанию непустым значением, тогда как указание пустой строки должно заставить скрипт использовать пустое расширение или список дополнительных свойств.

различие не может быть существенным в каждом сценарии, хотя. В таких случаях [ -z "$var" ] будет просто штраф.


чтобы проверить ненулевую / ненулевую строковую переменную, т. е. если она установлена, используйте

if [ -n "" ]

наоборот -z. Я обнаружил, что использую -n больше, чем -z.


вот как проверить, является ли параметр unset или пусто ("Null") или задано значение:

+--------------------+----------------------+-----------------+-----------------+
|                    |       parameter      |     parameter   |    parameter    |
|                    |   Set and Not Null   |   Set But Null  |      Unset      |
+--------------------+----------------------+-----------------+-----------------+
| ${parameter:-word} | substitute parameter | substitute word | substitute word |
| ${parameter-word}  | substitute parameter | substitute null | substitute word |
| ${parameter:=word} | substitute parameter | assign word     | assign word     |
| ${parameter=word}  | substitute parameter | substitute null | assign word     |
| ${parameter:?word} | substitute parameter | error, exit     | error, exit     |
| ${parameter?word}  | substitute parameter | substitute null | error, exit     |
| ${parameter:+word} | substitute word      | substitute null | substitute null |
| ${parameter+word}  | substitute word      | substitute word | substitute null |
+--------------------+----------------------+-----------------+-----------------+

источник: POSIX: расширение параметров:

во всех случаях, показанных с помощью "substitute", выражение заменяется показанным значением. Во всех случаях, показанных с "assign", параметру присваивается то значение, которое также заменяет выражение.


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

if [ -z "" ]

это удается, если $1 равно null или unset


в то время как большинство методов, указанных здесь, являются правильными,Баш 4.2 поддерживает фактический тест на наличие переменной (man bash), а не тестирование значения переменной.

[[ -v foo ]]; echo $?
# 1

foo=bar
[[ -v foo ]]; echo $?
# 0

foo=""
[[ -v foo ]]; echo $?
# 0

чтобы увидеть, является ли переменная непустой, я использую

if [[ $var ]]; then ...       # `$var' expands to a nonempty string

противоположные тесты, Если переменная либо не установлена, либо пуста:

if [[ ! $var ]]; then ...     # `$var' expands to the empty string (set or not)

чтобы увидеть, установлена ли переменная (пустая или непустая), я использую

if [[ ${var+x} ]]; then ...   # `var' exists (empty or nonempty)
if [[ ${1+x} ]]; then ...     # Parameter 1 exists (empty or nonempty)

противоположные тесты, Если переменная не установлена:

if [[ ! ${var+x} ]]; then ... # `var' is not set at all
if [[ ! ${1+x} ]]; then ...   # We were called with no arguments

я всегда нахожу таблицу POSIX в другого ответа медленно grok, так что вот мой взгляд на это:

   +----------------------+------------+-----------------------+-----------------------+
   |   if VARIABLE is:    |    set     |         empty         |        unset          |
   +----------------------+------------+-----------------------+-----------------------+
 - |  ${VARIABLE-default} | $VARIABLE  |          ""           |       "default"       |
 = |  ${VARIABLE=default} | $VARIABLE  |          ""           | $(VARIABLE="default") |
 ? |  ${VARIABLE?default} | $VARIABLE  |          ""           |       exit 127        |
 + |  ${VARIABLE+default} | "default"  |       "default"       |          ""           |
   +----------------------+------------+-----------------------+-----------------------+
:- | ${VARIABLE:-default} | $VARIABLE  |       "default"       |       "default"       |
:= | ${VARIABLE:=default} | $VARIABLE  | $(VARIABLE="default") | $(VARIABLE="default") |
:? | ${VARIABLE:?default} | $VARIABLE  |       exit 127        |       exit 127        |
:+ | ${VARIABLE:+default} | "default"  |          ""           |          ""           |
   +----------------------+------------+-----------------------+-----------------------+

обратите внимание, что каждая группа (С и без предыдущего двоеточия) имеет то же самое set и unset случаи, поэтому единственное, что отличается, как пустой дела.

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

рубрики:

  • set означает VARIABLE-непустая (VARIABLE="something")
  • пустой означает VARIABLE пуст/null (VARIABLE="")
  • unset означает VARIABLE не существует (unset VARIABLE)

значения:

  • $VARIABLE означает, что результатом является исходное значение переменной.
  • "default" означает, что результатом была строка замены.
  • "" означает, что результат равен null (пустая строка).
  • exit 127 означает, что скрипт прекращает выполнение кода с выхода 127.
  • $(VARIABLE="default") означает, что результатом является исходное значение переменной и предоставленная строка замены назначается переменной для будущего использования.

на современной версии Bash (4.2 или позже, я думаю, я не знаю точно), я бы попробовал это:

if [ ! -v SOMEVARIABLE ] #note the lack of a $ sigil
then
    echo "Variable is unset"
elif [ -z "$SOMEVARIABLE" ]
then
    echo "Variable is set to an empty string"
else
    echo "Variable is set to some string"
fi

if [ "" != "" ]; then
  echo $1 is set
else
  echo $1 is not set
fi

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

if [ $# -gt 0 ]; then
  echo $1 is set
else
  echo $1 is not set
fi

прочитайте раздел "расширение параметров"bash man-страница. Расширение параметра не обеспечивает общий тест для устанавливаемой переменной, но есть несколько вещей, которые вы можете сделать с параметром, если он не установлен.

например:

function a {
    first_arg=${1-foo}
    # rest of the function
}

устанавливается first_arg равна если он назначен, в противном случае он использует значение "foo". Если a абсолютно должен принимать один параметр, и нет хорошего значения по умолчанию, вы можете выйти с сообщением об ошибке, когда нет параметр:

function a {
    : ${1?a must take a single argument}
    # rest of the function
}

(обратите внимание на использование : как команда null, которая просто расширяет значения своих аргументов. Мы не хотим ничего делать с в этом примере, просто покинуть, если он не установлен)


вы хотите выйти, если он не установлен

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

#!/usr/bin/env bash

set -o errexit

# Get the value and empty validation check all in one
VER="${1:?You must pass a version of the format 0.0.0 as the only argument}"

это возвращается с ошибкой при запуске

peek@peek:~$ ./setver.sh
./setver.sh: line 13: 1: You must pass a version of the format 0.0.0 as the only argument

только проверка, нет выхода-пусто и Unset недействительны

попробуйте эту опцию, если вы просто хотите проверить, если значение set=VALID или unset / empty=INVALID.

TSET="good val"
TEMPTY=""
unset TUNSET

if [ "${TSET:-}" ]; then echo "VALID"; else echo "INVALID";fi
# VALID
if [ "${TEMPTY:-}" ]; then echo "VALID"; else echo "INVALID";fi
# INVALID
if [ "${TUNSET:-}" ]; then echo "VALID"; else echo "INVALID";fi
# INVALID

или даже короткие тесты ;-)

[ "${TSET:-}"   ] && echo "VALID" || echo "INVALID"
[ "${TEMPTY:-}" ] && echo "VALID" || echo "INVALID"
[ "${TUNSET:-}" ] && echo "VALID" || echo "INVALID"

Проверьте только, нет выход-только пустой недопустим

и это ответ на вопрос. Используйте это, если вы просто хотите проверить, является ли значение set / empty=VALID или unset=INVALID.

Примечание, "1" в "..-1}" является незначительным, это может быть что угодно (например, х)

TSET="good val"
TEMPTY=""
unset TUNSET

if [ "${TSET+1}" ]; then echo "VALID"; else echo "INVALID";fi
# VALID
if [ "${TEMPTY+1}" ]; then echo "VALID"; else echo "INVALID";fi
# VALID
if [ "${TUNSET+1}" ]; then echo "VALID"; else echo "INVALID";fi
# INVALID

короткие тесты

[ "${TSET+1}"   ] && echo "VALID" || echo "INVALID"
[ "${TEMPTY+1}" ] && echo "VALID" || echo "INVALID"
[ "${TUNSET+1}" ] && echo "VALID" || echo "INVALID"

Я посвящаю этот ответ @mklement0 (комментарии), который бросил мне вызов, чтобы ответить на вопрос точно.

ссылка http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_02


чтобы проверить, установлена ли переменная с непустым значением, используйте [ -n "$x" ], Как уже указывали другие.

большую часть времени, это хорошая идея, чтобы обработать переменную, которая имеет пустое значение таким же образом, как переменная, которая не установлена. Но вы можете различить два, если вам нужно:[ -n "${x+set}" ] ("${x+set}" увеличивается до set Если x устанавливается и в пустую строку, если x не установлена).

чтобы проверить, был ли передан параметр, test $#, который количество параметров, переданных функции (или скрипту, если не в функции) (см. Павла).


в bash, вы можете использовать -v внутри [[ ]] builtin:

#! /bin/bash -u

if [[ ! -v SOMEVAR ]]; then
    SOMEVAR='hello'
fi

echo $SOMEVAR

для тех, кто ищет, чтобы проверить на unset или пустой когда в скрипте с set -u:

if [ -z "${var-}" ]; then
   echo "Must provide var environment variable. Exiting...."
   exit 1
fi

обычный [ -z "$var" ] проверка завершается с var; unbound variable Если set -u но [ -z "${var-}" ] расширяет очистить строку, если var не установлен без сбоев.


вы можете сделать:

function a {
        if [ ! -z "" ]; then
                echo ' is set'
        fi
}

ответы выше не работают, когда опция Bash это. Кроме того, они не являются динамическими, например, как тестировать переменную с именем "манекен" определяется? Попробуйте это:

is_var_defined()
{
    if [ $# -ne 1 ]
    then
        echo "Expected exactly one argument: variable name as string, e.g., 'my_var'"
        exit 1
    fi
    # Tricky.  Since Bash option 'set -u' may be enabled, we cannot directly test if a variable
    # is defined with this construct: [ ! -z "$var" ].  Instead, we must use default value
    # substitution with this construct: [ ! -z "${var:-}" ].  Normally, a default value follows the
    # operator ':-', but here we leave it blank for empty (null) string.  Finally, we need to
    # substitute the text from  as 'var'.  This is not allowed directly in Bash with this
    # construct: [ ! -z "${:-}" ].  We need to use indirection with eval operator.
    # Example: ="var"
    # Expansion for eval operator: "[ ! -z ${:-} ]" -> "[ ! -z ${var:-} ]"
    # Code  execute: [ ! -z ${var:-} ]
    eval "[ ! -z ${:-} ]"
    return $?  # Pedantic.
}

по теме: в Bash, как проверить, определена ли переменная в режиме" - u"


используя [[ -z "$var" ]] это самый простой способ узнать, была ли установлена переменная или нет, но эта опция -z не различает переменную unset и переменную, установленную в пустую строку:

$ set=''
$ [[ -z "$set" ]] && echo "Set" || echo "Unset" 
Unset
$ [[ -z "$unset" ]] && echo "Set" || echo "Unset"
Unset

лучше всего проверить его в соответствии с типом переменной: переменная env, параметр или регулярная переменная.

для переменной env:

[[ $(env | grep "varname=" | wc -l) -eq 1 ]] && echo "Set" || echo "Unset"

для параметра (например, проверить наличие параметра ):

[[ $# -ge 5 ]] && echo "Set" || echo "Unset"

для регулярная переменная (с помощью вспомогательной функции, чтобы сделать это элегантно):

function declare_var {
   declare -p "" &> /dev/null
   return $?
}
declare_var "var_name" && echo "Set" || echo "Unset"

Примечания:

  • $#: говорит вам количество позиционных параметров.
  • declare -p: дает определение переменной, переданной в качестве параметра. Если он существует, возвращает 0, если нет, возвращает 1 и печатает сообщение об ошибке.
  • $?: дает вам код статуса последняя выполненная команда.

в оболочке вы можете использовать -z оператор, который имеет значение True, если длина строки равна нулю.

простой однострочный установить по умолчанию MY_VAR если он не установлен, в противном случае вы можете отобразить сообщение:

[[ -z "$MY_VAR" ]] && MY_VAR="default"
[[ -z "$MY_VAR" ]] && MY_VAR="default" || echo "Variable already set."

мой предпочтительный способ это:

$var=10
$if ! ${var+false};then echo "is set";else echo "NOT set";fi
is set
$unset var
$if ! ${var+false};then echo "is set";else echo "NOT set";fi
NOT set

таким образом, в основном, если переменная установлена, она становится " отрицанием результирующего false" (что будет true = "is set").

и, если он не установлен, он станет "отрицанием результирующего true " (поскольку пустой результат оценивается в true) (так закончится как false = "Не задано").


if [[ ${1:+isset} ]]
then echo "It was set and not null." >&2
else echo "It was not set or it was null." >&2
fi

if [[ ${1+isset} ]]
then echo "It was set but might be null." >&2
else echo "It was was not set." >&2
fi

Я нашел (намного) лучше код для этого, если вы хотите проверить что-нибудь в $@.

if [[  = "" ]]
then
  echo ' is blank'
else
  echo ' is filled up'
fi

зачем это все? Все в $@ существует в Bash, но по умолчанию он пуст, поэтому test -z и test -n не смог помочь вам.

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

if [ ${#1} = 0 ]
then
  echo ' is blank'
else
  echo ' is filled up'
fi

[[ $foo ]]

или

(( ${#foo} ))

или

let ${#foo}

или

declare -p foo

if [[ ${!xx[@]} ]] ; then echo xx is defined; fi

Я всегда использую этот, основываясь на том, что его легко понять любому, кто видит код в первый раз:

if [ "$variable" = "" ]
    then
    echo "Variable X is empty"
fi

и, если хотите проверить, если не пусто;

if [ ! "$variable" = "" ]
    then
    echo "Variable X is not empty"
fi

вот именно.


это то, что я использую каждый день:

#
# Check if a variable is set
#   param1  name of the variable
#
function is_set()
{
    [[ -n "" ]] && test -n "$(eval "echo "${+x}"")"
}

это хорошо работает под Linux и Solaris вплоть до bash 3.0.

bash-3.00$ myvar="TEST"
bash-3.00$ is_set myvar ; echo $?
0
bash-3.00$ mavar=""
bash-3.00$ is_set myvar ; echo $?
0
bash-3.00$ unset myvar
bash-3.00$ is_set myvar ; echo $?
1

если var может быть массив, то [ -z "${var+x}" ] подстановка некорректна. Чтобы быть действительно уверены в Bash, вам нужно использовать синтаксис массива как [ "${#var[@]}" = 0 ], как показано ниже.

is-var-set () {
    results="${var+x}=${var+x}\t${#var[@]}=${#var[@]}"
    if [ -z "${var+x}" ] && [ "${#var[@]}" = 0 ]; then
        echo -e ": var's unset.\t$results"
    elif [ -n "${var+x}" ] && [ "${#var[@]}" != 0 ]; then
        echo -e ": var is set. \t$results"
    else
        echo -e ": Is var set? \t$results"
    fi
    unset var # so we don't have to do it everywhere else
}

практически во всех случаях, они согласны. Единственная ситуация, в которой метод array является более точным, - это когда переменная является непустым массивом с position 0 unset (например, в тестах 7 и A ниже). Это несогласие происходит от $var будучи стенографии для ${var[0]}, так что [ -z "${var+x}" ] не проверяет весь массив.

вот мои тестовые случаи.

unset var;      is-var-set 1 # var unset
var='';         is-var-set 2 # var[0] set to ''
var=foo;        is-var-set 3 # var[0] set to 'foo'
var=();         is-var-set 4 # var unset (all indices)
var=(foo);      is-var-set 5 # var[0] set to 'foo'
var=([0]=foo);  is-var-set 6 # var[0] set to 'foo'
var=([1]=foo);  is-var-set 7 # var[0] unset, but var[1] set to 'foo'
declare -a var; is-var-set 8 # var empty, but declared as an array
declare -A var; is-var-set 9 # var empty, but declared as an associative array
declare -A var  # Because is-var-set() conveniently unsets it
var=([xz]=foo); is-var-set A # var[xz] set to 'foo', but var's otherwise empty
declare -a var  # Demonstrate that Bash knows about var, even when there's
declare -A var; is-var-set B # apparently no way to just _check_ its existence

вот вывод.

1: var's unset. ${var+x}=       ${#var[@]}=0
2: var is set.  ${var+x}=x      ${#var[@]}=1
3: var is set.  ${var+x}=x      ${#var[@]}=1
4: var's unset. ${var+x}=       ${#var[@]}=0
5: var is set.  ${var+x}=x      ${#var[@]}=1
6: var is set.  ${var+x}=x      ${#var[@]}=1
7: Is var set?  ${var+x}=       ${#var[@]}=1
8: var's unset. ${var+x}=       ${#var[@]}=0
9: var's unset. ${var+x}=       ${#var[@]}=0
A: Is var set?  ${var+x}=       ${#var[@]}=1
./foo.sh: line 26: declare: var: cannot convert indexed to associative array
B: var's unset. ${var+x}=       ${#var[@]}=0

в сумме:

  • ${var+x} синтаксис расширения параметр работает так же хорошо, как ${#var[@]} синтаксис массива в большинстве случаев, например, проверка параметров на функции. Единственный способ сломать этот случай - если будущая версия Bash добавляет способ передачи массивов функциям без преобразования содержимого в индивидуальные аргументы.
  • синтаксис массива требуется для непустых массивов (ассоциативных или нет) с элементом 0 unset.
  • ни один синтаксис не объясняет, что происходит, если declare -a var используется без присвоения даже нулевого значения где-либо в массиве. Баш все еще различает случай где-то (как видно из теста B выше), поэтому этот ответ не верный. К счастью, Bash преобразует экспортированные переменные среды в строки при запуске программы / скрипта, поэтому любые проблемы с объявленными, но не заданными переменными будут содержаться в одном скрипте, по крайней мере, если это не поиск других скриптов.

Если вы хотите проверить, что переменная связана или несвязана, это работает хорошо, даже после того, как вы включили опцию nounset:

set -o noun set

if printenv variableName >/dev/null; then
    # variable is bound to a value
else
    # variable is unbound
fi

мне нравятся вспомогательные функции, чтобы скрыть грубые детали bash. В этом случае это добавляет еще больше (скрытой) грубости:

# The first ! negates the result (can't use -n to achieve this)
# the second ! expands the content of varname (can't do ${$varname})
function IsDeclared_Tricky
{
  local varname=""
  ! [ -z ${!varname+x} ]
}

поскольку у меня впервые были ошибки в этой реализации (вдохновленные ответами Йенса и Лайонела), я придумал другое решение:

# Ask for the properties of the variable - fails if not declared
function IsDeclared()
{
  declare -p  &>/dev/null
}

Я считаю, что это более прямолинейно, более застенчиво и легче понять/запомнить. Тестовый пример показывает, что он эквивалентен:

function main()
{
  declare -i xyz
  local foo
  local bar=
  local baz=''

  IsDeclared_Tricky xyz; echo "IsDeclared_Tricky xyz: $?"
  IsDeclared_Tricky foo; echo "IsDeclared_Tricky foo: $?"
  IsDeclared_Tricky bar; echo "IsDeclared_Tricky bar: $?"
  IsDeclared_Tricky baz; echo "IsDeclared_Tricky baz: $?"

  IsDeclared xyz; echo "IsDeclared xyz: $?"
  IsDeclared foo; echo "IsDeclared foo: $?"
  IsDeclared bar; echo "IsDeclared bar: $?"
  IsDeclared baz; echo "IsDeclared baz: $?"
}

main

тестовый пример также показывает, что local var тут не объявить var (если за ним не следует '='). Какое-то время мне казалось, что я объявляю переменные таким образом только для того, чтобы обнаружить, что я просто выражаю свое намерение... Думаю, это не операция.

IsDeclared_Tricky xyz: 1
IsDeclared_Tricky foo: 1
Isdeclared_tricky bar: 0
IsDeclared_Tricky baz: 0
IsDeclared xyz: 1
IsDeclared foo: 1
IsDeclared bar: 0
IsDeclared баз: 0

бонус: usecase

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

#auxiliary functions
function die()
{
  echo "Error: "; exit 1
}

function assertVariableDeclared()
{
  IsDeclared "" || die "variable not declared: "
}

function expectVariables()
{
  while (( $# > 0 )); do
    assertVariableDeclared ; shift
  done
}

# actual example
function exampleFunction()
{
  expectVariables inputStr outputStr
  outputStr="$inputStr world!"
}

function bonus()
{
  local inputStr='Hello'
  local outputStr= # remove this to trigger error
  exampleFunction
  echo $outputStr
}

bonus

если вызывается со всеми требуемыми переменными, объявленными:

Привет, мир!

другое:

ошибка: переменная не объявлена: outputStr


функции для проверки, объявлена ли переменная / unset

включая пустые $array=()


Следующие функции проверяют, существует ли данное имя в качестве переменной

# The first parameter needs to be the name of the variable to be checked.
# (See example below)

var_is_declared() {
    { [[ -n ${!1+anything} ]] || declare -p  &>/dev/null;}
}

var_is_unset() {
    { [[ -z ${!1+anything} ]] && ! declare -p  &>/dev/null;} 
}
  • при первом тестировании, если переменная (un)установлена, можно избежать вызова объявления, если это не необходимо.
  • Если же содержит имя пустого $array=(), вызов объявить будет убедиться, что мы получим право результат
  • в /dev/null никогда не передается много данных, поскольку declare вызывается только в том случае, если переменная не установлена или пустой массив.

эти функции будут тестироваться, как показано в следующих условиях:

a;       # is not declared
a=;      # is declared
a="foo"; # is declared
a=();    # is declared
a=("");  # is declared
unset a; # is not declared

a;       # is unset
a=;      # is not unset
a="foo"; # is not unset
a=();    # is not unset
a=("");  # is not unset
unset a; # is unset

.

дополнительные детали

и тестовый скрипт см. Мой ответ на вопрос " Как проверить, существует ли переменная в bash?".

замечание: подобное использование declare -p, как это также показано Peregring-ЛК ' s ответ, это действительно совпадение. Иначе я бы, конечно, поверил!


case "" in
 "") echo "blank";;
 *) echo "set"
esac