Как узнать, не определена ли строка в сценарии оболочки bash?

StackOverflow https://stackoverflow.com/questions/228544

Вопрос

Если я хочу проверить нулевую строку, я бы сделал

[ -z $mystr ]

но что, если я захочу проверить, определена ли вообще переменная?Или в сценариях bash нет различий?

Это было полезно?

Решение

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

if [ -z "${VAR+xxx}" ]; then echo VAR is not set at all; fi
if [ -z "$VAR" ] && [ "${VAR+xxx}" = "xxx" ]; then echo VAR is set but empty; fi

Вероятно, вы можете объединить два теста во второй строке в один с помощью:

if [ -z "$VAR" -a "${VAR+xxx}" = "xxx" ]; then echo VAR is set but empty; fi

Однако, если вы прочитаете документацию для Autoconf, вы обнаружите, что они не рекомендуют объединять термины с «-a» и рекомендуют использовать отдельные простые тесты в сочетании с &&. Я не сталкивался с системой, где есть проблема; это не значит, что они не существовали (но они, вероятно, чрезвычайно редки в наши дни, даже если они не были такими редкими в далеком прошлом).

Вы можете найти подробную информацию об этом и других связанных расширения параметров оболочки , test или < => команда и условные выражения в руководстве по Bash.

<Ч>

Меня недавно спросили по электронной почте об этом ответе с вопросом:

  

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

if [ -z "${VAR+xxx}" ]; then echo VAR is not set at all; fi
     

Разве это не достигнет того же самого?

if [ -z "${VAR}" ]; then echo VAR is not set at all; fi

Справедливый вопрос - ответ «Нет, ваша простая альтернатива не делает то же самое».

Предположим, я напишу это перед вашим тестом:

VAR=

Ваш тест скажет " VAR вообще не установлен " ;, но мой скажет (неявно, потому что он ничего не повторяет) " VAR установлен, но его значение может быть пустым & Quot ;. Попробуйте этот скрипт:

(
unset VAR
if [ -z "${VAR+xxx}" ]; then echo JL:1 VAR is not set at all; fi
if [ -z "${VAR}" ];     then echo MP:1 VAR is not set at all; fi
VAR=
if [ -z "${VAR+xxx}" ]; then echo JL:2 VAR is not set at all; fi
if [ -z "${VAR}" ];     then echo MP:2 VAR is not set at all; fi
)

Вывод:

JL:1 VAR is not set at all
MP:1 VAR is not set at all
MP:2 VAR is not set at all

