Jika proses mewarisi lingkungan induk, mengapa kita perlu ekspor?

72

Saya membaca di sini bahwa tujuan dari exportsuatu shell adalah untuk membuat variabel tersedia untuk sub-proses yang dimulai dari shell.

Namun, saya juga membaca di sini dan di sini bahwa "Proses mewarisi lingkungan mereka dari orang tua mereka (proses yang memulai mereka)."

Jika ini masalahnya, mengapa kita perlu export? Apa yang saya lewatkan?

Apakah variabel shell bukan bagian dari lingkungan secara default? Apa bedanya?

Amelio Vazquez-Reina
sumber

Jawaban:

75

Asumsi Anda adalah bahwa variabel shell ada di lingkungan . Ini salah. The exportperintah apa yang mendefinisikan sebuah nama untuk berada di lingkungan sama sekali. Jadi:

a=1 b=2
export b

hasil di shell saat ini mengetahui bahwa $amemperluas ke 1 dan $bke 2, tetapi subproses tidak akan tahu apa-apa akarena itu bukan bagian dari lingkungan (bahkan di shell saat ini).

Beberapa alat yang berguna:

  • set: Berguna untuk melihat parameter shell saat ini, diekspor-atau-tidak
  • set -k: Mengatur argumen yang ditugaskan di lingkungan. Mempertimbangkanf() { set -k; env; }; f a=1
  • set -a: Memberitahu shell untuk memasukkan nama apa pun yang diatur ke lingkungan. Seperti menempatkan exportsebelum setiap tugas. Berguna untuk .envfile, seperti pada set -a; . .env; set +a.
  • export: Memberitahu shell untuk meletakkan nama di lingkungan. Ekspor dan penugasan adalah dua operasi yang sepenuhnya berbeda.
  • env: Sebagai perintah eksternal, envhanya bisa memberi tahu Anda tentang lingkungan yang diwarisi , jadi, ini berguna untuk pemeriksaan kewarasan.
  • env -i: Berguna untuk membersihkan lingkungan sebelum memulai subproses.

Alternatif untuk export:

  1. name=val command # Penugasan sebelum perintah mengekspor nama itu ke perintah.
  2. declare/local -x name # Ekspor nama, terutama berguna dalam fungsi shell ketika Anda ingin menghindari mengekspos nama ke lingkup luar.
  3. set -a # Mengekspor setiap penugasan berikut.
kojiro
sumber
3
set -kbegitu yang dapat digunakan cmd ENVVAR=valuedi tempat ENVVAR=value cmd, yang tidak akan bekerja dalam contoh Anda kecuali set -kdijalankan sebelum memohon f. Juga, tidak banyak shell yang mendukungnya saat ini dan hanya untuk kompatibilitas dengan shell Bourne. Dalam shell Bourne (atau Korn), itu tidak akan berfungsi untuk fungsi. Dan karena itu mempengaruhi penguraian shell, itu harus berlaku pada saat shell membaca kode yang menggunakannya di sana.
Stéphane Chazelas
1
Anda mungkin juga ingin menyebutkanset -a
Stéphane Chazelas
24

Ada perbedaan antara variabel shell dan variabel lingkungan. Jika Anda mendefinisikan variabel shell tanpa exportmemasukkannya, itu tidak ditambahkan ke lingkungan proses dan dengan demikian tidak diwariskan kepada anak-anaknya.

Menggunakan exportAnda memberi tahu shell untuk menambahkan variabel shell ke lingkungan. Anda dapat menguji ini menggunakan printenv(yang hanya mencetak lingkungannya stdout, karena ini adalah proses anak yang Anda lihat efek dari exportvariabel):

#!/bin/sh

MYVAR="my cool variable"

echo "Without export:"
printenv | grep MYVAR

echo "With export:"
export MYVAR
printenv | grep MYVAR
Andreas Wiese
sumber
6

Suatu variabel, setelah diekspor, adalah bagian dari lingkungan. PATHdiekspor dalam shell itu sendiri, sementara variabel khusus dapat diekspor sesuai kebutuhan. Menggunakan beberapa kode pengaturan:

$ cat subshell.sh 
#!/usr/bin/env bash
declare | grep -e '^PATH=' -e '^foo='

Membandingkan

$ cat test.sh 
#!/usr/bin/env bash
export PATH=/bin
export foo=bar
declare | grep -e '^PATH=' -e '^foo='
./subshell.sh
$ ./test.sh 
PATH=/bin
foo=bar
PATH=/bin
foo=bar

Dengan

$ cat test2.sh 
#!/usr/bin/env bash
PATH=/bin
foo=bar
declare | grep -e '^PATH=' -e '^foo='
./subshell.sh
$ ./test2.sh 
PATH=/bin
foo=bar
PATH=/bin

Karena footidak diekspor oleh shell, dan test2.shtidak pernah mengekspornya, itu bukan bagian dari lingkungan subshell.shdalam jangka terakhir.

l0b0
sumber