Chính xác thì biến môi trường là gì?


42

Tôi biết rằng VARIABLE=valuetạo ra một biến môi trường và export VARIABLE=valuelàm cho nó có sẵn cho các quy trình được tạo bởi trình bao hiện tại. envcho thấy các biến môi trường hiện tại, nhưng họ sống ở đâu? Điều gì bao gồm một biến môi trường (hoặc một môi trường , cho vấn đề đó)?

Câu trả lời:


29

Một môi trường không kỳ diệu như vẻ ngoài của nó. Shell lưu trữ nó trong bộ nhớ và chuyển đến execve()cuộc gọi hệ thống. Quá trình con kế thừa nó như là một con trỏ mảng được gọi environ. Từ execvetrang hướng dẫn:

TÓM TẮC

   #include <unistd.h>

   int execve(const char *filename, char *const argv[],
              char *const envp[]);

argvlà một chuỗi các chuỗi đối số được truyền cho chương trình mới.
Theo quy ước, chuỗi đầu tiên phải chứa tên tệp được liên kết với tệp đang được thực thi. envplà một chuỗi các chuỗi, theo quy ước của biểu mẫu key = value, được truyền dưới dạng môi trường cho chương trình mới.

Trang này environ(7)cũng cung cấp một số thông tin chi tiết:

TÓM TẮC

   extern char **environ;

SỰ MIÊU TẢ

Biến environchỉ đến một mảng các con trỏ tới các chuỗi được gọi là "môi trường". Con trỏ cuối cùng trong mảng này có giá trị NULL. (Biến này phải được khai báo trong chương trình người dùng, nhưng được khai báo trong tệp tiêu đề <unistd.h>trong trường hợp các tệp tiêu đề đến từ libc4 hoặc libc5 và trong trường hợp chúng đến từ glibc và _GNU_SOURCE đã được xác định.) quá trình bằng lệnh exec (3) đã bắt đầu tiến trình.

Cả hai trang GNU này đều khớp với đặc tả POSIX


4
+1 có lẽ đáng lưu ý rằng một số thành viên trong exec(3)gia đình (tức là những người không phù hợp với giám đốc điều hành * v) vượt qua ** môi trường dưới vỏ bọc.
msw

5
Lưu ý rằng đó không phải là về các tiến trình con (các tiến trình con kế thừa tất cả bộ nhớ của cha mẹ chúng), mà là các chương trình được thực thi (trong cùng một tiến trình), vì vậy đó là một cách khác để truyền dữ liệu qua một cuộc gọi hệ thống execve () nếu không sẽ xóa bộ nhớ của quá trình).
Stéphane Chazelas

@msw: Đó là các exec*ebiến thể vượt qua một env, thay vì sử dụng environbiến toàn cục. Nghĩa vlà "vectơ" và tham chiếu đến các đối số dòng lệnh được truyền dưới dạng một mảng (chứ không phải là "danh sách" (hàm có độ dài thay đổi)) execvelà một lệnh gọi hệ thống và tất cả các exec*hàm khác là các hàm bao libc cho nó.
Peter Cordes

19

Bạn đã hiểu sai một chút: SOME_NAME=valuetạo một biến shell (trong hầu hết các shell). export SOME_NAME=valuetạo ra một biến môi trường. Để tốt hơn cho điều tồi tệ hơn, hầu hết các shell Unix / Linux / * BSD sử dụng cú pháp giống hệt nhau trong việc truy cập các biến môi trường và biến shell.

Trong một số ý nghĩa lớn hơn, một "môi trường" chỉ là thông tin đi cùng với việc thực hiện chương trình. Trong các chương trình C, bạn có thể tìm thấy ID tiến trình với một getpid()cuộc gọi, trong chương trình shell bạn sẽ sử dụng quyền truy cập biến : $$. ID tiến trình chỉ là một phần của môi trường của chương trình. Tôi tin rằng thuật ngữ "môi trường" xuất phát từ một số chủ đề khoa học máy tính lý thuyết hơn, như mô hình hóa thực hiện chương trình .. Các mô hình thực hiện chương trình có một môi trường "chứa các liên kết giữa các biến và giá trị của chúng".

