Mendefinisikan variabel dengan atau tanpa ekspor

955

Untuk apa export?

Apa perbedaan antara:

export name=value

dan

name=value
flybywire
sumber
4
Perhatikan juga bahwa export name=valueitu tidak portabel. Bergantung pada apa yang Anda inginkan, cobalah name=value; export namesolusi portabel.
tripleee

Jawaban:

1054

export membuat variabel tersedia untuk sub-proses.

Itu adalah,

export name=value

berarti bahwa nama variabel tersedia untuk setiap proses yang Anda jalankan dari proses shell itu. Jika Anda ingin suatu proses memanfaatkan variabel ini, gunakanexport , dan jalankan proses dari shell itu.

name=value

berarti ruang lingkup variabel dibatasi untuk shell, dan tidak tersedia untuk proses lain. Anda akan menggunakan ini untuk (katakanlah) variabel loop, variabel sementara dll.

Penting untuk dicatat bahwa mengekspor variabel tidak membuatnya tersedia untuk proses induk. Artinya, menentukan dan mengekspor variabel dalam proses spawned tidak membuatnya tersedia dalam proses yang diluncurkan itu.

Brian Agnew
sumber
105
Secara khusus ekspor membuat variabel tersedia untuk proses anak melalui lingkungan.
Beano
15
Saya juga akan menambahkan bahwa jika ekspor ada dalam file yang Anda "sumber" (seperti nama file) maka itu ekspor ke lingkungan kerja Anda juga.
rogerdpack
6
@rogerdpack tidak bisakah Anda melakukannya tanpa ekspor? cat> blah \ na = hi \ n. bla; echo $ a; output 'hai' untuk saya.
David Winiecki
2
Bagus itu bekerja bahkan tanpa ekspor. Jadi saya kira ketika sumber file, jika Anda menggunakan ekspor itu akan tercermin dalam proses anak, jika Anda tidak itu hanya akan mempengaruhi lingkungan bash lokal ...
rogerdpack
19
Ada satu kasus tepi untuk ini; name=value command tidak membuat variabel tersedia di sub-proses command.
Oliver Charlesworth
254

Untuk menggambarkan apa yang dikatakan jawaban lain:

$ foo="Hello, World"
$ echo $foo
Hello, World
$ bar="Goodbye"
$ export foo
$ bash
bash-3.2$ echo $foo
Hello, World
bash-3.2$ echo $bar

bash-3.2$ 
alxp
sumber
9
Satu lagi contoh untuk inial$ foobar="Whatever" bash
Alun
70

Yang lain telah menjawab bahwa ekspor membuat variabel tersedia untuk subkulit, dan itu benar tetapi hanya efek samping. Ketika Anda mengekspor variabel, itu menempatkan variabel itu di lingkungan shell saat ini (yaitu shell panggilan putenv(3)atau setenv(3)).
Lingkungan suatu proses diwariskan di eksekutif, membuat variabel terlihat dalam subkulit.

Sunting (dengan perspektif 5 tahun): ini adalah jawaban konyol. Tujuan dari 'ekspor' adalah untuk membuat variabel "berada di lingkungan perintah yang dieksekusi selanjutnya", apakah perintah itu adalah subkulit atau subproses. Implementasi yang naif adalah dengan hanya menempatkan variabel di lingkungan shell, tetapi ini akan membuatnya tidak mungkin untuk diimplementasikan export -p.

William Pursell
sumber
6
Perhatikan bahwa ini tidak sepenuhnya benar. Dalam bash, ekspor memang menambahkan variabel ke lingkungan shell saat ini, tetapi tidak demikian halnya dengan dash. Sepertinya saya bahwa menambahkan variabel ke lingkungan shell saat ini adalah cara paling sederhana untuk mengimplementasikan semantik export, tetapi perilaku itu tidak diamanatkan.
William Pursell
7
Saya tidak yakin apa yang dashharus dilakukan dengan ini. Poster asli bertanya secara spesifik tentang bash.
Starfish
14
Pertanyaannya ditandai bashtetapi berlaku sama untuk varian bourne-shell. Menjadi terlalu spesifik dan memberikan jawaban yang hanya berlaku untuk bashadalah kejahatan besar.
William Pursell
12
bashadalah jQuery of the shell.
Potherca
2
export makes the variable available to subshells, and that is correctIni adalah penggunaan terminologi yang sangat membingungkan. Subshell tidak perlu exportmewarisi variabel. Subproses lakukan.
Amit Naidu
62

