Saya tertarik untuk mengatur variabel lingkungan dari satu contoh shell dari yang lain. Jadi saya memutuskan untuk melakukan riset. Setelah membaca sejumlah dari pertanyaan tentang ini saya memutuskan untuk menguji itu.
Saya menelurkan dua cangkang A dan B (PID 420), keduanya berjalan zsh
. Dari shell AI berlari berikut ini.
sudo gdb -p 420
(gdb) call setenv("FOO", "bar", 1)
(gdb) detach
Dari shell B ketika saya menjalankan env
saya dapat melihat variabel FOO memang diatur dengan nilai bar. Ini membuat saya berpikir bahwa FOO telah berhasil diinisialisasi di lingkungan shell B. Namun, jika saya mencoba untuk mencetak FOO saya mendapatkan garis kosong yang menyiratkan bahwa itu tidak disetel. Bagi saya, rasanya ada kontradiksi di sini.
Ini diuji pada Arch GNU / Linux system saya sendiri dan Ubuntu VM. Saya juga menguji ini di bash
mana variabel bahkan tidak muncul di env. Ini walaupun mengecewakan bagi saya, masuk akal jika shell menyimpan salinan lingkungannya pada waktu spawn dan hanya menggunakannya (yang disarankan dalam salah satu pertanyaan terkait). Ini masih tidak menjawab mengapa zsh
bisa melihat variabel.
Mengapa output echo $FOO
kosong?
EDIT
Setelah masukan dalam komentar saya memutuskan untuk melakukan pengujian sedikit lebih. Hasilnya dapat dilihat pada tabel di bawah ini. Di kolom pertama adalah shell yang FOO
variabelnya diinjeksikan. Baris pertama berisi perintah yang outputnya bisa dilihat di bawahnya. Variabel FOO
disuntikkan menggunakan: sudo gdb -p 420 -batch -ex 'call setenv("FOO", "bar", 1)'
. Perintah khusus untuk zsh: zsh -c '...'
juga diuji menggunakan bash. Hasilnya identik, hasilnya dihilangkan untuk singkatnya.
Arch GNU / Linux, zsh 5.3.1, bash 4.4.12 (1)
| | env | grep FOO | echo $FOO | zsh -c 'env | grep FOO' | zsh -c 'echo $FOO' | After export FOO |
|------|------------------|-----------|---------------------------|----------------------|-----------------------------------|
| zsh | FOO=bar | | FOO=bar | bar | No Change |
| bash | | bar | | | Value of FOO visible in all tests |
Ubuntu 16.04.2 LTS, zsh 5.1.1, bash 4.3.48 (1)
| | env | grep FOO | echo $FOO | zsh -c 'env | grep FOO' | zsh -c 'echo $FOO' | After export FOO |
|------|------------------|-----------|---------------------------|----------------------|-----------------------------------|
| zsh | FOO=bar | | FOO=bar | bar | No Change |
| bash | | bar | | | Value of FOO visible in all tests |
Di atas tampaknya menyiratkan bahwa hasilnya agnostik distribusi. Ini tidak memberi tahu saya lebih dari zsh
dan bash
menangani pengaturan variabel secara berbeda. Lebih jauh lagi, export FOO
memiliki perilaku yang sangat berbeda dalam konteks ini tergantung pada shell. Semoga tes ini dapat membuat sesuatu menjadi jelas bagi orang lain.
zsh -c 'echo $FOO'
(gunakan tanda kutip tunggal!)? Bisakah Anda melihatnya?env
) melihat lingkungan yang dimodifikasi.zsh
di GDB tidak membuatnya terlihat sebagai variabel shell tetapi tidak menyebabkannya diteruskan ke proses anak (seperti Anda telah mengamati), sedangkan pengaturan satu untukbash
tidak membuatnya terlihat sebagai variabel shell tapi tidak tidak menyebabkan itu untuk diteruskan ke proses anak! Sepertinya zsh dan bash menggunakan berbagai strategi untuk mengelola variabel, dengan zsh melacak variabel non-lingkungan dan bash menyimpan segala sesuatu di lingkungannya yang disanitasi ketika meluncurkan anak (non-kulit).export FOO
dibash
?Jawaban:
Kebanyakan kerang tidak menggunakan
getenv()
/setenv()
/putenv()
API.Saat start-up, mereka membuat variabel shell untuk setiap variabel lingkungan. Itu akan disimpan dalam struktur internal yang perlu membawa informasi lain seperti apakah variabel diekspor, hanya-baca ... Mereka tidak dapat menggunakan libc
environ
untuk itu.Demikian pula, dan untuk alasan itu, mereka tidak akan menggunakan
execlp()
,execvp()
untuk mengeksekusi perintah tetapi memanggil panggilanexecve()
sistem secara langsung, menghitungenvp[]
array berdasarkan daftar variabel yang diekspor.Jadi di Anda
gdb
, Anda perlu menambahkan entri ke tabel internal variabel shell, atau mungkin memanggil fungsi yang tepat yang akan membuatnya menafsirkanexport VAR=value
kode untuk memperbaruinya sendiri.Mengapa Anda melihat perbedaan antara
bash
danzsh
ketika Anda meneleponsetenv()
digdb
, saya menduga bahwa karena Anda meneleponsetenv()
sebelum inisialisasi shell, misalnya saat memasukimain()
.Anda akan melihat
bash
'smain()
adalahint main(int argc, char* argv[], char* envp[])
(danbash
peta variabel dari env yang vars dienvp[]
) sementarazsh
' s adalahint main(int argc, char* argv[])
danzsh
mendapat variabel darienviron
sebaliknya.setenv()
tidak memodifikasienviron
tetapi tidak dapat memodifikasienvp[]
di tempat (baca-saja pada beberapa sistem serta string yang ditunjukkan oleh pointer).Dalam kasus apa pun, setelah shell membaca
environ
saat startup, menggunakansetenv()
tidak akan efektif karena shell tidak lagi menggunakanenviron
(ataugetenv()
) sesudahnya.sumber