Và sau này, định nghĩa mạnh hơn là "môi trường" dành cho các shell BSD Unix / Linux / *: sự liên kết giữa các tên ("biến") và các giá trị của chúng. Đối với hầu hết các shell kiểu Unix, các giá trị đều là các chuỗi ký tự, mặc dù điều đó không hoàn toàn đúng như trước đây. Ksh, Zsh và Bash đều đã gõ các biến trong những ngày này. Ngay cả định nghĩa hàm shell cũng có thể được xuất.

Việc sử dụng một môi trường tách biệt với các biến shell đơn giản liên quan đến fork/execphương pháp bắt đầu một quy trình mới mà tất cả các Unix sử dụng. Khi bạn exportlà một cặp tên / giá trị, cặp tên / giá trị đó sẽ có mặt trong môi trường của các tệp thực thi mới, được bắt đầu bằng shell với một execve(2)lệnh gọi hệ thống (thường theo a fork(2), trừ khi execsử dụng lệnh shell).

Theo sau execve(), main()hàm của nhị phân mới có các đối số dòng lệnh, môi trường (được lưu trữ dưới dạng một mảng con trỏ kết thúc NULL với var=valuechuỗi, xem environ(7)trang man). Các trạng thái khác được kế thừa bao gồm các ulimitcài đặt, thư mục làm việc hiện tại và bất kỳ mô tả tệp mở nào mà execve()người gọi không có FD_CLOEXEC được đặt cho. Trạng thái hiện tại của tty (bật echo, chế độ thô, v.v.) cũng có thể được coi là một phần của trạng thái thực thi được kế thừa bởi một execquy trình mới.

Xem bashmô tả của hướng dẫn về môi trường thực thi để biết các lệnh đơn giản (ngoài các hàm dựng sẵn hoặc hàm).

Môi trường Unix khác với ít nhất một số hệ điều hành khác: VMS "từ vựng" có thể được thay đổi bởi một tiến trình con và sự thay đổi đó có thể nhìn thấy ở cha mẹ. Một VMS cdtrong một tiến trình con sẽ ảnh hưởng đến thư mục làm việc của cha mẹ. Ít nhất trong một số trường hợp, và trí nhớ của tôi có thể làm tôi thất vọng.

Một số biến môi trường đang nổi tiếng, $HOME, $PATH, $LD_LIBRARY_PATHvà những người khác. Một số thông thường cho một hệ thống lập trình nhất định, do đó, trình bao cha mẹ có thể truyền rất nhiều thông tin mục đích đặc biệt cho một số chương trình, như một thư mục tạm thời cụ thể, hoặc ID người dùng và mật khẩu không hiển thị ps -ef. Các chương trình CGI đơn giản thừa hưởng rất nhiều thông tin từ máy chủ web thông qua các biến môi trường.


1
Nó có vẻ phức tạp hơn một chút. Trong bash ít nhất SOME_NAME=value commandsẽ đặt biến môi trường SOME_NAME cho lệnh gọi đó. Một cách khó hiểu, dường như nó không đặt biến shell cùng tên.
Phường Samuel Edwin

2
Nói chính xác hơn, các biến môi trường không được kế thừa mà được truyền rõ ràng từ shell sang các chương trình mà nó sinh ra.
msw

2
@SamuelEdwinWard lý do mà SOME_NAME=value commandhành vi của bạn trái với mong đợi của bạn là vì đó là một cú pháp đặc biệt có nghĩa là "thêm SOME_NAME vào môi trường được truyền vào lệnh nhưng không làm thay đổi các biến của shell này".
msw

1
Hấp dẫn, liên kết đến lambda tính toán / lập trình chức năng. Đó là một kết nối thú vị mà rất có ý nghĩa.
Matt

1
Một số điều này không hoàn toàn đúng. Ví dụ, subshells là subprocesses và phải được fork()ed, nhưng họ làm nhận (bản sao) các biến shell.
ruakh

7

Các biến môi trường ở dạng raxi của chúng chỉ là một tập hợp các cặp tên / giá trị. Như được mô tả trong trang bash man ( man 1 bash) trong phần MÔI TRƯỜNG:

   When  a  program  is invoked it is given an array of strings called the
   environment.   This  is  a  list  of  name-value  pairs,  of  the  form
   name=value.

   The  shell  provides  several  ways  to manipulate the environment.  On
   invocation, the shell scans its own environment and creates a parameter
   for  each name found, automatically marking it for export to child pro-
   cesses.  Executed commands inherit the  environment.