Dikatakan bahwa tidak perlu untuk mengekspor dalam bash ketika menelurkan subkulit, sementara yang lain mengatakan sebaliknya. Hal ini penting untuk dicatat perbedaan antara subkulit (orang-orang yang diciptakan oleh (), ``, $()atau loop) dan subproses (proses yang dipanggil dengan nama, misalnya literal bashmuncul dalam naskah Anda).

  • Sub kerang akan memiliki akses ke semua variabel dari orangtua, terlepas dari negara mereka diekspor.
  • Sub proses hanya akan melihat variabel yang diekspor.

Apa yang umum dalam dua konstruksi ini adalah bahwa tidak ada yang dapat meneruskan variabel kembali ke shell induk.

$ noexport=noexport; export export=export; (echo subshell: $noexport $export; subshell=subshell); bash -c 'echo subprocess: $noexport $export; subprocess=subprocess'; echo parent: $subshell $subprocess
subshell: noexport export
subprocess: export
parent:

Ada satu lagi sumber kebingungan: beberapa orang berpikir bahwa subproses 'bercabang' adalah yang tidak melihat variabel yang tidak diekspor. Biasanya fork () langsung diikuti oleh exec (), dan karena itulah tampaknya fork () adalah hal yang harus dicari, padahal sebenarnya itu adalah exec (). Anda dapat menjalankan perintah tanpa fork () terlebih dahulu dengan execperintah, dan proses yang dimulai dengan metode ini juga tidak akan memiliki akses ke variabel yang tidak diekspor:

$ noexport=noexport; export export=export; exec bash -c 'echo execd process: $noexport $export; execd=execd'; echo parent: $execd
execd process: export

Perhatikan bahwa kita tidak melihat parent:garis kali ini, karena kita telah mengganti shell induk dengan execperintah, jadi tidak ada yang tersisa untuk mengeksekusi perintah itu.

Matyas Koszik
sumber
Saya belum pernah melihat loop yang (dengan sendirinya) membuat subkulit; OTOH tidak seperti pipa (selalu untuk potongan selain yang terakhir, kadang-kadang untuk yang terakhir tergantung pada shell, versi, dan opsi Anda). Backgrounding ( &) juga membuat subkulit.
dave_thompson_085
Bagaimana dengan ini var=asdf bash -c 'echo $var'atau var=asdf exec bash -c 'echo $var'? Outputnya adalah asdf. The ;membuat perbedaan jika ditempatkan setelah definisi variabel. Apa penjelasannya? Sepertinya var(tanpa ;) salam untuk menelurkan subproses entah bagaimana, karena shell asal tidak ada hubungannya dengan itu. echo $vartidak mencetak apa pun jika dijalankan pada baris kedua. Tapi satu berjajar var=asdf bash -c 'echo $var'; echo $varmemberi asdf\nasdf.
4xy
31

export NAME=value untuk pengaturan dan variabel yang memiliki arti ke suatu subproses.

NAME=value untuk variabel sementara atau loop pribadi ke proses shell saat ini.

