posix shell: Liste der Umgebungsvariablennamen drucken (ohne Werte)

11

Wie kann ich auf eine posix-kompatible Weise, die mit mehreren Implementierungen funktioniert, die Liste der aktuell definierten Umgebungsvariablen ohne deren Werte drucken ?

Bei einigen Implementierungen (mksh, freebsd / bin / sh) ist die alleinige Verwendung genau das Richtige für Sie export:

$ export
FOO2
FOO

Bei einigen anderen Implementierungen (bash, zsh, dash) wird jedoch exportauch der Wert angezeigt. Mit Bash zum Beispiel:

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

Andere Optionen wie envoder printenvhaben keine Optionen, um nur die Variablennamen ohne Werte zu drucken, zumindest nicht auf den Linux- und Freebsd-Plattformen, die ich ausprobiert habe.

Rohrleitungen zu awk / sed / etc. Das Trimmen der Liste mit Parametererweiterungstechniken (z. B. ${foo%%=*}) ist akzeptabel, muss jedoch mit Werten arbeiten, die sich über Linien erstrecken können =und Leerzeichen im Wert enthalten (siehe Beispiel oben).

Spezifische Antworten für bestimmte Shell-Implementierungen sind interessant, aber ich suche hauptsächlich nach etwas, das für alle Implementierungen kompatibel ist.

Juan
quelle
2
Wenn Sie etwas analysieren möchten, verwenden Sie die export -pvon POSIX angegebene Ausgabe, um eine Ausgabe zu generieren, die auch für die Eingabe in die Shell geeignet ist.
Kusalananda
Ich brauche nichts, um in eine Shell einzugeben. Ich möchte nur die Namen der Umgebungsvariablen. Die zusätzliche Cruft (z. B. das Exportwort am Anfang jeder Zeile) müsste also sowieso nur entfernt werden. Warum sollte ich das verwenden wollen export -p?
Juan
1
Sie möchten verwenden, export -pda Sie dadurch eine konsistente Ausgabe über alle POSIX-Shells erhalten, von denen Sie sagten, dass Sie sie wollten.
Kusalananda
Ich möchte eine Lösung, die nur die Variablennamen druckt und eine konsistente Lösung für alle Shells darstellt. export -ppasst nicht zur ersten Anforderung - nur Variablennamen ohne Werte drucken.
Juan
Wenn Sie etwas analysieren wollen, gehen Sie mit der Ausgabe von export -p. Ich werde diese Analyse nicht schreiben, da sie im allgemeinen Fall auch eine ordnungsgemäße Anführungszeichenanalyse durchführen müsste, falls Sie eine Variable haben, deren Wert so etwas wie ist hello\nexport var=value. Einer der wenigen anderen Befehle, mit denen Sie in allen POSIX-Shells eine konsistente Ausgabe erhalten, ist env, aber diese Ausgabe ist schwieriger zu analysieren, da das export =Bit fehlt .
Kusalananda

Antworten:

9

In awk ist es ziemlich einfach.

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

Beachten Sie jedoch, dass einige awk-Implementierungen eigene Umgebungsvariablen hinzufügen (z. B. GNU awk fügt hinzu AWKPATHund AWKLIBPATHzu ENVIRON).

Die Ausgabe ist nicht eindeutig, wenn der Name einer Umgebungsvariablen einen Zeilenumbruch enthält, was äußerst ungewöhnlich, aber technisch möglich ist. Eine reine sh-Lösung wäre schwierig. Ihre beste Wette ist, mit zu beginnen, export -paber es ist schwierig, es in reinem sh zu massieren. Sie können sed verwenden, um die Ausgabe von zu massieren export -p, und dann verwenden eval, um die Schale dazu zu bringen, das zu entfernen, was sie zitiert. Bash und zsh drucken nicht standardmäßige Präfixe.

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

