shell posix: imprime la lista de nombres de variables de entorno (sin valores)

11

De una manera compatible con posix que funciona con múltiples implementaciones, ¿cómo puedo imprimir la lista de variables de entorno definidas actualmente sin sus valores?

En algunas implementaciones (mksh, freebsd / bin / sh), solo usarlo exportpor sí solo se ajustará a la factura:

$ export
FOO2
FOO

Pero para algunas otras implementaciones (bash, zsh, dash), exporttambién muestra el valor. Con bash, por ejemplo:

$ export
export FOO2='as  df\
  asdk=fja:\
asd=fa\
asdf'
export FOO='sjfkasjfd  kjasdf:\
   asdkj=fkajdsf:\
       :askjfkajsf=asdfkj:\
   safdkj'
$ printenv | sed -n l
FOO2=as\tdf\$
  asdk=fja:\$
asd=fa\$
asdf$
FOO=sjfkasjfd  kjasdf:\$
   asdkj=fkajdsf:\$
\t:askjfkajsf=asdfkj:\$
   safdkj$

Otras opciones como envo printenvno tienen opciones para imprimir solo los nombres de las variables sin valores, al menos no en las plataformas Linux y Freebsd que he probado.

Tuberías a awk / sed / etc. o recortar la lista con técnicas de expansión de parámetros (por ejemplo, ${foo%%=*}) es aceptable, pero tiene que funcionar con valores que pueden abarcar líneas y tener un =espacio en blanco en el valor (ver el ejemplo anterior).

Las respuestas específicas a implementaciones de shell particulares son interesantes, pero principalmente estoy buscando algo que sea compatible entre implementaciones.

Juan
fuente
2
Si va a analizar algo, vaya con la salida export -pespecificada por POSIX para generar una salida que también sea adecuada para la entrada en el shell.
Kusalananda
No necesito nada para ingresar a un shell. Solo quiero los nombres de las variables de entorno. Por lo tanto, el cruft extra (p. Ej., La palabra 'exportar' al frente de cada línea) simplemente debería eliminarse de todos modos. ¿Por qué querría usar export -ppara esto?
Juan
1
Desearía usarlo export -pporque eso le daría una salida consistente en todos los shells POSIX, que dijo que quería.
Kusalananda
Quiero una solución que imprima solo los nombres de las variables que sea una solución consistente en todos los shells. export -pno se ajusta al primer requisito: imprimir solo nombres de variables sin valores.
Juan
Si vas a analizar algo, ve con la salida de export -p. No voy a escribir ese análisis, porque en el caso general, también tendría que hacer un análisis de comillas apropiado, en caso de que tenga una variable cuyo valor sea similar hello\nexport var=value. Uno de los pocos otros comandos que le dará una salida consistente en todos los shells POSIX es env, pero esa salida es más difícil de analizar ya que carece del export =bit.
Kusalananda

Respuestas:

9

Es bastante fácil en awk.

awk 'BEGIN{for(v in ENVIRON) print v}'

Sin embargo, tenga cuidado con algunas implementaciones de awk que agregan sus propias variables de entorno (por ejemplo, GNU awk add AWKPATHy AWKLIBPATHto ENVIRON).

El resultado es ambiguo si el nombre de una variable de entorno contiene una nueva línea, lo cual es extremadamente inusual pero técnicamente posible. Una solución pura sh sería difícil. Su mejor opción es comenzar, export -ppero es difícil masajearlo en sh puro. Puede usar sed para masajear la salida de export -p, luego usar evalpara obtener el shell para eliminar lo que se cita. Bash y zsh imprimen prefijos no estándar.

report () { echo "${1%%=*}"; };
eval "$(export -p | sed "s/^export /report /;
                         s/^declare -x /report /;
                         s/typeset -x /report /")"

Tenga en cuenta que, dependiendo del shell, export -ppuede mostrar o no variables cuyo nombre no sea válido en el shell, y si no lo hace, puede citar o no los nombres correctamente. Por ejemplo, dash, mksh y zsh omiten variables cuyo nombre incluye una nueva línea, BusyBox dash y ksh93 las imprimen sin formato y bash las imprime sin su valor. Si necesita defenderse de entradas no confiables, no confíe en una solución POSIX pura y definitivamente no invoque evalnada derivado de la salida de export -p.

Gilles 'SO- deja de ser malvado'
fuente
No estoy seguro de lo "fácil" que es realmente con sed (1) con valores de varias líneas. Me gustaría ver eso. Pero gracias por el método awk (1). Creo que esta es la forma más portátil hasta ahora (aunque no creo que exitsea ​​necesaria).
Juan
Tenga en cuenta que si usted consigue FOO<newline>BAR, usted no sabe si se trata de una FOO<newline>BARvariable de entorno (que export -pno se muestran con la mayoría de conchas, ver env $'FOO\nBAR=test' awk 'BEGIN{for (v in ENVIRON) print v}') o ambos una FOOy BARvariable de entorno.
Stéphane Chazelas
Tenga en cuenta que GNU awks establece variables de entorno propias ( AWKPATHy AWKLIBPATHen mi sistema)
Stéphane Chazelas
@ StéphaneChazelas - re: nueva línea incrustada en el nombre var - de acuerdo - difícil de defender contra eso con código shell. Re: AWKPATH y AWKLIBPATH contaminación, también noté esa insidiosa inserción. Eso es gnu awk, no bsd awk.
Juan
0

Me gustan las cosas simples; Esto funcionará para los sistemas POSIX:

printenv | sed 's;=.*;;' | sort
HOME
HOSTNAME
PATH
PWD
SHLVL
TERM
todd_dsm
fuente
55
export AAA=$'multi\nBBB=line'
roaima
@todd_dsm: esto falla para las variables de entorno que tienen valores que abarcan más de una línea (p. ej., a veces TERMCAP: lo veo en una sesión de pantalla (1), IIRC). Por lo tanto, esta respuesta no cumple con los requisitos descritos en la pregunta original. También me gusta simple, pero esto no funciona en general.
Juan
El dato que ha editado en su puesto original era interesante para la fiesta: compgen -e. No ayuda para mis scripts portátiles (p. Ej., Cuando bash no está disponible), pero es interesante.
Juan
solo por curiosidad, ¿por qué restringirse al caparazón bourne (posix)? cumplir con posix es excelente, pero pierdes una gran cantidad de funcionalidad en esa búsqueda. puede ser portátil y NO compatible con posh con bash; Es parte de la familia GNU.
todd_dsm
Utilizando dashen debian, obtengo los mismos resultados con el comando anterior o el modificado printenv | sed 's;*=.;;' | sortpara obtener los valores. Exporté la variable yoy le asigné tu primer comentario anterior; se imprimió como se esperaba, con múltiples líneas. No estoy seguro de lo que está experimentando, pero no debería haber una salida truncada. ejecuta el comando en el shell; sea ​​lo que sea que produzca, así es como debería funcionar; no esperes truncar. Luego, dentro del contexto de TERMCAP / screen / iirc; Debería ser lo mismo. Si el resultado no coincide, entonces es probable que sea un problema con uno de esos programas.
todd_dsm