Во второй паре тестов переменная установлена, но ей присвоено пустое значение. Это различие между нотациями [ и ${VAR=value}. То же самое для ${VAR:=value} и ${VAR-value}, а также ${VAR:-value} и ${VAR+value} и т. Д.

<Ч>

Как отметил Гили в своем ответ , если вы запускаете ${VAR:+value} с параметром bash, то приведенный выше базовый ответ завершается ошибкой с set -o nounset. Это легко исправить:

if [ -z "${VAR+xxx}" ]; then echo VAR is not set at all; fi
if [ -z "${VAR-}" ] && [ "${VAR+xxx}" = "xxx" ]; then echo VAR is set but empty; fi

Или вы можете отменить параметр unbound variable, указав set +u (set -u эквивалентно <=>).

Другие советы

~> if [ -z $FOO ]; then echo "EMPTY"; fi
EMPTY
~> FOO=""
~> if [ -z $FOO ]; then echo "EMPTY"; fi
EMPTY
~> FOO="a"
~> if [ -z $FOO ]; then echo "EMPTY"; fi
~> 

-z работает и для неопределенных переменных. Чтобы различать неопределенное и определенное, вы должны использовать перечисленные здесь здесь или с более понятными пояснениями. здесь .

Самый чистый способ - использовать расширение, как в этих примерах. Чтобы получить все ваши варианты, обратитесь к разделу «Расширение параметров» в руководстве.

Альтернативное слово:

~$ unset FOO
~$ if test ${FOO+defined}; then echo "DEFINED"; fi
~$ FOO=""
~$ if test ${FOO+defined}; then echo "DEFINED"; fi
DEFINED

Значение по умолчанию:

~$ FOO=""
~$ if test "${FOO-default value}" ; then echo "UNDEFINED"; fi
~$ unset FOO
~$ if test "${FOO-default value}" ; then echo "UNDEFINED"; fi
UNDEFINED

Конечно, вы бы использовали один из них по-другому, поместив желаемое значение вместо «значение по умолчанию» и используя расширение, если это необходимо.

Расширенное руководство по написанию сценариев bash, 10.2.Замена параметра:

  • ${вар+блабла}:Если вар определяется, «блахблах» заменяется выражением, иначе заменяется нуль
  • ${вар-блабла}:Если вар определен, он сам заменяется, иначе «блахблах» заменяется
  • ${вар?блабла}:Если VAR определяется, это заменяется, иначе функция существует с «блахблай» в качестве сообщения об ошибке.


Чтобы логика вашей программы основывалась на том, определена ли переменная $mystr или нет, вы можете сделать следующее:

isdefined=0
${mystr+ export isdefined=1}

теперь, если isdefined=0, то переменная не определена, если isdefined=1, то переменная определена

Этот способ проверки переменных лучше, чем приведенный выше ответ, потому что он более элегантен, удобочитаем, и если ваша оболочка bash настроена на ошибку при использовании неопределенных переменных. (set -u), сценарий завершится преждевременно.


Другие полезные вещи:

чтобы присвоить $mystr значение по умолчанию 7, если оно не определено, и оставить его нетронутым в противном случае:

mystr=${mystr- 7}

чтобы напечатать сообщение об ошибке и выйти из функции, если переменная не определена:

: ${mystr? not defined}

Имейте в виду, что я использовал ':', чтобы содержимое $mystr не выполнялось как команда в случае, если оно определено.

Сводка тестов.

[ -n "$var" ] && echo "var is set and not empty"
[ -z "$var" ] && echo "var is unset or empty"
[ "${var+x}" = "x" ] && echo "var is set"  # may or may not be empty
[ -n "${var+x}" ] && echo "var is set"  # may or may not be empty
[ -z "${var+x}" ] && echo "var is unset"
[ -z "${var-x}" ] && echo "var is set and empty"

https://stackoverflow.com/a/9824943/14731 содержит лучший ответ (более читаемый) и работает с включенным set -o nounset). Это работает примерно так:

if [ -n "${VAR-}" ]; then
    echo "VAR is set and is not empty"
elif [ "${VAR+DEFINED_BUT_EMPTY}" = "DEFINED_BUT_EMPTY" ]; then
    echo "VAR is set, but empty"
else
    echo "VAR is not set"
fi

Явным способом проверки определяемой переменной будет следующий:

[ -v mystr ]

другой вариант: список &; индексы массива " Расширение :

$ unset foo
$ foo=
$ echo ${!foo[*]}
0
$ foo=bar
$ echo ${!foo[*]}
0
$ foo=(bar baz)
$ echo ${!foo[*]}
0 1

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

$ unset foo
$ [[ ${!foo[*]} ]]; echo $?
1
$ foo=
$ [[ ${!foo[*]} ]]; echo $?
0
$ foo=bar
$ [[ ${!foo[*]} ]]; echo $?
0
$ foo=(bar baz)
$ [[ ${!foo[*]} ]]; echo $?
0

должен быть доступен в любой версии bash > = 3.0

не пролить этот байк еще дальше, но хотел добавить

shopt -s -o nounset

это то, что вы можете добавить в начало скрипта, что приведет к ошибке, если переменные не объявлены где-либо в скрипте. Вы увидите сообщение unbound variable, но, как отмечают другие, оно не будет перехватывать пустую строку или нулевое значение. Чтобы убедиться, что любое отдельное значение не пустое, мы можем проверить переменную, поскольку она раскрывается с помощью ${mystr:?}, также известного как расширение знака доллара, что приводит к ошибке с parameter null or not set.

Справочное руководство по Bash является официальным источником информации о bash.

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

if [ -z "$PS1" ]; then
        echo This shell is not interactive
else
        echo This shell is interactive
fi

(From раздел 6.3.2 .)

Обратите внимание, что пробел после открытия [ и до ] является не обязательным .

<Ч>

Советы для пользователей Vim

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

export VARIABLE_NAME="$SOME_OTHER_VARIABLE/path-part"

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

if [ -z "$VARIABLE_NAME" ]; then
        export VARIABLE_NAME="$SOME_OTHER_VARIABLE/path-part"
fi

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

s/\vexport ([A-Z_]+)\=("[^"]+")\n/if [ -z "$\1" ]; then\r  export \1=\2\rfi\r/gc

Это можно сделать, выбрав соответствующие строки визуально, а затем напечатав :. Панель команд заполняется :'<,'>. Вставьте указанную выше команду и нажмите Enter.

<Ч>

Проверено на этой версии Vim:

VIM - Vi IMproved 7.3 (2010 Aug 15, compiled Aug 22 2015 15:38:58)
Compiled by root@apple.com

Пользователям Windows могут потребоваться разные окончания строк.

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

var_defined() {
    local var_name=$1
    set | grep "^${var_name}=" 1>/dev/null
    return $?
}

Используйте его следующим образом:

if var_defined foo; then
    echo "foo is defined"
else
    echo "foo is not defined"
fi

вызов установлен без аргументов .. он выводит все определенные переменные ..
последними в списке будут те, которые определены в вашем скрипте ..
чтобы вы могли направить его вывод во что-то, что могло бы определить, какие вещи определены, а какие нет

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top