Xác định một biến có hoặc không xuất


955

Để làm gì export?

Sự khác biệt giữa:

export name=value

name=value

4
Lưu ý tiếp theo cũng export name=valuekhông phải là di động. Tùy thuộc vào chính xác những gì bạn muốn, hãy thử name=value; export namecho một giải pháp di động.
tripleee

Câu trả lời:


1054

export làm cho biến có sẵn cho các quy trình phụ.

Đó là,

export name=value

có nghĩa là tên biến có sẵn cho bất kỳ quy trình nào bạn chạy từ quy trình shell đó. Nếu bạn muốn một quy trình sử dụng biến này, hãy sử dụng exportvà chạy quy trình từ trình bao đó.

name=value

có nghĩa là phạm vi biến được giới hạn trong trình bao và không có sẵn cho bất kỳ quy trình nào khác. Bạn sẽ sử dụng điều này cho các biến vòng lặp (nói), các biến tạm thời, v.v.

Điều quan trọng cần lưu ý là việc xuất một biến không làm cho nó có sẵn cho các tiến trình cha. Đó là, việc chỉ định và xuất một biến trong một quy trình được sinh ra sẽ không làm cho nó có sẵn trong quy trình đưa ra nó.


105
Xuất cụ thể làm cho biến có sẵn cho các tiến trình con thông qua môi trường.
Beano

15
Tôi cũng nói thêm rằng nếu xuất trong một tệp mà bạn "nguồn" (như tên tệp) thì nó cũng xuất nó sang môi trường làm việc của bạn.
rogerdpack

6
@rogerdpack bạn không thể làm điều đó mà không xuất khẩu? mèo> blah \ na = hi \ n. blah; tiếng vang $ a; đầu ra 'hi' cho tôi.
David Winiecki

2
Đẹp nó làm việc ngay cả khi không xuất khẩu. Vì vậy, tôi đoán khi tìm nguồn cho một tệp, nếu bạn sử dụng xuất, nó sẽ được phản ánh trong các quy trình con, nếu bạn không làm như vậy sẽ chỉ ảnh hưởng đến môi trường bash cục bộ ...
rogerdpack

19
Có một trường hợp cạnh này; name=value command không làm cho biến có sẵn trong quy trình phụ command.
Oliver Charlesworth

254

Để minh họa những gì các câu trả lời khác đang nói:

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

9
Thêm một ví dụ cho điều nàyal$ foobar="Whatever" bash
Alun

70

Những người khác đã trả lời rằng xuất khẩu làm cho biến có sẵn cho các mạng con và điều đó đúng nhưng chỉ là tác dụng phụ. Khi bạn xuất một biến, nó đặt biến đó trong môi trường của shell hiện tại (tức là shell gọi putenv(3)hoặc setenv(3)).
Môi trường của một quá trình được kế thừa qua exec, làm cho biến có thể nhìn thấy trong các lớp con.

Chỉnh sửa (với quan điểm 5 năm): đây là một câu trả lời ngớ ngẩn. Mục đích của 'xuất khẩu' là tạo ra các biến "trong môi trường của các lệnh được thực hiện sau đó", cho dù các lệnh đó là chuỗi con hay quy trình con. Một triển khai ngây thơ sẽ chỉ đơn giản là đặt biến trong môi trường của trình bao, nhưng điều này sẽ làm cho nó không thể thực hiện được export -p.


6
Lưu ý rằng điều này không hoàn toàn đúng. Trong bash, xuất thực sự thêm biến vào môi trường của shell hiện tại, nhưng đây không phải là trường hợp với dash. Dường như với tôi rằng việc thêm biến vào môi trường của shell hiện tại là cách đơn giản nhất để thực hiện ngữ nghĩa của nó export, nhưng hành vi đó không bắt buộc.
William Pursell

7
Tôi không chắc dashphải làm gì với điều này. Các poster ban đầu được hỏi cụ thể về bash.
Sao biển

14
Câu hỏi được gắn thẻ bashnhưng áp dụng như nhau cho bất kỳ biến thể bourne-shell. Quá cụ thể và cung cấp câu trả lời chỉ áp dụng cho bashlà một tội ác lớn.
William Pursell

12
bashlà jQuery của shell.
Potherca

2
export makes the variable available to subshells, and that is correctĐây là một cách sử dụng thuật ngữ rất khó hiểu. Subshells không cần exportkế thừa các biến. Các quy trình làm.
Amit N Nikol

62

Người ta nói rằng không cần thiết phải xuất khẩu bash khi sinh ra các mạng con, trong khi những người khác nói hoàn toàn ngược lại. Điều quan trọng cần lưu ý sự khác biệt giữa subshells (những người được tạo ra bởi (), ``, $()hoặc vòng) và quy trình con (quá trình được gọi theo tên, ví dụ một chữ bashxuất hiện trong kịch bản của bạn).

  • Các shell phụ sẽ có quyền truy cập vào tất cả các biến từ cha, bất kể trạng thái xuất của chúng.
  • Các quy trình phụ sẽ chỉ nhìn thấy các biến được xuất.

