Was ist die einfachste skriptfähige Methode, um zu überprüfen, ob eine Shell-Variable exportiert wird?

20

Für einige Shell-Sitzungen möchte ich in der Lage sein, ein Warnflag zu drucken, wenn eine Shell-Variable nicht gesetzt und exportiert wird.

Es ist ziemlich einfach, so etwas zu tun, um "Error" in der Eingabeaufforderung zu drucken, wenn "unset" SET_MEoder "null" ist.

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

Dieses Flag wird jedoch nicht angezeigt, wenn ich es SET_MEohne Export festgelegt habe. Dies ist ein Fehler, den ich erkennen möchte. Kurz etwas wie $(bash -c 'test -z "$SET_ME" && echo Error;')oder greppen die Ausgabe export, gibt es eine einfache Prüfung , dass ich zu Test tun kann , ob SET_MEexportiert worden ist ?

Eine reine Nicht-POSIX-Bash-Lösung ist völlig akzeptabel.

CB Bailey
quelle

Antworten:

11

Verwenden Sie den declareBefehl und den Übereinstimmungsoperator für reguläre Ausdrücke:

test_var () {
    # $1 - name of a shell variable
    var=$1
    [[ -z "${!var}" ]] && echo Error
    [[ $(declare -p $1)  =~ ^declare\ -[aAilrtu]*x[aAilrtu]*\  ]] || echo Error
}
chepner
quelle
Ich denke, das ist was ich suche. Theoretisch muss das re möglicherweise flexibler sein, z. B. wenn ich eine schreibgeschützte exportierte Variable hatte, aber in der Praxis verwende ich nie andere typesetAttribute.
CB Bailey
Guter Punkt. Ich werde es für die Nachwelt reparieren.
Chepner
Es sieht so aus, als würde der Versuch, den regulären Ausdruck in Anführungszeichen zu setzen, dazu führen, dass er in bash> = 3.2 nicht mehr als regulärer Ausdruck funktioniert.
CB Bailey
Es gibt auch eine Inkonsistenz, -z "$1"vorausgesetzt, ich übergebe den Wert einer Variablen an test_var(wie ich war), während declare -pder Name erwartet wird. Ich kam mit diesem Test auf , die den Namen eines Shell - Variable nimmt: test_exported_notnull () { re='^declare -\w*x'; [[ -n $(eval echo \$$1) ]] && [[ $(declare -p "$1") =~ $re ]]; }.
CB Bailey
Um dies zu vermeiden eval, fügen Sie einfach diese erste Zeile hinzu: var=$1und verwenden Sie dann [[ -z "${!var}" ]] && echo Error.
Chepner
4

Mir ist bewusst, dass die Frage 3 Jahre alt ist, jedoch kann man die folgende Lösung einfacher finden:

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

antwortet, wenn die Variable exportiert wird und einen nicht leeren Wert hat.

ArturFH
quelle
4

In Bash 4.4 oder höher können Sie die ${parameter@a} Shell-Parametererweiterung verwenden , um eine Liste der Attribute zu einem Parameter abzurufen, auch wenn dieser exportiert wird.

Hier ist eine einfache Funktion ${parameter@a}, die zeigt, ob eine bestimmte Variable mit ihrem Namen exportiert wird:

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

Anwendungsbeispiel:

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

Wie es funktioniert:

Das von zurückgegebene Format ${parameter@a}ist ein Zeichen pro Attribut, wobei die Bedeutung jedes Attributzeichens aus den entsprechenden Optionen des Befehls declare stammt. In diesem Fall möchten wir nach xexportiert suchen .

Robert Hencke
quelle
Beste Antwort, wenn Sie Bash 4.4 oder neuer verwenden!
Andy
3

Sie können mit compgenmit seiner -XOption , um zu bestimmen , ob eine Variable exportiert wird:

compgen -e -X "!$MAY_BE_EXPORTED_VARIABLE"

Z.B:

$ NOT_EXPORTED="xxx"
$ compgen -e -X '!SHELL'
SHELL
$ compgen -e -X '!NOT_EXPORTED'
$ echo $?
1
Eric Pruitt
quelle
Beste kompatible Antwort! Mehr als doppelt so langsam wie die $ {parameter @ a} -Lösung, aber weitaus besser für Bash 3.2-Fälle geeignet
Andy,
2

Wenn ich mich damit abfinde, exportund verwenden zu müssen grep, ist der einfachste Test wahrscheinlich so etwas.

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

oder wenn ich auch nicht null will:

export | grep -Eq '^declare -x SET_ME=".+"'
CB Bailey
quelle
1
POSIX 7 sagt, dass dies exportnicht spezifiziert ist, und definiert ein genaues Format für export -pähnlich wie Bash, exportaber anders. Aber bash scheint POSIX zu ignorieren und verwendet dasselbe Format wie exportfür export -p!
Ciro Santilli am
1

Der exportBefehl ohne Parameter gibt eine Liste der exportierten Namen in der aktuellen Umgebung an:

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

Beim Schneiden und Sedieren werden die Flusen entfernt:

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

Es gibt Ihre Exportliste, die zur weiteren Verarbeitung bereit ist.

DevSolar
quelle
1
Dies funktioniert, aber ich hatte auf eine leichtere Antwort mit weniger impliziten Gabeln gehofft (daher "zu wenig [...] Greifen der Ausgabe von export"), da meine geplante Verwendung in meiner Eingabeaufforderung liegt.
CB Bailey
@ Charles Bailey: Ich verstehe. Ich bin dazu gekommen, indem ich die Bash-Manpage nach durchsucht habe export, und dies war das einzige, was ich mir ausgedacht habe. Es kommt auch keine Hilfe aus der Shell heraus. Das exportist sowieso eingebaut, aber ich bezweifle, dass du das vermeiden kannst grep.
DevSolar
1

Die einfachste Methode, die mir derzeit einfällt:

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