it-swarm-es.tech

Cómo imprimir solo variables definidas (Shell y / o variables de entorno) en bash

El comando bash builtin set, si se invoca sin argumentos, imprimirá todas las variables de Shell y de entorno, pero también todas las funciones definidas. Esto hace que la salida sea inutilizable para humanos y difícil de grep.

¿Cómo puedo hacer que el comando bash builtin set imprima solo las variables y no las funciones?

¿Hay otros comandos que imprimen solo las variables de Shell, sin las funciones?

Nota: bash diferencia entre las variables de Shell y las variables de entorno. ver aquí Diferencia entre variables de entorno y variables de entorno exportadas en bash

59
lesmana

"¿Hay otros comandos que imprimen solo las variables de Shell, sin las funciones?"

En man bash, en la sección Shell BUILTIN COMMANDS (en la sección set) dice: "En modo posix, solo se enumeran las variables de Shell".

(set -o posix; set)

nota: () la sintaxis genera una subshell, si no te gusta bifurcar solo usa la versión más detallada

set -o posix; set; set +o posix
54
temp

Aquí hay algunas soluciones:

$ comm -3 <(declare | sort) <(declare -f | sort)

descompostura:

  1. declare imprime cada variable definida (exportada o no) y función.
  2. declare -f solo imprime funciones.
  3. comm -3 eliminará todas las líneas comunes a ambos. En efecto, esto eliminará las funciones, dejando solo las variables.

Para imprimir solo variables que no se exportan:

$ comm -3 <(comm -3 <(declare | sort) <(declare -f | sort)) <(env | sort)

Otra solución alternativa:

$ declare -p

Esto solo imprimirá las variables, pero con algunos atributos feos.

declare -- BASH="/bin/bash"
declare -ir BASHPID=""
declare -A BASH_ALIASES='()'
declare -a BASH_ARGC='()'
...

Puede cortar los atributos usando ... cortar:

$ declare -p | cut -d " " -f 3

Una desventaja es que el valor de IFS se interpreta en lugar de mostrarse.

comparar:

$ comm -3 <(declare | sort) <(declare -f | sort)
...
IFS=$' \t\n'
...
$ declare -p | cut -d " " -f 3
...
IFS="
"
...

Esto hace que sea bastante difícil usar esa salida para un procesamiento posterior, debido a que solo " en una línea. Quizás se pueda hacer algo de IFS-fu para evitar esto.


Otra solución alternativa, usando compgen:

$ compgen -v

El bash builtin compgen estaba destinado a ser utilizado en scripts de finalización. Para tal fin, compgen -v enumera todas las variables definidas. La desventaja: enumera solo los nombres de las variables, no los valores.

Aquí hay un truco para enumerar también los valores.

$ compgen -v | while read var; do printf "%s=%q\n" "$var" "${!var}"; done

La ventaja: es una solución pura de bash. La desventaja: algunos valores están en mal estado debido a la interpretación a través de printf. Además, la subshell de la tubería y/o el bucle agrega algunas variables adicionales.

32
lesmana

El typeset incorporado extrañamente tiene una opción para mostrar funciones solamente (-f) pero no para mostrar solo los parámetros. Afortunadamente, typeset (o set) muestra todos los parámetros antes de que todas las funciones, funciones y nombres de parámetros no puedan contener líneas nuevas o signos iguales, y las líneas nuevas en los valores de los parámetros se citan (aparecen como \n). Por lo tanto, puede detenerse en la primera línea que no contiene un signo igual:

set | awk -F '=' '! /^[0-9A-Z_a-z]+=/ {exit} {print $1}'

Esto solo imprime los nombres de los parámetros; si quieres los valores, cambia print $1 a print $0.

Tenga en cuenta que esto imprime todos los nombres de parámetros (los parámetros y las variables se usan como sinónimos aquí), no solo las variables de entorno ("variable de entorno" es sinónimo de "parámetros exportados").

Tenga en cuenta también que esto supone que no hay una variable de entorno con un nombre que no coincida con las restricciones de bash en los nombres de los parámetros. Dichas variables no se pueden crear dentro de bash, pero pueden haberse heredado del entorno cuando se inicia bash:

env 'foo ()
{
  =oops' bash

No estoy seguro de cómo se puede hacer que set imprima solo variables. Sin embargo, al observar la salida de set, pude llegar a lo siguiente que parece tomar solo variables:

$ set | grep "^\([[:alnum:]]\|[[:punct:]]\)\+=" 

Básicamente, estoy buscando líneas que comiencen con letras, números o signos de puntuación seguidos de un "=". De la salida que vi, esto toma todas las variables; Sin embargo, dudo que esto sea muy portátil.

Si, como sugiere su título, desea restar de esta lista las variables que se exportan y obtener así una lista de variables no exportadas, entonces podría hacer algo como esto

$ set | grep "^\([[:alnum:]]\|[[:punct:]]\)\+=" | sort > ./setvars && env | sort | comm -23 ./setvars - 

Para desglosar un poco, esto es lo que hace:

  1. set | grep "^\([[:alnum:]]\|[[:punct:]]\)\+=" | sort > ./setvars: Con suerte, obtiene todas las variables (como se discutió antes), las clasifica y pega el resultado en un archivo.
  2. && env | sort: Después de completar el comando anterior, vamos a llamar a env y ordenar su salida.
  3. | comm -23 ./setvars -: Finalmente, canalizamos la salida ordenada de env en comm y usamos la opción -23 Para imprimir las líneas que son exclusivas del primer argumento, en este caso las líneas exclusivas de nuestra salida del conjunto.

Cuando haya terminado, es posible que desee limpiar el archivo temporal que creó con el comando rm ./setvars

7
Steven D

Simplemente use el comando env. No imprime funciones.

6
unxnut

Prueba el comando printenv:

$printenv
2
Emilio R.

En bash, esto imprimirá solo nombres de variables:

compgen -v

O, si también se necesitan valores, use:

declare -p
1
Isaac

La respuesta aceptada es genial. Estoy ofreciendo una alternativa que no implica configurar el modo POSIX:

Aquí está la técnica que he estado usando para almacenar el estado de la función en un archivo para poder continuar más tarde. El primero produce un volcado de estado y el segundo produce solo una lista de los nombres de las variables.

set 2>/dev/null | while read a; do [[ $a == *=* ]] || break; echo $a; done 

set 2>/dev/null | while read a; do [[ $a == *=* ]] || break; echo ${a/=*}; done 

Ambos funcionan volcando líneas hasta encontrar uno sin un carácter '=', que ocurre cuando se enumera la primera función. Este último recorta la tarea.

0
Wil

diferenciarse de un Shell limpio para garantizar que también se omitan los vars de los scripts rc

## get mostly local vars
diff_env(){
    diff <(bash -cl 'set -o posix && set') \
        <(set -o posix && set && set +o posix) | \
        grep -E "^>|^\+" | \
        grep -Ev "^(>|\+|\+\+) ?(BASH|COLUMNS|LINES|HIST|PPID|SHLVL|PS(1|2)|Shell|FUNC)" | \
        sed -r 's/^> ?|^\+ ?//'
}

la versión con comm sería demasiado complicada

0
untore