Điều phổ biến trong hai cấu trúc này là không thể chuyển các biến trở lại trình bao cha.

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

Có thêm một nguồn gây nhầm lẫn: một số người nghĩ rằng các quy trình con 'rẽ nhánh' là những quy trình không thấy các biến không xuất. Thông thường các fork () ngay lập tức được theo sau bởi exec () và đó là lý do tại sao dường như fork () là thứ cần tìm, trong khi thực tế nó là exec (). Bạn có thể chạy các lệnh mà không cần fork () trước tiên bằng execlệnh và các quy trình được bắt đầu bằng phương thức này cũng sẽ không có quyền truy cập vào các biến không được báo cáo:

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

Lưu ý rằng lần này chúng ta không thấy parent:dòng này, vì chúng ta đã thay thế shell cha bằng execlệnh, vì vậy không còn gì để thực thi lệnh đó.


Tôi chưa bao giờ thấy một vòng lặp mà (tự nó) tạo ra một mạng con; OTOH một đường ống thực hiện (luôn dành cho các phần khác với phần cuối cùng, đôi khi cho phần cuối cùng tùy thuộc vào trình bao, phiên bản và tùy chọn của bạn). Bối cảnh ( &) cũng tạo ra một subshell.
dave_thndry_085

Những gì về những điều này var=asdf bash -c 'echo $var'hay var=asdf exec bash -c 'echo $var'? Đầu ra là asdf. Sự ;khác biệt nếu được đặt sau định nghĩa biến. Điều gì sẽ là lời giải thích? Có vẻ như var(không có ;) liên quan đến quá trình sinh sản bằng cách nào đó, do shell nguồn gốc không liên quan gì đến nó. echo $varkhông in gì nếu thực hiện trên dòng thứ hai. Nhưng một lót var=asdf bash -c 'echo $var'; echo $varcho asdf\nasdf.
4xy

31

export NAME=value cho các cài đặt và các biến có ý nghĩa đối với một quy trình con.

NAME=value cho các biến tạm thời hoặc vòng lặp riêng tư cho quá trình shell hiện tại.

