powłoka posix: wypisuje listę nazw zmiennych środowiskowych (bez wartości)

11

W jaki sposób mogę wydrukować listę aktualnie zdefiniowanych zmiennych środowiskowych bez ich wartości w sposób zgodny z posix, który działa z wieloma implementacjami ?

W niektórych implementacjach (mksh, freebsd / bin / sh), samo użycie exportbędzie pasować do rachunku:

$ export
FOO2
FOO

Ale w przypadku niektórych innych implementacji (bash, zsh, dash) exportrównież pokazuje wartość. Z bash na przykład:

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

Inne opcje, takie jak envlub printenvnie mają możliwości, aby wydrukować tylko nazwy zmiennych bez wartości, a przynajmniej nie na platformach Linux i FreeBSD próbowałem.

Przesyłanie strumieniowe do awk / sed / etc. lub przycinanie listy za pomocą technik rozszerzania parametrów (np. ${foo%%=*}) jest dopuszczalne, ale musi współpracować z wartościami, które mogą obejmować linie i zawierać =oraz spacje w wartości (patrz przykład powyżej).

Odpowiedzi dotyczące konkretnych implementacji powłoki są interesujące, ale przede wszystkim szukam czegoś, co będzie kompatybilne z różnymi implementacjami.

Juan
źródło
2
Jeśli zamierzasz parsować coś, idź z wyjściem export -pokreślonym przez POSIX, aby wygenerować wyjście, które jest również odpowiednie dla danych wejściowych w powłoce.
Kusalananda
Nie potrzebuję niczego, aby wprowadzić dane do powłoki. Chcę tylko nazwy zmiennych środowiskowych. Tak więc dodatkowe cruft (np. Słowo „eksportuj” z przodu każdej linii) musiałoby i tak zostać usunięte. Dlaczego miałbym tego używać export -p?
Juan
1
Powinieneś użyć, export -pponieważ dałoby to spójny wynik we wszystkich powłokach POSIX, co powiedziałeś, że chcesz.
Kusalananda
Chcę rozwiązania, które wypisze tylko nazwy zmiennych, które jest spójnym rozwiązaniem dla różnych powłok. export -pnie spełnia pierwszego wymagania - wypisuje tylko nazwy zmiennych bez wartości.
Juan
JEŚLI zamierzasz coś przeanalizować, skorzystaj z wyjścia export -p. Nie zamierzam pisać tego parsowania, ponieważ w ogólnym przypadku musiałoby to również wykonać prawidłowe parsowanie cytatów, na wypadek gdybyś miał zmienną, której wartość jest podobna hello\nexport var=value. Jednym z niewielu innych poleceń, które zapewniają spójny wynik we wszystkich powłokach POSIX, jest envjednak trudniejsze do przeanalizowania, ponieważ brakuje w nim export =bitu.
Kusalananda

Odpowiedzi:

9

W awk jest dość łatwe.

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

Jednak uważaj niektóre implementacje awk dodać zmienne środowiskowe własnych (np GNU awk dodaje AWKPATHi AWKLIBPATHdo ENVIRON).

Dane wyjściowe są niejednoznaczne, jeśli nazwa zmiennej środowiskowej zawiera nowy wiersz, co jest niezwykle nietypowe, ale technicznie możliwe. Rozwiązanie czystego sh byłoby trudne. Najlepiej zacząć od tego, export -pale masowanie go w czystym sh jest trudne. Można użyć sed do masażu wyjście export -p, a następnie użyć eval, aby uzyskać powłokę, aby usunąć to, co cytowany. Bash i zsh drukują niestandardowe prefiksy.

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

Zauważ, że w zależności od powłoki, export -pmoże, ale nie musi pokazywać zmiennych, których nazwa jest niepoprawna w powłoce, a jeśli nie, to może, ale nie musi, poprawnie podawać nazwy. Na przykład dash, mksh i zsh pomijają zmienne, których nazwa zawiera znak nowej linii, BusyBox dash i ksh93 drukują je na surowo, a bash drukuje je na surowo bez ich wartości. Jeśli musisz bronić się przed niezaufanymi danymi wejściowymi, nie polegaj na czystym rozwiązaniu POSIX i zdecydowanie nie wzywaj evalniczego pochodzącego z danych wyjściowych export -p.

Gilles „SO- przestań być zły”
źródło
Nie jestem pewien, jak „łatwo” tak naprawdę jest w przypadku sed (1) z wartościami wielowierszowymi - chciałbym to zobaczyć. Ale dziękuję za metodę awk (1). Myślę, że jest to jak dotąd najbardziej przenośny sposób (choć nie uważam, że exitjest to konieczne).
Juan
Zauważ, że jeśli to FOO<newline>BARzrobisz, nie wiesz, czy jest to FOO<newline>BARzmienna środowiskowa (która export -pnie wyświetla się w przypadku większości powłok, zobacz env $'FOO\nBAR=test' awk 'BEGIN{for (v in ENVIRON) print v}') czy zarówno zmienna środowiskowa FOOi BAR.
Stéphane Chazelas
Zauważ, że GNU awks ustawia własne zmienne środowiskowe ( AWKPATHi AWKLIBPATHw moim systemie)
Stéphane Chazelas
@ StéphaneChazelas - re: osadzony znak nowej linii w nazwie var - uzgodniony - trudny do obrony przed tym za pomocą kodu powłoki. Re: AWKPATH i AWKLIBPATH zanieczyszczenie, zauważyłem również podstępne wstawienie. To jest gnu awk, nie bsd awk.
Juan
0

Lubię proste rzeczy; zadziała to dla systemów POSIX:

printenv | sed 's;=.*;;' | sort
HOME
HOSTNAME
PATH
PWD
SHLVL
TERM
todd_dsm
źródło
5
export AAA=$'multi\nBBB=line'
roaima
@todd_dsm - Nie udaje się to w przypadku zmiennych środowiskowych o wartościach obejmujących więcej niż jedną linię (np. czasami TERMCAP - Widzę to podczas sesji screen (1), IIRC). Tak więc ta odpowiedź nie spełnia wymagań opisanych w pierwotnym pytaniu. Lubię też proste, ale to ogólnie nie działa.
Juan
Smakołyk edytowane w oryginalnym poście była interesująca dla bash: compgen -e. To nie pomaga w moim przenośnym skrypcie (np. Gdy bash nie jest dostępny), ale jest interesujące.
Juan
ciekawe, po co ograniczać się do powłoki Bourne'a (posix)? zgodność z posixem jest świetna, ale tracisz wiele funkcjonalności w tym pościgu. możesz być przenośny i NIE zgodny z POSIX-em z bash; jest częścią rodziny GNU.
todd_dsm
Używając dashw debianie, otrzymuję te same wyniki z powyższym poleceniem lub zmodyfikowałem, printenv | sed 's;*=.;;' | sortaby uzyskać wartości. Wyeksportowałem zmienną yoi przypisałem jej twój pierwszy komentarz powyżej; wydrukowano zgodnie z oczekiwaniami, z wieloma liniami. nie jestem pewien, czego doświadczasz, ale nie powinno być obciętego wyjścia. uruchom polecenie w powłoce; cokolwiek wyjdzie, to jak powinno działać; nie oczekuj żadnego obcięcia. Następnie w kontekście TERMCAP / screen / iirc; powinno być takie samo. Jeśli dane wyjściowe nie są zgodne, to prawdopodobnie jest to problem z jednym z tych programów.
todd_dsm