¿Cuál es la forma más simple de verificar si se exporta una variable de shell?

20

Para algunas sesiones de shell, quiero poder imprimir un indicador de advertencia si una variable de shell no está configurada y exportada.

Es bastante simple hacer algo como esto para imprimir "Error" en el mensaje si no SET_MEestá configurado o es nulo.

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

Sin embargo, esto no se marca si lo configuro SET_MEsin exportarlo, lo cual es un error que deseo poder detectar. A falta de algo parecido $(bash -c 'test -z "$SET_ME" && echo Error;')o grepping de la salida export, ¿hay una simple comprobación que pueda hacer para probar si SET_MEse ha exportado?

Una solución que no sea POSIX y solo bash es completamente aceptable.

CB Bailey
fuente

Respuestas:

11

Use el declarecomando y el operador de coincidencia de expresiones regulares:

test_var () {
    # $1 - name of a shell variable
    var=$1
    [[ -z "${!var}" ]] && echo Error
    [[ $(declare -p $1)  =~ ^declare\ -[aAilrtu]*x[aAilrtu]*\  ]] || echo Error
}
chepner
fuente
Creo que esto es lo que estoy buscando. En teoría, el re podría necesitar ser más flexible, por ejemplo, si tuviera una variable exportada de solo lectura, pero en la práctica nunca uso otros typesetatributos.
CB Bailey
Buen punto. Lo arreglaré para la posteridad.
chepner
Parece que intentar citar la expresión regular deja de funcionar como una expresión regular en bash> = 3.2.
CB Bailey
También hay una inconsistencia, -z "$1"supone que estoy pasando el valor de una variable a test_var(como era) mientras que declare -pespera su nombre. Se me ocurrió con esta prueba que toma el nombre de una variable del shell: test_exported_notnull () { re='^declare -\w*x'; [[ -n $(eval echo \$$1) ]] && [[ $(declare -p "$1") =~ $re ]]; }.
CB Bailey
Para evitarlo eval, simplemente agregue esta primera línea:, var=$1luego use [[ -z "${!var}" ]] && echo Error.
chepner
4

Sé que la pregunta tiene 3 años, sin embargo, uno puede encontrar la siguiente solución más simple:

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

respuestas, si la variable se exporta y tiene un valor no vacío.

ArturFH
fuente
4

En Bash 4.4 o posterior , puede usar la ${parameter@a} expansión de parámetros de shell para obtener una lista de atributos sobre un parámetro, incluso si se exporta.

Aquí hay una función simple que demuestra ${parameter@a}, que le dirá si se exporta una variable dada, dado su nombre:

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

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

Cómo funciona:

El formato devuelto por ${parameter@a}es un carácter por atributo, y el significado de cada carácter de atributo proviene de las opciones correspondientes del comando declarar (en este caso, queremos buscar x) exportado.

Robert Hencke
fuente
¡La mejor respuesta si está usando Bash 4.4 o más reciente!
Andy
3

Puede usar compgencon su -Xopción para determinar si se exporta una variable:

compgen -e -X "!$MAY_BE_EXPORTED_VARIABLE"

P.ej:

$ NOT_EXPORTED="xxx"
$ compgen -e -X '!SHELL'
SHELL
$ compgen -e -X '!NOT_EXPORTED'
$ echo $?
1
Eric Pruitt
fuente
¡La mejor respuesta compatible! Más del doble de lento que la solución $ {parameter @ a}, pero mucho más compatible para los casos de bash 3.2
Andy
2

Si me resigno a tener que usar exporty grep, la prueba más simple es probablemente algo como esto.

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

o si quiero no nulo también:

export | grep -Eq '^declare -x SET_ME=".+"'
CB Bailey
fuente
1
POSIX 7 dice que exportno está especificado, y define un formato preciso para export -psimilar a bash exportpero diferente. ¡Pero bash parece ignorar POSIX y usar el mismo formato que exportpara export -p!
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件
1

El exportcomando, dado sin parámetros, proporciona una lista de nombres exportados en el entorno actual:

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

Algunos cortes y sedimentos eliminan la pelusa:

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

Ahí está su lista de exportaciones, lista para su posterior procesamiento.

DevSolar
fuente
1
Esto funciona, pero esperaba una respuesta más clara con menos tenedores implícitos (por lo tanto, "corto de [...] agotar la salida de export") ya que mi uso planificado está en mi solicitud.
CB Bailey
@CharlesBailey: Ya veo. Llegué a esto buscando en la página de manual de bash export, y esto fue lo único que se me ocurrió. Tampoco se escapa la ayuda del shell. El exportestá incorporado de todos modos, pero dudo que puedas evitarlo grep.
DevSolar
1

El método más simple en el que actualmente puedo pensar:

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