Secara lebih rinci, exporttandai nama variabel di lingkungan yang menyalin ke subproses dan subproses mereka saat pembuatan. Tidak ada nama atau nilai yang pernah disalin kembali dari subproses.

  • Kesalahan umum adalah menempatkan spasi di sekitar tanda sama dengan:

    $ export FOO = "bar"  
    bash: export: `=': not a valid identifier
  • Hanya variabel yang diekspor ( B) yang dilihat oleh subproses:

    $ A="Alice"; export B="Bob"; echo "echo A is \$A. B is \$B" | bash
    A is . B is Bob
  • Perubahan pada subproses tidak mengubah shell utama:

    $ export B="Bob"; echo 'B="Banana"' | bash; echo $B
    Bob
  • Variabel yang ditandai untuk ekspor memiliki nilai yang disalin ketika subproses dibuat:

    $ export B="Bob"; echo '(sleep 30; echo "Subprocess 1 has B=$B")' | bash &
    [1] 3306
    $ B="Banana"; echo '(sleep 30; echo "Subprocess 2 has B=$B")' | bash 
    Subprocess 1 has B=Bob
    Subprocess 2 has B=Banana
    [1]+  Done         echo '(sleep 30; echo "Subprocess 1 has B=$B")' | bash
  • Hanya variabel yang diekspor yang menjadi bagian dari lingkungan ( man environ):

     $ ALICE="Alice"; export BOB="Bob"; env | grep "ALICE\|BOB"
     BOB=Bob

Jadi, sekarang harus sejelas matahari musim panas! Terima kasih untuk Brain Agnew, alexp, dan William Prusell.

Charles Merriam
sumber
12

export akan membuat variabel tersedia untuk semua shell yang bercabang dari shell saat ini.

John T
sumber
11

Perlu dicatat bahwa Anda dapat mengekspor variabel dan kemudian mengubah nilainya. Nilai variabel yang berubah akan tersedia untuk proses anak. Setelah ekspor ditetapkan untuk variabel, Anda harus melakukan export -n <var>untuk menghapus properti.

$ K=1
$ export K
$ K=2
$ bash -c 'echo ${K-unset}'
2
$ export -n K
$ bash -c 'echo ${K-unset}'
unset
Brian S. Wilson
sumber
Terima kasih, ini persis informasi yang saya cari karena saya melihat skrip yang menggunakan variabel lingkungan dan kemudian "diekspor kembali" mereka dengan nilai baru, dan saya bertanya-tanya apakah itu perlu.
Mike Lippert
8

Seperti yang mungkin sudah Anda ketahui, UNIX memungkinkan proses untuk memiliki satu set variabel lingkungan, yang merupakan pasangan kunci / nilai, baik kunci dan nilai menjadi string. Sistem operasi bertanggung jawab untuk menjaga pasangan ini untuk setiap proses secara terpisah.

Program dapat mengakses variabel lingkungannya melalui API UNIX ini:

  • char *getenv(const char *name);
  • int setenv(const char *name, const char *value, int override);
  • int unsetenv(const char *name);

Proses juga mewarisi variabel lingkungan dari proses induk. Sistem operasi bertanggung jawab untuk membuat salinan dari semua "envars" pada saat proses anak dibuat.

Bash , di antara shell lainnya, mampu mengatur variabel lingkungannya berdasarkan permintaan pengguna. Inilah yang exportada untuk.

exportadalah perintah Bash untuk mengatur variabel lingkungan untuk Bash. Semua variabel yang diatur dengan perintah ini akan diwarisi oleh semua proses yang akan dibuat oleh Bash ini.

Lebih lanjut tentang Lingkungan di Bash

Jenis variabel lain dalam Bash adalah variabel internal. Karena Bash bukan hanya shell interaktif, ia sebenarnya adalah juru bahasa skrip, seperti juru bahasa lain (misalnya Python) yang mampu menyimpan serangkaian variabelnya sendiri. Harus disebutkan bahwa Bash (tidak seperti Python) hanya mendukung variabel string.

Notasi untuk mendefinisikan variabel Bash adalah name=value. Variabel-variabel ini tetap berada di dalam Bash dan tidak ada hubungannya dengan variabel lingkungan yang disimpan oleh sistem operasi.

Lebih lanjut tentang Parameter Shell (termasuk variabel)

Juga patut dicatat bahwa, menurut manual referensi Bash:

Lingkungan untuk setiap perintah atau fungsi sederhana dapat ditambah sementara dengan mengawalinya dengan penetapan parameter, seperti yang dijelaskan dalam Parameter Shell . Pernyataan penugasan ini hanya memengaruhi lingkungan yang dilihat oleh perintah itu.


Singkatnya:

  • exportdigunakan untuk mengatur variabel lingkungan dalam sistem operasi. Variabel ini akan tersedia untuk semua proses anak yang dibuat oleh proses Bash saat ini selamanya.
  • Notasi variabel Bash (nama = nilai) digunakan untuk mengatur variabel lokal yang tersedia hanya untuk proses bash saat ini
  • Notasi variabel Bash, awalan perintah lain, menciptakan variabel lingkungan hanya untuk cakupan perintah itu.
progalgo
sumber
1
bash vars tidak mendukung jenis sebanyak Python, tetapi memiliki string, integer, dan dua jenis array ('diindeks' / tradisional dan 'asosiatif' yang mirip dengan awk array, perl hash, atau Python dict). Kerang lain bervariasi; hanya string yang portabel .
dave_thompson_085
7

The jawaban yang diterima menyiratkan ini, tapi aku ingin membuat eksplisit koneksi ke builtin shell:

Seperti yang sudah disebutkan, exportakan membuat variabel tersedia untuk shell dan anak-anak. Jika exportini tidak digunakan, variabel hanya akan tersedia di shell, dan hanya shell builtin dapat mengaksesnya.

Itu adalah,

tango=3
env | grep tango # prints nothing, since env is a child process
set | grep tango # prints tango=3 - "type set" shows `set` is a shell builtin
flow2k
sumber
3

Ini contoh lain:

VARTEST="value of VARTEST" 
#export VARTEST="value of VARTEST" 
sudo env | grep -i vartest 
sudo echo ${SUDO_USER} ${SUDO_UID}:${SUDO_GID} "${VARTEST}" 
sudo bash -c 'echo ${SUDO_USER} ${SUDO_UID}:${SUDO_GID} "${VARTEST}"'  

Hanya dengan menggunakan ekspor VARTEST, nilai VARTEST tersedia di sudo bash -c '...'!

Untuk contoh lebih lanjut, lihat:


sumber
3

Dua pencipta UNIX, Brian Kernighan dan Rob Pike, menjelaskan hal ini dalam buku mereka "Lingkungan Pemrograman UNIX". Google untuk judul dan Anda akan dengan mudah menemukan versi pdf.

Mereka membahas variabel shell di bagian 3.6, dan fokus pada penggunaan exportperintah di akhir bagian itu:

Ketika Anda ingin membuat nilai variabel dapat diakses di sub-shell, perintah ekspor shell harus digunakan. (Anda mungkin berpikir mengapa tidak ada cara untuk mengekspor nilai variabel dari sub-shell ke induknya).

Dan Carter
sumber
2

Hanya untuk menunjukkan perbedaan antara variabel yang diekspor berada di lingkungan (env) dan variabel yang tidak diekspor yang tidak berada di lingkungan:

Jika saya melakukan ini:

$ MYNAME=Fred
$ export OURNAME=Jim

maka hanya $ OURNAME yang muncul di env. Variabel $ MYNAME tidak ada dalam env.

$ env | grep NAME
OURNAME=Jim

tetapi variabel $ MYNAME ada di shell

$ echo $MYNAME
Fred
Akan
sumber
1

Secara default, variabel yang dibuat dalam skrip hanya tersedia untuk shell saat ini; proses anak (sub-shell) tidak akan memiliki akses ke nilai yang telah ditetapkan atau dimodifikasi. Mengizinkan proses anak untuk melihat nilai-nilai, membutuhkan penggunaan perintah ekspor.

Amjad
sumber
0

Meskipun tidak secara eksplisit disebutkan dalam diskusi, TIDAK perlu menggunakan ekspor ketika memunculkan subkulit dari dalam bash karena semua variabel disalin ke dalam proses anak.

Scott
sumber
Tolong jelaskan apa yang Anda katakan tampaknya bertentangan langsung dengan jawaban di atas.
Mike Lippert
Ini adalah cara yang tepat jika Anda tidak ingin variabel diekspor secara global tetapi hanya tersedia untuk subproses! Terima kasih.
jtblin