Trong điều kiện thực tế, nó cho phép bạn xác định hành vi được chia sẻ hoặc duy nhất cho các chương trình được gọi từ trình bao hiện tại. Ví dụ: khi sử dụng crontabhoặc visudobạn có thể xác định EDITORbiến môi trường để xác định trình soạn thảo khác ngoài trình soạn thảo mà hệ thống của bạn sẽ sử dụng theo mặc định. Điều tương tự cũng có thể đúng đối với những thứ như manlệnh nhìn vào PAGERmôi trường của bạn để tìm ra chương trình máy nhắn tin nào nên được sử dụng để hiển thị đầu ra của trang man với.

Khá nhiều lệnh unix đọc môi trường và tùy thuộc vào những gì được đặt ở đó thay đổi đầu ra / xử lý / hành động của chúng tùy thuộc vào các lệnh này. Một số được chia sẻ, một số là duy nhất cho chương trình. Hầu hết các trang man chứa thông tin về cách biến môi trường có ảnh hưởng đến chương trình được mô tả.

Các minh họa thực tế khác dành cho những thứ như các hệ thống có nhiều bản cài đặt của Oracle trên cùng một nền tảng. Bằng cách cài đặt ORACLE_HOME, toàn bộ bộ lệnh oracle (như được tải từ PATHbiến môi trường của bạn ) sau đó kéo cài đặt, định nghĩa, ánh xạ và thư viện từ dưới thư mục cấp cao nhất đó. Điều tương tự cũng đúng với các chương trình khác như java với JAVA_HOMEbiến môi trường.

Bản thân bash có nhiều biến môi trường có thể thay đổi hành vi của một loạt các thứ từ lịch sử ( HISTSIZE, HISTFILEv.v.), kích thước màn hình ( COLUMNS), hoàn thành tab ( FIGNORE, GLOBIGNORE) ngôn ngữ và mã hóa / giải mã ký tự ( LANG, LC_*), prompt ( PS1.. PS4), và vân vân (một lần nữa tìm kiếm kiến ​​thức từ trang bash man).

Ngoài ra, bạn có thể viết các tập lệnh / chương trình sử dụng các biến môi trường tùy chỉnh của riêng bạn (để vượt qua các cài đặt hoặc thay đổi chức năng).


0

"Biến môi trường" là một tập hợp các giá trị động được đặt tên có thể ảnh hưởng đến cách các quy trình đang chạy sẽ hoạt động trên máy tính.

Chúng là một phần của môi trường hoạt động trong đó một quy trình chạy. Ví dụ, một quy trình đang chạy có thể truy vấn giá trị của biến môi trường TEMP để khám phá một vị trí phù hợp để lưu trữ các tệp tạm thời hoặc biến HOME hoặc USERPROFILE để tìm cấu trúc thư mục do người dùng chạy quy trình sở hữu.

Thêm thông tin ở đây → http://en.wikipedia.org/wiki/En Môi_variable .

Mọi thứ bạn muốn biết về Biến môi trường ...


1
Mặc dù không chắc là các liên kết này biến mất, tốt hơn là trả lời câu hỏi ở đây bằng văn bản có liên quan và cung cấp liên kết dưới dạng bổ sung cho thông tin dự phòng.
Anthon

@Anthon Tôi tin rằng bạn là chính xác và tôi sẽ thực hiện các thay đổi ngay khi tôi có thể ... Cảm ơn vì lời khuyên ...
SoCalDiegoRob

-1

Câu trả lời này đòi hỏi một số kinh nghiệm và kiến ​​thức về kịch bản shell với các thuật ngữ biến, giá trị, thay thế biến, dấu nhắc, echo, kernel, shell, tiện ích, phiên và quy trình.

Một biến môi trường (envar) là một tập hợp các biến định nghĩa toàn cầu có thể ảnh hưởng đến cách một quá trình nhất định sẽ cư xử trên hệ điều hành của máy tính.

1. Giới thiệu mẫu mực:

Chúng tôi thay thế envars bằng một chữ cái$viết hoa . Ví dụ : $PS1.

Chúng ta có thể in một envar theo cách này:

echo $PS1

$PS1giữ giá trị của dấu nhắc Unix. Nói giá trị bản địa của nó là \u \w $.

  • \u là viết tắt của người dùng (hiện tại),
  • \w là viết tắt của thư mục làm việc,
  • $ là để biên giới nhắc.

