Jaki jest najprostszy skryptowalny sposób sprawdzenia, czy zmienna powłoki jest eksportowana?


20

W przypadku niektórych sesji powłoki chcę mieć możliwość drukowania flagi ostrzeżenia, jeśli zmienna powłoki nie jest ustawiona i wyeksportowana.

Jest dość proste, aby zrobić coś takiego, aby wydrukować „Błąd” w monicie, jeśli SET_MEjest rozbrojony lub zerowy.

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

Jednak to nie oznacza flagi, jeśli ustawię SET_MEbez eksportowania, co jest błędem, który chcę wykryć. Czy brakuje czegoś takiego jak $(bash -c 'test -z "$SET_ME" && echo Error;')grepowanie export, czy jest prosty test, który mogę zrobić, aby sprawdzić, czy SET_MEzostał wyeksportowany?

Rozwiązanie nieobsługujące POSIX, tylko bash, jest całkowicie dopuszczalne.

Odpowiedzi:


11

Użyj declarepolecenia i operatora dopasowywania wyrażeń regularnych:

test_var () {
    # $1 - name of a shell variable
    var=$1
    [[ -z "${!var}" ]] && echo Error
    [[ $(declare -p $1)  =~ ^declare\ -[aAilrtu]*x[aAilrtu]*\  ]] || echo Error
}

Myślę, że tego właśnie szukam. Teoretycznie re może być bardziej elastyczne, np. Gdybym miał wyeksportowaną zmienną tylko do odczytu, ale w praktyce nigdy nie używam innych typesetatrybutów.
CB Bailey,

Słuszna uwaga. Naprawię to dla potomności.
chepner

Wygląda na to, że próba cytowania wyrażenia regularnego przestaje działać jako wyrażenie regularne w bash> = 3.2.
CB Bailey,

Jest też niespójność, -z "$1"zakładam, że przekazuję wartość zmiennej do test_var(tak jak byłem), podczas gdy declare -poczekuje jej nazwy. Wpadłem na ten test, który przybiera nazwę zmiennej powłoki: test_exported_notnull () { re='^declare -\w*x'; [[ -n $(eval echo \$$1) ]] && [[ $(declare -p "$1") =~ $re ]]; }.
CB Bailey,

Aby tego uniknąć eval, po prostu dodaj ten pierwszy wiersz:, var=$1a następnie użyj [[ -z "${!var}" ]] && echo Error.
chepner

4

Wiem, że pytanie ma 3 lata, jednak poniższe rozwiązanie może być prostsze:

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

odpowiada, jeśli zmienna jest eksportowana i ma niepustą wartość.


4

W wersji Bash 4.4 lub nowszej możesz użyć ${parameter@a} rozszerzenia parametrów powłoki, aby uzyskać listę atrybutów dotyczących parametru, w tym jeśli jest on eksportowany.

Oto prosta funkcja pokazująca ${parameter@a}, czy dana zmienna jest eksportowana, biorąc pod uwagę jej nazwę:

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

Przykład zastosowania:

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

Jak to działa:

Format zwracany przez ${parameter@a}to jeden znak na atrybut, przy czym znaczenie każdego znaku atrybutu pochodzi z odpowiednich opcji polecenia deklaracji - w tym przypadku chcemy szukać x- eksportowane.


Najlepsza odpowiedź, jeśli używasz Bash 4.4 lub nowszej!
Andy

3

Możesz użyć compgentej -Xopcji, aby określić, czy zmienna jest eksportowana:

compgen -e -X "!$MAY_BE_EXPORTED_VARIABLE"

Na przykład:

$ NOT_EXPORTED="xxx"
$ compgen -e -X '!SHELL'
SHELL
$ compgen -e -X '!NOT_EXPORTED'
$ echo $?
1

Najlepsza kompatybilna odpowiedź! Ponad dwa razy wolniejszy niż rozwiązanie $ {parametr @ a}, ale o wiele bardziej kompatybilny dla przypadków bash 3.2
Andy

2

Jeśli zrezygnuję z konieczności używania exporti grep, najprostszy test jest prawdopodobnie taki.

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

lub jeśli chcę również wartość inną niż null:

export | grep -Eq '^declare -x SET_ME=".+"'

1
POSIX 7 mówi, że exportjest nieokreślony i definiuje dokładny format export -ppodobny do bash, exportale inny. Ale bash wydaje się ignorować POSIX i używać tego samego formatu co exportdla export -p!
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件

1

exportPolecenia podane bez parametrów, podaje listę eksportowanych nazwisk w obecnej sytuacji:

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

Trochę cięcia i sedingu pozbywa się puchu:

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

Twoja lista eksportów jest gotowa do dalszego przetwarzania.


1
To działa, ale miałem nadzieję na lżejszą odpowiedź przy mniejszej liczbie dorozumianych widelców (stąd „Brak [...] grepowania wyniku export”), ponieważ moje planowane użycie jest w mojej linii.
CB Bailey,

@CharlesBailey: Rozumiem. Doszedłem do tego, przeszukując stronę bash export, i to była jedyna rzecz, jaką wymyśliłem. Nie ucieka też żadna pomoc ze strony powłoki. W exportkażdym razie jest wbudowany, ale wątpię, czy można tego uniknąć grep.
DevSolar,

1

Najprostsza metoda, jaką obecnie mogę wymyślić:

[ bash -c ': ${v1?}' 2>/dev/null ]
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.