shell posix: imprimer la liste des noms de variables d'environnement (sans valeurs)

11

D'une manière compatible posix qui fonctionne avec plusieurs implémentations, comment puis-je imprimer la liste des variables d'environnement actuellement définies sans leurs valeurs?

Sur certaines implémentations (mksh, freebsd / bin / sh), le simple fait d'utiliser exportseul suffira:

$ export
FOO2
FOO

Mais pour certaines autres implémentations (bash, zsh, dash), exportaffiche également la valeur. Avec bash, par exemple:

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

D'autres options comme envou printenvn'ont pas d'options pour imprimer uniquement les noms de variables sans valeurs, du moins pas sur les plates-formes Linux et FreeBSD que j'ai essayées.

Tuyauterie vers awk / sed / etc. ou rogner la liste avec des techniques d'expansion de paramètres (par exemple, ${foo%%=*}) est acceptable, mais il doit fonctionner avec des valeurs qui peuvent s'étendre sur des lignes et avoir des =espaces dans la valeur (voir l'exemple ci-dessus).

Les réponses spécifiques à des implémentations de shell particulières sont intéressantes, mais je recherche principalement quelque chose de compatible entre les implémentations.

Juan
la source
2
Si vous allez analyser quelque chose, utilisez la sortie export -pspécifiée par POSIX pour générer une sortie qui convient également à l'entrée dans le shell.
Kusalananda
Je n'ai besoin de rien pour entrer dans un shell. Je veux juste les noms des variables d'environnement. Ainsi, la louche supplémentaire (par exemple, le mot «exportation» au début de chaque ligne) devrait simplement être supprimée de toute façon. Pourquoi voudrais-je l'utiliser export -ppour cela?
Juan
1
Vous voudriez l'utiliser export -pparce que cela vous donnerait une sortie cohérente sur tous les shells POSIX, ce que vous avez dit vouloir.
Kusalananda
Je veux une solution qui n'imprimera que les noms de variables, ce qui est une solution cohérente entre les shells. export -pne correspond pas à la première exigence - imprimer uniquement les noms de variables sans valeurs.
Juan
SI vous allez analyser quelque chose, utilisez la sortie de export -p. Je ne vais pas écrire cette analyse, car dans le cas général, il faudrait également effectuer une analyse des guillemets appropriée, au cas où vous auriez une variable dont la valeur ressemble à quelque chose hello\nexport var=value. L'une des rares autres commandes qui vous donnera une sortie cohérente dans tous les shells POSIX est env, mais cette sortie est plus difficile à analyser car elle manque le export =bit.
Kusalananda

Réponses:

9

C'est assez facile en awk.

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

Cependant méfiez - vous des implémentations de awk ajouter des variables d' environnement de leur propre (par exemple GNU awk ajoute AWKPATHet AWKLIBPATHà ENVIRON).

La sortie est ambiguë si le nom d'une variable d'environnement contient une nouvelle ligne, ce qui est extrêmement inhabituel mais techniquement possible. Une solution pure sh serait difficile. Votre meilleur pari est de commencer export -pmais le masser en pure sh est difficile. Vous pouvez utiliser sed pour masser la sortie de export -p, puis utiliser evalpour obtenir la coque pour supprimer ce qu'elle a cité. Bash et zsh impriment des préfixes non standard.

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

Notez que selon le shell, export -ppeut ou peut ne pas afficher les variables dont le nom n'est pas valide dans le shell, et si ce n'est pas le cas, il peut ou non citer les noms correctement. Par exemple, dash, mksh et zsh omettent les variables dont le nom inclut une nouvelle ligne, BusyBox dash et ksh93 les affichent brutes et bash les imprime brutes sans leur valeur. Si vous devez vous défendre contre des entrées non fiables, ne vous fiez pas à une solution POSIX pure et n'appelez certainement evalrien de ce qui dérive de la sortie de export -p.

Gilles 'SO- arrête d'être méchant'
la source
Je ne sais pas à quel point c'est "facile" avec sed (1) avec des valeurs multilignes - j'aimerais voir ça. Mais merci pour la méthode awk (1). Je pense que c'est le moyen le plus portable à ce jour (bien que je ne pense pas que ce exitsoit nécessaire).
Juan
Notez que si vous obtenez FOO<newline>BAR, vous ne savez pas s'il s'agit d'une FOO<newline>BARvariable d'environnement (qui export -pne s'afficherait pas avec la plupart des shells, voir env $'FOO\nBAR=test' awk 'BEGIN{for (v in ENVIRON) print v}') ou à la fois d'une variable d'environnement FOOet BAR.
Stéphane Chazelas
Notez que GNU awkdéfinit ses propres variables d'environnement ( AWKPATHet AWKLIBPATHsur mon système)
Stéphane Chazelas
@ StéphaneChazelas - re: newline incorporé dans le nom var - d'accord - difficile de se défendre contre cela avec du code shell. Re: AWKPATH & AWKLIBPATH pollution, j'ai aussi remarqué cette insertion insidieuse. C'est gnu awk, pas bsd awk.
Juan
0

J'aime les choses simples; cela fonctionnera pour les systèmes POSIX:

printenv | sed 's;=.*;;' | sort
HOME
HOSTNAME
PATH
PWD
SHLVL
TERM
todd_dsm
la source
5
export AAA=$'multi\nBBB=line'
roaima
@todd_dsm - Cela échoue pour les variables d'environnement qui ont des valeurs qui s'étendent sur plus d'une ligne (par exemple, parfois TERMCAP - je le vois lors d'une session screen (1), IIRC). Cette réponse ne répond donc pas aux exigences décrites dans la question d'origine. J'aime aussi simple, mais cela ne fonctionne généralement pas.
Juan
La friandise que vous avez modifié dans votre message original était intéressant pour bash: compgen -e. Cela n'aide pas pour mes scripts portables (par exemple, quand bash n'est pas disponible), mais c'est intéressant.
Juan
juste curieux, pourquoi se limiter au shell bourne (posix)? être conforme à posix est génial, mais vous perdez beaucoup de fonctionnalités dans cette poursuite. vous pouvez être portable et PAS compatible posix avec bash; cela fait partie de la famille GNU.
todd_dsm
En utilisant dashDebian, j'obtiens les mêmes résultats avec la commande ci-dessus ou, la modifiée printenv | sed 's;*=.;;' | sortpour obtenir les valeurs. J'ai exporté la variable yoet lui ai attribué votre premier commentaire ci-dessus; il a imprimé comme prévu, avec plusieurs lignes. Je ne sais pas ce que vous vivez, mais il ne devrait pas y avoir de sortie tronquée. exécutez la commande dans le shell; quoi qu'il produise il y a comment cela devrait fonctionner; ne vous attendez pas à la tronquer. Ensuite, dans le cadre de TERMCAP / screen / iirc; devrait être le même. Si la sortie ne correspond pas, c'est probablement un problème avec l'un de ces programmes.
todd_dsm