Vì vậy, nếu chúng ta làm : echo $PS1, chúng ta sẽ thấy các giá trị của \u, \wcộng với ký hiệu đô la cuối cùng.

Chúng ta có thể thay đổi hành vi Unix trong bối cảnh đó, nếu chúng ta thay đổi các giá trị của envar đó. Ví dụ:

PS1="\w >"

Bây giờ lời nhắc trông như thế này (giả sử thư mục công việc được đặt tên là "John"):

John >

Theo cách tương tự chúng ta có thể làm PS1="Hello, I'm your prompt >", vì vậy echo $PS1sẽ mang lại:

Hello, I'm your prompt >

Trong Bash 4.xx, chúng ta có thể in TẤT CẢ các envars trong hệ thống bằng envlệnh. Tôi đề nghị thực hiện envtrong thiết bị đầu cuối và xem xét đầu ra.

2. Những dữ liệu này được hiển thị và thao tác như thế nào:

Thiết bị đầu cuối của phiên chúng ta hãy tùy chỉnh các envars đi kèm với Bash.

Những thay đổi đã nói ở trên thường là tạm thời và đây là lý do:

Mỗi phiên (không phải là phiên phụ) là duy nhất và một số quy trình có thể chạy duy nhất cùng một lúc (mỗi phiên có một bộ envars riêng) nhưng thường có sự kế thừa từ phiên 0 đến phiên 1 trở lên.

Những thay đổi chúng tôi thực hiện cho một quy trình là duy nhất cho quy trình đó và sẽ chấm dứt nếu chúng tôi đóng nó mà không lưu chúng theo một cách nào đó.

Vậy làm thế nào chúng ta có thể lưu những thay đổi này:

Có một số cách có sẵn để lưu trữ các thay đổi envar, tùy thuộc vào phạm vi chúng tôi chọn. Dưới đây là các phạm vi (cấp độ) khác nhau cho những thay đổi như vậy:

  • Cấp độ quy trình: Các envars chỉ có sẵn cho các chương trình trong phiên hiện tại.
  • Mức xuất: Các envars có sẵn cho các chương trình trong phiên hiện tại hoặc tất cả các phiên phụ của nó .
  • Cấp độ toàn cầu: Các thay đổi sẽ được lưu trữ cho tất cả các phiên bất kỳ (chính và tất cả các mục phụ).

Dữ liệu envar được lưu trữ ở đâu:

Unix được xây dựng gồm 3 lớp chính: Kernel, shell và các tiện ích. AFAIK mỗi vỏ có đặc điểm riêng và chúng được chế tạo chủ yếu hoặc độc quyền trong vỏ.

Vị trí cụ thể để thay đổi toàn cầu thường là /etc/profilemặc dù chúng ta cũng có thể làm điều đó trong .bashrckhóa học.

3. Tạo envars mới:

Chúng ta có thể tạo ra những người mới và đây là một cách; kể từ Bash 4.xx, không có enavar bản địa nào được đặt tên MESSAGE(như đã nói, envars thường được đặt ở trên).

MESSAGE="Hello world!"

sẽ tạo nó cho chúng ta và bây giờ nếu chúng ta gõ echo $MESSAGE, chúng ta sẽ nhận được hello world!.

Nếu chúng tôi thực thi bashtrong phiên làm việc hiện tại (cửa sổ), chúng tôi sẽ bắt đầu một phiên phụ bash mới và sẽ không còn hoạt động trong quy trình ban đầu, trừ khi chúng tôi thực thi exit.

Lưu ý: Trong các hệ điều hành có trình giả lập thiết bị đầu cuối (như máy tính để bàn Ubuntu), phiên phụ thường chạy trên cùng một cửa sổ, nhưng phiên mới trong cửa sổ khác không phải là phiên phụ của phiên hiện có (đó là quy trình liền kề ) .

Lưu ý: Không sử dụng các dấu hiệu đặc biệt trong các giá trị envar như! hoặc họ sẽ không được cứu.

Xuất envar từ phiên ban đầu sang tất cả các phiên phụ:

Chúng ta vẫn có thể sử dụng envar được tạo trong phiên đầu tiên, trong phiên thứ hai, mà không cần đăng ký nó trong các tệp conf cấp độ người dùng hoặc toàn cầu (xem dữ liệu sau). Đây là cách để làm điều đó:

