Shell

shell變數和環境變數在用法上有什麼區別?

  • November 20, 2019

我實際上不知道我可以從命令行訪問兩種不同類型的變數。我所知道的是,我可以聲明如下變數:

foo="my dear friends"
bar[0]="one"
bar[1]="two"
bar[2]="three"

或使用 $ 符號訪問它們,例如:

echo $foo
echo ${bar[1]}

或使用內置變數,例如:

echo $PWD
PATH=$PATH:"/usr/bin/myProg"

現在,我聽說有兩種(至少?)變數類型:shell 變數和環境變數。

  • 擁有兩種不同類型的目的是什麼?
  • 我怎麼知道變數是哪種類型?
  • 每種的典型用法是什麼?

環境變數是name=value存在於任何程序(shell、應用程序、守護程序……)中的對的列表。它們通常由子程序繼承(由fork/exec序列創建):子程序獲得自己的父變數副本。

Shell 變數確實只存在於 shell 的上下文中。它們僅在子shell 中繼承(即當shell 沒有exec操作被分叉時)。根據 shell 特性,變數可能不僅是簡單的字元串(如環境變數),還可能是數組、複合變數、類型變數(如整數或浮點數等)。

當 shell 啟動時,它從其父級繼承的所有環境變數也成為 shell 變數(除非它們作為 shell 變數和其他極端情況無效,如IFS某些 shell 重置),但這些繼承的變數被標記為 export 1。這意味著它們將保持可用於具有由 shell 設置的潛在更新值的子程序。export在 shell 下創建變數並用關鍵字標記為導出的情況也是如此。

數組和其他復雜類型變數不能被導出,除非它們的名稱和值可以轉換為name=value模式,或者當有特定於 shell 的機制時(例如:bash導出環境中的函式和一些異國情調的非 POSIX shell,例如rc並且es可以導出數組)。

因此,環境變數和 shell 變數之間的主要區別在於它們的作用域:環境變數是全域的,而非導出的 shell 變數是腳本的本地變數。

另請注意,現代 shell(至少kshand bash)支持第三個 shell 變數範圍。使用關鍵字在函式中創建的變數是該函式的typeset局部變數(聲明函式的方式在 下啟用/禁用此功能,並且持久性行為在和ksh之間是不同的)。見https://unix.stackexchange.com/a/28349/2594bash``ksh

1這適用於現代 shell,如、ksh和類似的。傳統的 Bourne shell 和非 Bourne 語法 shell具有不同的行為。dash``bash``csh

外殼變數

Shell 變數是作用域在目前 shell 會話中的變數,例如在互動式 shell 會話或腳本中。

您可以通過為未使用的名稱分配值來創建 shell 變數:

var="hello"

shell 變數的使用是為了跟踪目前會話中的數據。Shell 變數的名稱通常帶有小寫字母。

環境變數

環境變數是已導出的 shell 變數。這意味著它將作為變數可見,不僅在創建它的 shell 會話中,而且對於從該會話啟動的任何程序(不僅僅是 shell)也是可見的。

VAR="hello"  # shell variable created
export VAR   # variable now part of the environment

或者

export VAR="hello"

一旦一個 shell 變數被導出,它就會一直被導出,直到它被取消設置,或者直到它的“導出屬性”被刪除(使用export -nin bash),所以通常不需要重新導出它。取消設置變數unset會刪除它(無論它是否是環境變數)。

數組和關聯散列在bash和其他 shell 中可能不會被導出為環境變數。環境變數必須是簡單的變數,其值為字元串,並且它們的名稱通常由大寫字母組成。

環境變數的使用是為了跟踪目前 shell 會話中的數據,同時也允許任何啟動的程序獲取該數據的一部分。典型的情況是PATH環境變數,它可以在 shell 中設置,然後由任何想要啟動程序而不指定它們的完整路徑的程序使用。

程序中環境變數的集合通常被稱為“程序的環境”。每個程序都有自己的環境。

環境變數只能“轉發”,即子程序永遠不能更改其父程序中的環境變數,並且除了在啟動子程序時為子程序設置環境外,父程序不能更改子程序的現有環境子程序。

環境變數可以與env(不帶任何參數)一起列出。除此之外,它們看起來與 shell 會話中的非導出 shell 變數相同。這對於 shell 來說有點特殊,因為大多數其他程式語言通常不會將“普通”變數與環境變數混合(見下文)。

env也可用於在程序的環境中設置一個或多個環境變數的值,而無需在目前會話中設置它們:

env CC=clang CXX=clang++ make

這首先make將環境變數CC設置為 valueclangCXX設置為clang++.

它也可用於清除程序的環境:

env -i bash

這會啟動bash但不會將目前環境轉移到新bash程序(它仍然具有環境變數,因為它會從其 shell 初始化腳本創建新環境變數)。

差異範例

$ var="hello"   # create shell variable "var"
$ bash          # start _new_ bash session
$ echo "$var"   # no output
$ exit          # back to original shell session
$ echo "$var"   # "hello" is outputted
$ unset var     # remove variable

$ export VAR="hello"  # create environment variable "VAR"
$ bash
$ echo "$VAR"         # "hello" is outputted since it's exported
$ exit                # back to original shell session
$ unset VAR           # remove variable

$ ( export VAR="hello"; echo "$VAR" )  # set env. var "VAR" to "hello" in subshell and echo it
$ echo "$VAR"         # no output since a subshell has its own environment

其他語言

大多數程式語言中都有允許獲取和設置環境變數的庫函式。請注意,由於環境變數儲存為簡單的鍵值關係,它們通常不是語言的“變數”。程序可能會獲取與鍵(環境變數的名稱)相對應的值(始終是字元串),但隨後必須將其轉換為整數或語言期望值具有的任何數據類型。

在 C 中,可以使用getenv()setenv()和訪問環境變數。C 程序啟動的任何程序都以相同的方式繼承使用這些常式創建的變數。putenv()``unsetenv()

其他語言可能有特殊的資料結構來完成同樣的事情,比如%ENVPerl 中的雜湊,或者ENVIRON大多數awk.

引用自:https://unix.stackexchange.com/questions/363525