posix shell: stampa l'elenco dei nomi delle variabili d'ambiente (senza valori)


11

In un modo compatibile con posix che funziona con più implementazioni, come posso stampare l'elenco delle variabili d'ambiente attualmente definite senza i loro valori?

Su alcune implementazioni (mksh, freebsd / bin / sh), solo l'utilizzo exportda solo si adatta al conto:

$ export
FOO2
FOO

Ma per alcune altre implementazioni (bash, zsh, dash), exportmostra anche il valore. Con bash, ad esempio:

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

Altre opzioni come envo printenvnon hanno opzioni per stampare solo i nomi delle variabili senza valori, almeno non sulle piattaforme linux e freebsd che ho provato.

Piping su awk / sed / etc. o tagliare la lista con tecniche di espansione dei parametri (ad es. ${foo%%=*}) è accettabile, ma deve lavorare con valori che possono estendersi su linee e avere =e spazi bianchi nel valore (vedi esempio sopra).

Le risposte specifiche a particolari implementazioni della shell sono interessanti, ma sto principalmente cercando qualcosa che sia compatibile tra le implementazioni.


2
Se stai per analizzare qualcosa, procedi con l'output export -pspecificato da POSIX per generare output adatto anche all'input nella shell.
Kusalananda

Non ho bisogno di nulla da inserire in una shell. Voglio solo i nomi delle variabili d'ambiente. Quindi la extra cruft (ad esempio, la parola "export" nella parte anteriore di ogni riga) dovrebbe essere rimossa comunque. Perché dovrei voler usare export -pper questo?
Juan,

1
Dovresti usarlo export -pperché questo ti darebbe un output coerente su tutte le shell POSIX, che hai detto che volevi.
Kusalananda

Voglio una soluzione che stamperà solo i nomi delle variabili che è una soluzione coerente tra le shell. export -pnon soddisfa il primo requisito: stampare solo nomi di variabili senza valori.
Juan,

Se hai intenzione di analizzare qualcosa, vai con l'output di export -p. Non scriverò questo parsing, perché nel caso generale, dovrebbe anche fare un corretto parsing delle quotazioni, nel caso in cui tu abbia una variabile il cui valore è qualcosa del genere hello\nexport var=value. Uno dei pochi altri comandi che ti darà un output coerente in tutte le shell POSIX è env, ma quell'output è più difficile da analizzare poiché manca il export =bit.
Kusalananda

Risposte:


9

È abbastanza facile in awk.

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

Tuttavia attenzione alcune implementazioni awk aggiungono le variabili d'ambiente dei loro propri (per esempio GNU awk aggiunge AWKPATHe AWKLIBPATHper ENVIRON).

L'output è ambiguo se il nome di una variabile di ambiente contiene una nuova riga, il che è estremamente insolito ma tecnicamente possibile. Una soluzione sh pura sarebbe difficile. La tua scommessa migliore è iniziare export -pma massaggiarlo in puro sh è difficile. Puoi usare sed per massaggiare l'output di export -p, quindi usare evalper ottenere il guscio per rimuovere ciò che ha citato. Bash e zsh stampano prefissi non standard.

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

Si noti che, a seconda della shell, export -ppuò o meno mostrare variabili il cui nome non è valido nella shell e, in caso contrario, potrebbe o meno citare correttamente i nomi. Ad esempio, trattino, mksh e zsh omettono le variabili il cui nome include una nuova riga, trattino BusyBox e ksh93 li stampano grezzi e bash li stampa grezzi senza il loro valore. Se è necessario difendersi da input non attendibili, non fare affidamento su una soluzione POSIX pura e sicuramente non fare affidamento evalsu qualcosa derivato dall'output di export -p.


Non sono sicuro di quanto sia "facile" con sed (1) con valori multilinea - mi piacerebbe vederlo. Ma grazie per il metodo awk (1). Penso che questo sia il modo più portatile finora (anche se non credo exitsia necessario).
Juan,

Si noti che se si ottiene FOO<newline>BAR, non si sa se si tratta di una FOO<newline>BARvariabile di ambiente (che export -pnon mostrerebbe con la maggior parte delle shell, vedi env $'FOO\nBAR=test' awk 'BEGIN{for (v in ENVIRON) print v}') o di una variabile di ambiente FOOe BAR.
Stéphane Chazelas,

Nota che GNU awkimposta variabili di ambiente proprie ( AWKPATHe AWKLIBPATHsul mio sistema)
Stéphane Chazelas,

@ StéphaneChazelas - re: newline incorporato in nome var - concordato - difficile difendersi da quello con codice shell. Ri: AWKPATH e AWKLIBPATH, ho notato anche l'inserimento insidioso. Questo è gnu awk, non bsd awk.
Juan,

0

Mi piacciono le cose semplici; questo funzionerà per i sistemi POSIX:

printenv | sed 's;=.*;;' | sort
HOME
HOSTNAME
PATH
PWD
SHLVL
TERM

5
export AAA=$'multi\nBBB=line'
roaima,

@todd_dsm - Questo non riesce per le variabili di ambiente che hanno valori che si estendono su più di una riga (ad esempio, a volte TERMCAP - Lo vedo in una sessione di schermata (1), IIRC). Quindi questa risposta non soddisfa i requisiti descritti nella domanda originale. Mi piace anche semplice, ma questo non funziona in generale.
Juan,

Il bocconcino hai modificato nel tuo post originale era interessante per bash: compgen -e. Non aiuta per i miei script portatili (ad esempio, quando bash non è disponibile), ma è interessante.
Juan,

solo curioso, perché limitarti alla shell bourne (posix)? essere conformi a posix è fantastico, ma in tale ricerca si perde una grande quantità di funzionalità. puoi essere portatile e NON conforme a posix con bash; fa parte della famiglia GNU.
todd_dsm,

Usando dashin debian, ottengo gli stessi risultati con il comando sopra o, modificato printenv | sed 's;*=.;;' | sortper ottenere i valori. Ho esportato la variabile yoe assegnato il tuo primo commento sopra; è stato stampato come previsto, con più righe. non sono sicuro di cosa stai vivendo ma non dovrebbe esserci un output troncato. eseguire il comando nella shell; qualunque cosa ci sia, è come dovrebbe funzionare; non aspettarti di troncare. Quindi, nel contesto di TERMCAP / screen / iirc; dovrebbe essere lo stesso. Se l'output non corrisponde, è probabile che sia un problema con uno di quei programmi.
todd_dsm,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.