Chuyển đến phiên ban đầu (cho dù trên cửa sổ hiện tại hay khác) và thực hiện:

export MESSAGE

Khi xuất khẩu, không sử dụng $dấu hiệu.

Bây giờ nó được xuất khẩu cho tất cả các phiên phụ. Nếu bạn sẽ làm echo $MESSAGEtrong một phiên phụ, cho dù từ người dùng của bạn hay người khác, thì nó sẽ được in.

Lưu ý rằng các biến nội bộ của Shell như PS1không nên xuất, nhưng nếu bạn muốn xuất chúng từ bất kỳ lý do gì và chúng không xuất hiện, thì đừng thực hiện bashsau exportmà thay vào đó bash –norc.

4. $ PATH envar:

$PATH là envar mà người dùng thường sẽ thay đổi nhiều nhất.

Nếu chúng ta echo $PATH, chúng ta sẽ thấy luồng này:

/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games

Các giá trị in của envar này được phân tách bằng dấu hai chấm (:) ở đó, nhưng đây là một cách có khả năng thoải mái hơn (đây là các giá trị giống nhau ):

/usr/local/bin
/usr/bin
/bin
/usr/local/games
/usr/games

Đây là các direcotries để tìm kiếm, khi chúng tôi chạy một tiện ích.

Bằng cách thực thi, which echochúng ta sẽ có được vị trí tệp của nó - ví dụ, chúng ta có thể thấy nó tồn tại /bin/echo.

Dựa vào đó, chúng ta không phải gõ echo envar để xem các giá trị của evnar. Chúng tôi cũng có thể làm:

/bin/echo $ENVAR

Envar vẫn sẽ được thực thi, ví dụ:

/bin/echo $HOME

Cung cấp cho chúng tôi

/home/User || /root

Cũng như:

echo $HOME

Cung cấp cho chúng tôi

/home/User || /root

Lưu ý: $HOMEđược viết tắt là ~.

Các mối quan hệ hệ thống- $ PATH và khả năng tương tác người dùng có thể:

Trong Bash 4.xx, khi chúng tôi sử dụng một tiện ích không có đường dẫn đầy đủ, hệ thống sẽ sử dụng tất cả 6 giá trị được đề cập ở trên, của $PATHenvar. Vì vậy, nó sẽ bắt đầu từ /user/local/binvà sẽ theo tất cả nội dung của nó để tìm kiếm echotệp thực thi.

Trong trường hợp này, nó sẽ dừng lại /bin/echo, trong đó, trong trường hợp này, thực thi cư trú.

Do đó, lý do chính chúng ta có thể tùy chỉnh $PATHenvar, là cài đặt các tệp thực thi không thuộc bất kỳ giá trị gốc nào của nó.

Sau khi cài đặt các tệp thực thi như vậy, chúng ta nên đặt $PATHgiá trị của chúng cho phù hợp và sau đó chúng ta sẽ có thể làm việc với chúng.

5. Phụ lục - mở rộng $PATH:

Chúng tôi có thể export $PATHbash các phiên phụ (bao gồm các tiện ích mở rộng bash như WP-CLI cho WordPress hoặc Drush cho Drupal) theo cách này:

export PATH="/home/John:$PATH"

Điều này sẽ thêm một giá trị mới /home/Johnvào $PATH, và sau đó ngay sau đó, nó sẽ sáp nhập bất kỳ giá trị gốc nào vào nó (ngay sau dấu hai chấm), được lưu trữ theo cú pháp $PATH.

Thay đổi vĩnh viễn như vậy có thể được thực hiện trong kịch bản có liên quan, thường là dưới /etc/profilevà theo tên .bashrc.


3
Có rất nhiều sai lầm với câu trả lời này: sự kết hợp của các phiên và quy trình, cảnh báo về !một giá trị biến môi trường không hoạt động ngay bên dưới một ví dụ cho thấy nó hoạt động, một khái niệm sai về các phiên phụ, lời khuyên khá kỳ quái về những việc cần làm sau khi xuất một biến shell và một khái niệm sai về các biến môi trường toàn cầu.
JdeBP

warning about ! in an environment variable value not working that is right below an example showing it working? Xin ví dụ.
JohnDoea

quite bizarre advice about what to do after exporting a shell variable, Chính xác ý của bạn là gì?
JohnDoea

false notion of global environment variables, Chính xác ý của bạn là gì?
JohnDoea
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.