Quelle est la manière la plus simple de scripter de vérifier si une variable shell est exportée?

20

Pour certaines sessions shell, je veux pouvoir imprimer un indicateur d'avertissement si une variable shell n'est pas définie et exportée.

Il est assez simple de faire quelque chose comme ça pour imprimer "Erreur" dans l'invite si SET_MEest non défini ou nul.

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

Cependant, cela ne parvient pas à marquer si j'ai défini SET_MEsans l'exporter, ce qui est une erreur que je veux pouvoir détecter. À court de quelque chose comme $(bash -c 'test -z "$SET_ME" && echo Error;')ou de saluer la sortie de export, y a-t-il une simple vérification que je peux faire pour tester si elle SET_MEa été exportée?

Une solution non POSIX, bash uniquement est tout à fait acceptable.

CB Bailey
la source

Réponses:

11

Utilisez la declarecommande et l'opérateur de correspondance d'expressions régulières:

test_var () {
    # $1 - name of a shell variable
    var=$1
    [[ -z "${!var}" ]] && echo Error
    [[ $(declare -p $1)  =~ ^declare\ -[aAilrtu]*x[aAilrtu]*\  ]] || echo Error
}
chepner
la source
Je pense que c'est ce que je recherche. En théorie, le re pourrait devoir être plus flexible, par exemple si j'avais une variable exportée en lecture seule, mais en pratique je n'utilise jamais d'autres typesetattributs.
CB Bailey
Bon point. Je vais le réparer pour la postérité.
chepner le
Il semble que tenter de citer l'expression régulière l'empêche de fonctionner comme une expression régulière dans bash> = 3.2.
CB Bailey
Il y a aussi une incohérence, -z "$1"suppose que je passe la valeur d'une variable à test_var(comme je l'étais) alors qu'elle declare -pattend son nom. Je suis venu avec ce test qui prend le nom d'une variable de shell: test_exported_notnull () { re='^declare -\w*x'; [[ -n $(eval echo \$$1) ]] && [[ $(declare -p "$1") =~ $re ]]; }.
CB Bailey
Pour éviter cela eval, ajoutez simplement cette première ligne:, var=$1puis utilisez [[ -z "${!var}" ]] && echo Error.
chepner le
4

Je sais que la question a 3 ans, mais on peut trouver la solution suivante plus simple:

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

répond, si la variable est exportée et a une valeur non vide.

ArturFH
la source
4

Dans Bash 4.4 ou version ultérieure , vous pouvez utiliser l' ${parameter@a} expansion des paramètres du shell pour obtenir une liste des attributs d'un paramètre, y compris s'il est exporté.

Voici une fonction simple démontrant ${parameter@a}, qui vous dira si une variable donnée est exportée, compte tenu de son nom:

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

Exemple d'utilisation:

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

Comment ça fonctionne:

Le format renvoyé par ${parameter@a}est d'un caractère par attribut, avec la signification de chaque caractère d'attribut provenant des options correspondantes de la commande declare - dans ce cas, nous voulons rechercher x- exporté.

Robert Hencke
la source
Meilleure réponse si vous utilisez Bash 4.4 ou une version plus récente!
Andy
3

Vous pouvez utiliser compgenavec son -Xoption pour déterminer si une variable est exportée:

compgen -e -X "!$MAY_BE_EXPORTED_VARIABLE"

Par exemple:

$ NOT_EXPORTED="xxx"
$ compgen -e -X '!SHELL'
SHELL
$ compgen -e -X '!NOT_EXPORTED'
$ echo $?
1
Eric Pruitt
la source
Meilleure réponse compatible! Plus de deux fois plus lent que la solution $ {parameter @ a}, mais beaucoup plus compatible pour les cas bash 3.2
Andy
2

Si je me résigne à devoir utiliser exportet grep, le test le plus simple est probablement quelque chose comme ça.

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

ou si je veux aussi non nul:

export | grep -Eq '^declare -x SET_ME=".+"'
CB Bailey
la source
1
POSIX 7 indique que cela exportn'est pas spécifié et définit un format précis pour export -psimilaire à bash exportmais différent. Mais bash semble ignorer POSIX et utiliser le même format que exportpour export -p!
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件
1

La exportcommande, donnée sans paramètres, donne une liste des noms exportés dans l'environnement actuel:

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

Quelques coupures et sédiments se débarrassent des peluches:

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

Voici votre liste d'exportations, prête pour un traitement ultérieur.

DevSolar
la source
1
Cela fonctionne, mais j'espérais une réponse plus claire avec moins de fourches implicites (d'où "À court de [...] saluer la sortie de export") car mon utilisation prévue est dans mon invite.
CB Bailey
@CharlesBailey: Je vois. Je suis arrivé à cela en recherchant la page de manuel bash export, et c'est la seule chose que j'ai trouvée. Aucune aide du shell ne s'échappe non plus. Le exportest intégré de toute façon, mais je doute que vous puissiez éviter le grep.
DevSolar
1

La méthode la plus simple à laquelle je pense actuellement:

[ bash -c ': ${v1?}' 2>/dev/null ]
Dani
la source