Chi tiết hơn, exportđánh dấu tên biến trong môi trường sao chép vào một quy trình con và quy trình con của chúng khi tạo. Không có tên hoặc giá trị nào được sao chép lại từ quy trình con.

  • Một lỗi phổ biến là đặt một khoảng trắng xung quanh dấu bằng:

    $ export FOO = "bar"  
    bash: export: `=': not a valid identifier
    
  • Chỉ có biến được xuất ( B) được nhìn thấy bởi quy trình con:

    $ A="Alice"; export B="Bob"; echo "echo A is \$A. B is \$B" | bash
    A is . B is Bob
    
  • Thay đổi trong quy trình con không thay đổi vỏ chính:

    $ export B="Bob"; echo 'B="Banana"' | bash; echo $B
    Bob
    
  • Các biến được đánh dấu để xuất có các giá trị được sao chép khi quy trình con được tạo:

    $ 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
    
  • Chỉ các biến được xuất trở thành một phần của môi trường ( man environ):

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

Vì vậy, bây giờ nó phải rõ ràng như mặt trời của mùa hè! Cảm ơn Brain Agnew, alexp và William Prusell.


12

export sẽ làm cho biến có sẵn cho tất cả các shell được chia từ shell hiện tại.


11

Cần lưu ý rằng bạn có thể xuất một biến và sau đó thay đổi giá trị. Giá trị thay đổi của biến sẽ có sẵn cho các tiến trình con. Khi xuất đã được đặt cho một biến, bạn phải làm export -n <var>để xóa thuộc tính.

$ K=1
$ export K
$ K=2
$ bash -c 'echo ${K-unset}'
2
$ export -n K
$ bash -c 'echo ${K-unset}'
unset

Cảm ơn, đây chính xác là thông tin tôi đang tìm kiếm vì tôi thấy một tập lệnh sử dụng các biến môi trường và sau đó "tái xuất" chúng với giá trị mới và tôi tự hỏi liệu nó có cần thiết không.
Mike Lippert

8

Như bạn có thể đã biết, UNIX cho phép các quy trình có một tập hợp các biến môi trường, là các cặp khóa / giá trị, cả khóa và giá trị là các chuỗi. Hệ điều hành có trách nhiệm giữ các cặp này cho mỗi quy trình riêng biệt.

Chương trình có thể truy cập các biến môi trường của nó thông qua API UNIX này:

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

Các quy trình cũng kế thừa các biến môi trường từ các quy trình cha. Hệ điều hành chịu trách nhiệm tạo một bản sao của tất cả các "envars" tại thời điểm tiến trình con được tạo.

Bash , trong số các shell khác, có khả năng thiết lập các biến môi trường theo yêu cầu của người dùng. Đây là những gì exporttồn tại cho.

exportlà một lệnh Bash để đặt biến môi trường cho Bash. Tất cả các biến được thiết lập bằng lệnh này sẽ được kế thừa bởi tất cả các quy trình mà Bash này sẽ tạo.

Thêm về môi trường ở Bash

Một loại biến khác trong Bash là biến nội bộ. Vì Bash không chỉ là vỏ tương tác, nên trên thực tế nó là một trình thông dịch kịch bản, như bất kỳ trình thông dịch nào khác (ví dụ Python), nó có khả năng giữ tập hợp các biến của riêng nó. Cần phải đề cập rằng Bash (không giống như Python) chỉ hỗ trợ các biến chuỗi.

Ký hiệu để xác định các biến Bash là name=value. Các biến này nằm trong Bash và không liên quan gì đến các biến môi trường được giữ bởi hệ điều hành.

Thông tin thêm về Shell Tham số (bao gồm các biến)

Cũng đáng lưu ý rằng, theo hướng dẫn tham khảo Bash:

Môi trường cho bất kỳ lệnh hoặc hàm đơn giản nào có thể được tăng cường tạm thời bằng cách thêm tiền tố vào nó bằng các phép gán tham số, như được mô tả trong Shell Paramameter . Các câu lệnh gán này chỉ ảnh hưởng đến môi trường mà lệnh đó nhìn thấy.


Để tổng hợp mọi thứ:

  • exportđược sử dụng để đặt biến môi trường trong hệ điều hành. Biến này sẽ có sẵn cho tất cả các quy trình con được tạo bởi quy trình Bash hiện tại mãi mãi về sau.
  • Ký hiệu biến Bash (name = value) được sử dụng để đặt các biến cục bộ chỉ khả dụng cho quy trình bash hiện tại
  • Ký hiệu biến Bash tiền tố một lệnh khác tạo biến môi trường chỉ cho phạm vi của lệnh đó.

1
bash vars không hỗ trợ nhiều loại như Python, nhưng có chuỗi, số nguyên và hai loại mảng ('được lập chỉ mục' / truyền thống và 'kết hợp' tương tự như mảng awk, hàm băm perl hoặc dict Python). Vỏ khác thay đổi; chuỗi duy nhất là di động .
dave_thndry_085

7

Các câu trả lời được chấp nhận hàm ý này, nhưng tôi muốn làm sáng tỏ những kết nối đến builtins vỏ:

Như đã đề cập, exportsẽ làm cho một biến có sẵn cho cả vỏ và trẻ em. Nếu exportkhông được sử dụng, biến sẽ chỉ sẵn có trong vỏ, và chỉ có vỏ builtins có thể truy cập vào nó.

Đó là,

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

3

Đây là một ví dụ khác:

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}"'  

Chỉ bằng cách sử dụng xuất VARTEST, giá trị của VARTEST mới khả dụng trong sudo bash -c '...'!

Để biết thêm ví dụ, xem:


3

Hai trong số những người tạo ra UNIX, Brian Kernighan và Rob Pike, giải thích điều này trong cuốn sách "Môi trường lập trình UNIX" của họ. Google cho tiêu đề và bạn sẽ dễ dàng tìm thấy phiên bản pdf.

Chúng giải quyết các biến shell trong phần 3.6 và tập trung vào việc sử dụng exportlệnh ở cuối phần đó:

Khi bạn muốn làm cho giá trị của một biến có thể truy cập được trong các khung con, nên sử dụng lệnh xuất của shell. (Bạn có thể nghĩ về lý do tại sao không có cách nào để xuất giá trị của biến từ vỏ phụ sang mẹ của nó).


2

Chỉ để hiển thị sự khác biệt giữa một biến được xuất trong môi trường (env) và biến không xuất trong môi trường:

Nếu tôi làm điều này:

$ MYNAME=Fred
$ export OURNAME=Jim

sau đó chỉ $ OURNAME xuất hiện trong env. Biến $ MYNAME không có trong env.

$ env | grep NAME
OURNAME=Jim

nhưng biến $ MYNAME không tồn tại trong trình bao

$ echo $MYNAME
Fred

1

Theo mặc định, các biến được tạo trong một tập lệnh chỉ có sẵn cho trình bao hiện tại; các tiến trình con (shell con) sẽ không có quyền truy cập vào các giá trị đã được đặt hoặc sửa đổi. Cho phép các tiến trình con để xem các giá trị, yêu cầu sử dụng lệnh xuất.


0

Mặc dù không được đề cập rõ ràng trong cuộc thảo luận, KHÔNG cần phải sử dụng xuất khi sinh ra một lớp con từ bên trong bash vì tất cả các biến được sao chép vào tiến trình con.


Hãy giải thích như những gì bạn đang nói dường như mâu thuẫn trực tiếp với các câu trả lời w / ví dụ ở trên.
Mike Lippert

Đây là cách phù hợp nếu bạn không muốn các biến được xuất ra trên toàn cầu nhưng chỉ có sẵn cho quy trình con! Cảm ơn bạn.
jtblin
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.