Beachten Sie, dass je nach Shell export -pmöglicherweise Variablen angezeigt werden, deren Name in der Shell nicht gültig ist, und wenn dies nicht der Fall ist, werden die Namen möglicherweise richtig zitiert oder nicht. Beispielsweise lassen dash, mksh und zsh Variablen weg, deren Name eine neue Zeile enthält, BusyBox dash und ksh93 drucken sie roh und bash druckt sie roh ohne ihren Wert. Wenn Sie sich gegen nicht vertrauenswürdige Eingaben verteidigen müssen, verlassen Sie sich nicht auf eine reine POSIX-Lösung und rufen Sie evalauf keinen Fall etwas auf, das aus der Ausgabe von abgeleitet ist export -p.

Gilles 'SO - hör auf böse zu sein'
quelle
Ich bin mir nicht sicher, wie "einfach" es mit sed (1) mit mehrzeiligen Werten wirklich ist - das würde ich gerne sehen. Aber danke für die awk (1) -Methode. Ich denke, dies ist der bisher tragbarste Weg (obwohl ich nicht denke, dass dies exitnotwendig ist).
Juan
Beachten Sie, dass , wenn Sie erhalten FOO<newline>BAR, die Sie nicht wissen , ob es eine ist die FOO<newline>BARUmgebungsvariable (die export -pmit den meisten Schalen nicht zeigen würde, sehen env $'FOO\nBAR=test' awk 'BEGIN{for (v in ENVIRON) print v}') oder sowohl ein FOOund BARUmgebungsvariablen.
Stéphane Chazelas
Beachten Sie, dass GNUs awkeigene Umgebungsvariablen ( AWKPATHund AWKLIBPATHauf meinem System)
Stéphane Chazelas
@ StéphaneChazelas - re: eingebettete Newline in var name - vereinbart - schwer dagegen mit Shell-Code zu verteidigen. Betreff: AWKPATH & AWKLIBPATH Verschmutzung, ich bemerkte auch diese heimtückische Einfügung. Das ist gnu awk, nicht bsd awk.
Juan
0

Ich mag einfache Dinge; Dies funktioniert für POSIX-Systeme:

printenv | sed 's;=.*;;' | sort
HOME
HOSTNAME
PATH
PWD
SHLVL
TERM
todd_dsm
quelle
4
export AAA=$'multi\nBBB=line'
Roaima
@todd_dsm - Dies schlägt bei Umgebungsvariablen fehl, deren Werte mehr als eine Zeile umfassen (z. B. manchmal TERMCAP - Ich sehe dies in einer Bildschirmsitzung (1), IIRC). Diese Antwort entspricht also nicht den in der ursprünglichen Frage beschriebenen Anforderungen. Ich mag auch einfach, aber das funktioniert im Allgemeinen nicht.
Juan
Der Leckerbissen, den Sie in Ihrem ursprünglichen Beitrag bearbeitet haben, war für bash interessant : compgen -e. Es hilft nicht für meine tragbaren Skripte (z. B. wenn Bash nicht verfügbar ist), aber es ist interessant.
Juan
nur neugierig, warum beschränken Sie sich auf die Bourne (Posix) Shell? Posix-konform zu sein ist großartig, aber Sie verlieren dabei viel Funktionalität. Sie können tragbar und NICHT posix-konform mit bash sein. Es ist Teil der GNU-Familie.
todd_dsm
Bei Verwendung dashin Debian erhalte ich die gleichen Ergebnisse mit dem obigen Befehl oder dem, der geändert wurde printenv | sed 's;*=.;;' | sort, um die Werte zu erhalten. Ich habe die Variable exportiert yound ihr Ihren ersten Kommentar oben zugewiesen. Es wurde wie erwartet mit mehreren Zeilen gedruckt. Ich bin mir nicht sicher, was Sie erleben, aber es sollte keine abgeschnittene Ausgabe geben. Führen Sie den Befehl in der Shell aus. Was auch immer es dort ausgibt, es sollte funktionieren. Erwarten Sie kein Abschneiden. Dann im Kontext von TERMCAP / screen / iirc; sollte gleich sein. Wenn die Ausgabe nicht übereinstimmt, liegt wahrscheinlich ein Problem mit einem dieser Programme vor.
todd_dsm