Какой самый простой способ сценариев проверить, экспортируется ли переменная оболочки?

20

Для некоторых сеансов оболочки я хочу иметь возможность печатать флаг предупреждения, если переменная оболочки не установлена ​​и не экспортирована.

Это довольно просто сделать что-то вроде этого, чтобы напечатать «Ошибка» в приглашении, если SET_MEне установлено или равно нулю.

test_var () { test -z "$1" && echo Error; }
PS1='$(test_var "$SET_ME") \$ '

Однако это не помечается, если я установил SET_MEбез экспорта, что является ошибкой, которую я хочу быть в состоянии обнаружить. Если не $(bash -c 'test -z "$SET_ME" && echo Error;')считать чего-то вроде или сгладить вывод export, есть ли простая проверка, которую я могу сделать, чтобы проверить, SET_MEбыл ли экспортирован?

Не POSIX, bash-only решение полностью приемлемо.

CB Bailey
источник

Ответы:

11

Используйте declareкоманду и оператор сопоставления регулярного выражения:

test_var () {
    # $1 - name of a shell variable
    var=$1
    [[ -z "${!var}" ]] && echo Error
    [[ $(declare -p $1)  =~ ^declare\ -[aAilrtu]*x[aAilrtu]*\  ]] || echo Error
}
chepner
источник
Я думаю, что это то, что я ищу. Теоретически, может потребоваться, чтобы re был более гибким, например, если бы у меня была экспортируемая переменная только для чтения, но на практике я никогда не использовал другие typesetатрибуты.
CB Bailey
Хорошая точка зрения. Я исправлю это для потомков.
Чепнер
Похоже, попытка заключить в кавычки регулярное выражение перестает работать как регулярное выражение в bash> = 3.2.
CB Bailey
Также есть несоответствие, -z "$1"предполагает, что я передаю значение переменной test_var(как я был), в то время как declare -pожидает ее имя. Я пришел с этим тестом , который принимает имя переменной оболочки: test_exported_notnull () { re='^declare -\w*x'; [[ -n $(eval echo \$$1) ]] && [[ $(declare -p "$1") =~ $re ]]; }.
CB Bailey
Чтобы избежать этого eval, просто добавьте эту первую строку:, var=$1затем используйте [[ -z "${!var}" ]] && echo Error.
Чепнер
4

Я знаю, что этому вопросу уже 3 года, но можно найти следующее решение проще:

[ "$(bash -c 'echo ${variable}')" ]

ответы, если переменная экспортирована и имеет непустое значение.

ArturFH
источник
4

В Bash 4.4 или более поздней версии вы можете использовать ${parameter@a} расширение параметра оболочки, чтобы получить список атрибутов о параметре, в том числе, если он экспортирован.

Вот простая функция, демонстрирующая ${parameter@a}, которая сообщит вам, экспортируется ли данная переменная, учитывая ее имя:

function is_exported {
    local name="$1"
    if [[ "${!name@a}" == *x* ]]; then
        echo "Yes - '$name' is exported."
    else
        echo "No - '$name' is not exported."
    fi
}

Пример использования:

$ is_exported PATH
Yes - 'PATH' is exported.
$ foo=1 is_exported foo
Yes - 'abc' is exported.
$ bar=1; is_exported bar
No - 'abc' is not exported.
$ export baz=1; is_exported baz
Yes - 'baz' is exported.
$ export -n baz; is_exported baz
No - 'baz' is not exported.
$ declare -x qux=3; is_exported qux
Yes - 'qux' is exported.

Как это устроено:

Формат, возвращаемый ${parameter@a}одним символом на атрибут, со значением каждого символа атрибута, полученным из соответствующих опций команды объявлений - в этом случае мы хотим искать x- экспортированный.

Роберт Хенке
источник
Лучший ответ, если вы используете Bash 4.4 или новее!
Энди
3

Вы можете использовать compgenс его -Xопцией, чтобы определить, экспортируется ли переменная:

compgen -e -X "!$MAY_BE_EXPORTED_VARIABLE"

Например:

$ NOT_EXPORTED="xxx"
$ compgen -e -X '!SHELL'
SHELL
$ compgen -e -X '!NOT_EXPORTED'
$ echo $?
1
Эрик Пруитт
источник
Лучший совместимый ответ! Более чем в два раза медленнее, чем решение $ {parameter @ a}, но гораздо более совместимо для случаев bash 3.2
Энди
2

Если я смиряюсь с необходимостью использовать exportи grep, возможно, самый простой тест будет примерно таким.

export | grep -Eq '^declare -x SET_ME='

или если я хочу также ненулевое значение:

export | grep -Eq '^declare -x SET_ME=".+"'
CB Bailey
источник
1
POSIX 7 говорит, что exportэто не определено, и определяет точный формат для export -pаналогичного bash, exportно различного. Но bash, похоже, игнорирует POSIX и использует тот же формат, что и exportдля export -p!
Сиро Сантилли 新疆 改造 中心 法轮功 六四 事件
1

Команда export, заданная без параметров, дает список экспортированных имен в текущей среде:

$ FOO1=test
$ FOO2=test
$ export | grep FOO
$ export FOO2
$ export | grep FOO
declare -x FOO2="test"

Некоторая стрижка и сединг избавляет от пуха:

export | cut -d' ' -f 3- | sed s/=.*//

Вот ваш список экспорта, готовый к дальнейшей переработке.

DevSolar
источник
1
Это действительно работает, но я надеялся на более легкий ответ с меньшим количеством подразумеваемых вилок (отсюда и «[...] не хватает результатов export»), поскольку мое запланированное использование находится в моем приглашении.
CB Bailey
@CharlesBailey: Понятно. Я пришел к этому, ища man-страницу bash export, и это было единственное, что я придумал. Никакая помощь из оболочки не ускользает. В exportлюбом случае встроенный, но я сомневаюсь, что вы можете избежать grep.
DevSolar
1

Самый простой метод, который я сейчас могу представить:

[ bash -c ': ${v1?}' 2>/dev/null ]
Дани
источник