shell posix: daftar cetak nama variabel lingkungan (tanpa nilai)

11

Dengan cara yang kompatibel dengan posix yang bekerja dengan banyak implementasi, bagaimana saya bisa mencetak daftar variabel lingkungan yang didefinisikan saat ini tanpa nilainya?

Pada beberapa implementasi (mksh, freebsd / bin / sh), hanya menggunakan exportdengan sendirinya akan sesuai dengan tagihan:

$ export
FOO2
FOO

Tetapi untuk beberapa implementasi lainnya (bash, zsh, dash), exportjuga menunjukkan nilainya. Dengan bash, misalnya:

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

Opsi lain suka envatau printenvtidak memiliki opsi untuk mencetak hanya nama variabel tanpa nilai, setidaknya tidak pada platform linux dan freebsd yang saya coba.

Perpipaan ke awk / sed / etc. atau memotong daftar dengan teknik ekspansi parameter (misalnya, ${foo%%=*}) dapat diterima, tetapi harus bekerja dengan nilai-nilai yang dapat menjangkau garis dan memiliki =dan spasi kosong dalam nilai (lihat contoh di atas).

Jawaban spesifik untuk implementasi shell tertentu menarik, tetapi saya terutama mencari sesuatu yang kompatibel di seluruh implementasi.

Juan
sumber
2
Jika Anda akan mem-parsing sesuatu, pergi dengan output export -pyang ditentukan oleh POSIX untuk menghasilkan output yang juga cocok untuk input di shell.
Kusalananda
Saya tidak perlu apa pun untuk dimasukkan ke shell. Saya hanya ingin nama-nama variabel lingkungan. Jadi cruft tambahan (misalnya, kata 'ekspor' di depan setiap baris) harus dihapus saja. Mengapa saya ingin menggunakan export -pini?
Juan
1
Anda ingin menggunakan export -pkarena itu akan memberi Anda output yang konsisten di semua shell POSIX, yang Anda katakan Anda inginkan.
Kusalananda
Saya ingin solusi yang akan mencetak hanya nama variabel yang merupakan solusi yang konsisten di seluruh shell. export -ptidak sesuai dengan persyaratan pertama - hanya mencetak nama variabel tanpa nilai.
Juan
JIKA Anda akan menguraikan sesuatu, ikuti output dari export -p. Saya tidak akan menulis parsing itu, karena dalam kasus umum, itu juga harus melakukan parsing kutipan yang tepat, jika Anda memiliki variabel yang nilainya seperti hello\nexport var=value. Salah satu dari beberapa perintah lain yang akan memberi Anda output yang konsisten di semua shell POSIX adalah env, tetapi output itu lebih sulit untuk diurai karena tidak memiliki export =bit.
Kusalananda

Jawaban:

9

Sangat mudah dalam awk.

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

Namun waspadalah beberapa implementasi awk menambahkan variabel lingkungannya sendiri (mis. GNU awk add AWKPATHand AWKLIBPATHto ENVIRON).

Outputnya ambigu jika nama variabel lingkungan berisi baris baru, yang sangat tidak biasa tetapi secara teknis memungkinkan. Solusi murni akan sulit. Taruhan terbaik Anda adalah memulainya export -ptetapi memijatnya dengan benar tidak sulit. Anda dapat menggunakan sed untuk memijat output export -p, lalu gunakan evaluntuk mendapatkan shell untuk menghapus apa yang dikutip. Bash dan zsh mencetak awalan non-standar.

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

Perhatikan bahwa tergantung pada shell, export -pmungkin atau mungkin tidak menampilkan variabel yang namanya tidak valid dalam shell, dan jika tidak, maka mungkin atau mungkin tidak mengutip nama-nama dengan benar. Misalnya, tanda hubung, mksh dan zsh menghilangkan variabel yang namanya menyertakan baris baru, BusyBox dash dan ksh93 mencetaknya mentah, dan bash mencetaknya mentah tanpa nilainya. Jika Anda perlu mempertahankan terhadap input yang tidak tepercaya, jangan mengandalkan solusi POSIX murni, dan pasti tidak meminta evalapa pun yang berasal dari output export -p.

Gilles 'SANGAT berhenti menjadi jahat'
sumber
Saya tidak yakin betapa "mudah" itu sebenarnya dengan sed (1) dengan nilai multiline - Saya ingin melihatnya. Tapi terima kasih untuk metode awk (1). Saya pikir ini adalah cara yang paling portabel sejauh ini (walaupun saya pikir itu exittidak perlu).
Juan
Perhatikan bahwa jika Anda mendapatkannya FOO<newline>BAR, Anda tidak tahu apakah itu FOO<newline>BARvariabel lingkungan (yang export -ptidak akan ditampilkan pada sebagian besar shell, lihat env $'FOO\nBAR=test' awk 'BEGIN{for (v in ENVIRON) print v}') atau keduanya a FOOdan BARvariabel lingkungan.
Stéphane Chazelas
Perhatikan bahwa GNU awkmenetapkan variabel lingkungannya sendiri ( AWKPATHdan AWKLIBPATHpada sistem saya)
Stéphane Chazelas
@ StéphaneChazelas - re: tertanam baris baru dalam nama var - setuju - sulit untuk mempertahankannya dengan kode shell. Re: AWKPATH & AWKLIBPATH polusi, saya perhatikan bahwa penyisipan juga berbahaya. Itu gnu awk, bukan bsd awk.
Juan
0

Saya suka hal-hal sederhana; ini akan bekerja untuk sistem POSIX:

printenv | sed 's;=.*;;' | sort
HOME
HOSTNAME
PATH
PWD
SHLVL
TERM
todd_dsm
sumber
5
export AAA=$'multi\nBBB=line'
roaima
@todd_dsm - Ini gagal untuk variabel lingkungan yang memiliki nilai yang menjangkau lebih dari satu baris (misalnya, kadang-kadang TERMCAP - Saya melihat ini ketika di layar (1) sesi, IIRC). Jadi jawaban ini tidak memenuhi persyaratan yang dijelaskan dalam pertanyaan awal. Saya juga suka sederhana, tetapi ini tidak bekerja secara umum.
Juan
Berita gembira Anda diedit di posting asli Anda menarik untuk bash: compgen -e. Itu tidak membantu untuk skrip portabel saya (misalnya, ketika bash tidak tersedia), tetapi menarik.
Juan
hanya ingin tahu, mengapa membatasi diri Anda pada bourne (posix) shell? bersikap patuh-posi itu bagus, tetapi Anda kehilangan banyak fungsi dalam pengejaran itu. Anda bisa portabel dan TIDAK sesuai dengan bash; itu adalah bagian dari keluarga GNU.
todd_dsm
Menggunakan dashdi debian, saya mendapatkan hasil yang sama dengan perintah di atas atau, dimodifikasi printenv | sed 's;*=.;;' | sortuntuk mendapatkan nilai. Saya mengekspor variabel yodan memberikannya komentar pertama Anda di atas; itu dicetak seperti yang diharapkan, dengan beberapa baris. tidak yakin apa yang Anda alami tetapi seharusnya tidak ada output yang terpotong. jalankan perintah di shell; apa pun yang dihasilkan di situ adalah cara kerjanya; berharap tidak memotong. Kemudian, dalam konteks TERMCAP / layar / iirc; harus sama. Jika output tidak cocok maka kemungkinan ada masalah dengan salah satu program tersebut.
todd_dsm