Qual é a maneira mais simples de script para verificar se uma variável de shell é exportada?

20

Para algumas sessões de shell, desejo poder imprimir um sinalizador de aviso se uma variável de shell não for definida e exportada.

É bastante simples fazer algo assim para imprimir "Erro" no prompt, se SET_MEnão estiver definido ou nulo.

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

No entanto, isso falha ao sinalizar se eu definir SET_MEsem exportá-lo, o que é um erro que desejo detectar. $(bash -c 'test -z "$SET_ME" && echo Error;')Exceto por algo parecido ou com saudação na saída export, existe uma verificação simples que posso fazer para testar se SET_MEfoi exportada?

Uma solução não-POSIX, somente bash, é completamente aceitável.

CB Bailey
fonte

Respostas:

11

Use o declarecomando e o operador de correspondência de expressão regular:

test_var () {
    # $1 - name of a shell variable
    var=$1
    [[ -z "${!var}" ]] && echo Error
    [[ $(declare -p $1)  =~ ^declare\ -[aAilrtu]*x[aAilrtu]*\  ]] || echo Error
}
chepner
fonte
Eu acho que é isso que estou procurando. Em teoria, o re talvez precise ser mais flexível, por exemplo, se eu tivesse uma variável exportada somente leitura, mas na prática nunca uso outros typesetatributos.
perfil completo de CB Bailey
Bom ponto. Vou consertar para a posteridade.
18712 chepner
Parece que tentar citar a expressão regular impede que ela funcione como uma expressão regular em bash> = 3.2.
CB Bailey
Também há uma inconsistência, -z "$1"assume que eu estou passando o valor de uma variável para test_var(como eu estava) enquanto declare -pespera seu nome. Eu vim com este teste, que leva o nome de uma variável de shell: test_exported_notnull () { re='^declare -\w*x'; [[ -n $(eval echo \$$1) ]] && [[ $(declare -p "$1") =~ $re ]]; }.
perfil completo de CB Bailey
Para evitar isso eval, basta adicionar esta primeira linha: e var=$1, em seguida, use [[ -z "${!var}" ]] && echo Error.
Chepner
4

Sei que a pergunta tem 3 anos, no entanto, pode-se encontrar a seguinte solução mais simples:

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

respostas, se a variável for exportada e tiver um valor não vazio.

ArturFH
fonte
4

No Bash 4.4 ou posterior , você pode usar a ${parameter@a} expansão de parâmetros do shell para obter uma lista de atributos sobre um parâmetro, incluindo se ele é exportado.

Aqui está uma função simples demonstrativa ${parameter@a}, que informa se uma determinada variável é exportada, devido ao seu nome:

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

Exemplo de uso:

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

Como funciona:

O formato retornado por ${parameter@a}é um caractere por atributo, com o significado de cada caractere de atributo vindo das opções correspondentes do comando declare - neste caso, queremos procurar x- exportado.

Robert Hencke
fonte
Melhor resposta se você estiver usando o Bash 4.4 ou mais recente!
Andy
3

Você pode usar compgencom sua -Xopção para determinar se uma variável é exportada:

compgen -e -X "!$MAY_BE_EXPORTED_VARIABLE"

Por exemplo:

$ NOT_EXPORTED="xxx"
$ compgen -e -X '!SHELL'
SHELL
$ compgen -e -X '!NOT_EXPORTED'
$ echo $?
1
Eric Pruitt
fonte
Melhor resposta compatível! Mais do que duas vezes mais lento que a solução $ {parameter @ a}, mas muito mais compatível para casos do bash 3.2
Andy
2

Se eu me resignar a ter que usar exporte grep, o teste mais simples provavelmente será algo assim.

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

ou se eu quiser não nulo também:

export | grep -Eq '^declare -x SET_ME=".+"'
CB Bailey
fonte
11
O POSIX 7 diz que exportnão é especificado e define um formato preciso para export -psimilar ao bash, exportmas diferente. Mas o bash parece ignorar o POSIX e usa o mesmo formato que exportpara export -p!
Ciro Santilli # 16/14
1

O exportcomando, fornecido sem parâmetros, fornece uma lista de nomes exportados no ambiente atual:

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

Alguns cortes e sedações se livram do cotão:

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

Aqui está sua lista de exportações, pronta para processamento adicional.

DevSolar
fonte
11
Isso funciona, mas eu estava esperando uma resposta mais leve com menos garfos implícitos (portanto, "menos que [...] cumpra a saída de export"), pois meu uso planejado é rápido.
CB Bailey
@CharlesBailey: Entendo. Cheguei a isso pesquisando na página de manual do bash export, e essa foi a única coisa que me veio à cabeça. Nenhuma ajuda do shell também escapa. O exportestá embutido de qualquer maneira, mas duvido que você possa evitar o grep.
DevSolar
1

O método mais simples em que posso pensar atualmente:

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