Unix 指南/解釋/環境
每個程式都從啟動它的程式繼承“環境變數”。這意味著每個程式都具有與啟動它的程式相同的環境變數。程式的環境可以改變,在這種情況下,該程式後來啟動的其他程式也具有更改的環境。
名為SHELL的環境變數包含預設 shell 的名稱。(您可能正在執行其他 shell,但預設 shell 始終在“SHELL”中。)“SHELL”環境變數在登入時設定,並由 shell 繼承。當我們啟動“printenv”程式時,它繼承了整個環境,包括“SHELL”,並將“SHELL”顯示給我們。
在沒有引數的情況下使用printenv會給出整個環境
$ printenv ... SHELL=/bin/bash ...
參見環境變數,以瞭解有關特定變數的資訊。
每個程序對以下內容都有限制。
限制是從父程序繼承的。設定限制的正常方法是更改某些 shell 的限制,然後從該 shell 啟動程式。每個 shell 都提供不同的設定限制方法:Bourne shell 使用ulimit命令,而 C shell 使用limit。
以下是可用限制的列表,並給出它們的C shell 名稱(“Bourne shell 選項”)。我們需要名稱(“選項”)來在C(“Bourne”)shell 中顯示或更改限制。
* cputime ("-t SECONDS")
* filesize ("-f BLOCKS")
* datasize ("-n KILOBYTES")
* stacksize ("-s KILOBYTES")
* coredumpsize ("-c BLOCKS") can also accept "unlimited" instead of BLOCKS
* memoryuse ("-m KILOBYTES")
* memorylocked ("-l KILOBYTES")
* maxproc ("-p COUNT")
* openfiles ("-n COUNT")
場景:程式崩潰並顯示有關“資源暫時不可用”或“開啟的檔案過多”的訊息。
從啟動程式的 shell 中提高限制。例如,要允許每個程序開啟 512 個檔案
Bourne shell $ ulimit -Sn 512
C shell $ limit openfiles 512
可以透過 shell 的引數訪問 shell 的環境。引數有三種類型
- 命名引數
- 位置引數
- 特殊引數
命名引數被稱為環境變數。其中一些變數在使用者登入時初始化,shell 使用它們來確定其行為。shell 還將在整個登入會話中維護某些變數,其中一些變數由 shell 定義並具有特殊含義,而另一些變數可以由使用者定義。
位置引數允許引用提供給 shell 指令碼的引數。shell 透過特殊引數傳達程序資訊。使用者可以訪問特殊引數,但與命名引數和位置引數不同,它們只能由 shell 本身設定。
環境變數是命名引數。變數使用命令列語句以name=value的形式分配。變數名稱是字母數字字串,可以包含數字字元或下劃線,但必須以字母字元開頭。下面列出了四個示例
$ n=2 $ n2=4 $ N=3 $ MYNAME=alan $ greeting="hello world"
請注意,Unix 區分大小寫,因此變數“name”與“Name”不同。可以透過在變數名前加 $ 來擴充套件(求值)變數,例如
$ echo $greeting hello world
變數可以連線起來
$ day=21 month=01 year=2006 $ echo $day$month$year 21012006
但是,將文字與變數連線起來可能會出現問題,使用變量表示日期和月份,但對年份進行硬編碼會導致
$ echo $day$month2006 05
問題是 shell 無法區分變數名month和字面值 2006。因此,它嘗試擴充套件一個變數,該變數的變數名為month2006,該變數未設定。可以透過用大括號 {} 括起變數名來解決此問題,例如
$ echo ${day}${month}2006
05112006
雖然並不總是需要大括號,但在求值變數時使用大括號是一種很好的做法。
考慮以下示例,其中變數擴充套件短語用雙引號括起來
$ echo "echo $greeting", displays $greeting echo hello world, displays hello world
用雙引號括起來的變數仍然由 shell 擴充套件。要防止擴充套件,變數應使用單引號括起來。要按字面意思顯示字串“echo $greeting”,請使用以下語句
$ echo ’echo $greeting’, displays $greeting echo $greeting, displays hello world
shell 支援相當複雜的引數擴充套件。結構NAME-literal如果引數已設定,則擴充套件為引數的值,否則擴充套件為文字值。例如
$ echo ${OPSYS-unix}
unix
變數OPSYS尚未分配值,因此命令的結果是在螢幕上回顯字串“unix”。如果變數被分配一個值
$ OPSYS=Linux
$ echo ${OPSYS-unix}
Linux
如果變數設定為 NULL,則顯示空白連結而不是文字值
$ OPSYS=""
$ echo ${OPSYS-unix}
(blank line)
但是,如果我們使用name:-literal,則變數將求值為文字而不是其 NULL 值
$ echo ${OPSYS:-unix}
unix
使用結構name=literal,如果引數尚未設定,則將引數分配為文字的值。假設變數 DAY 以前未設定
$ echo $DAY (blank line)
則以下命令列將字串“tuesday”分配給變數DAY並將其回顯到螢幕
$ echo ${DAY=tuesday}
tuesday
現在變數DAY已設定,因此如果命令列用不同的文字值重複,則其值保持不變
$ echo ${DAY=wednesday}
tuesday
如果DAY分配為 NULL 值,則以下引數擴充套件將導致返回 NULL 值
$ DAY=""
$ echo ${DAY=tuesday}
(blank line)
一個相關的擴充套件結構是name-value,它只在引數未分配時返回文字,即使值為 NULL,它也返回分配的值。
使用擴充套件結構name:=literal,如果引數尚未設定,則將引數分配為文字的值。例如
$ echo $DISTRO # DISTRO not assigned
echo ${DISTRO:=ubuntu}
ubuntu
此外,如果引數為 NULL,則分配文字,因此擴充套件結果為
$ DISTRO=""
$ echo ${DISTO:=ubuntu}
ubuntu
如果引數設定為非 NULL 值,則不會分配文字
$ echo ${DISTRO:=debian}
ubuntu
擴充套件結構name=value類似於name:=value,但是僅在引數以前未分配時才分配文字。如果引數值為 NULL,則不會分配文字。使用name:?messagestring結構,如果引數未設定或為 NULL,則可以顯示錯誤訊息
$ echo ${DISTVER:?distribution version unknown}
-bash: DISTVER: distribution version unknown
$ DISTVER=""
$ echo ${DISTVER:?distribution version unknown}
-bash: DISTVER: distribution version unknown
如果引數分配了非 NULL 值,則不會顯示error訊息
$ DISTVER="hoary hedgehog"
$ echo ${DISTVER:?distribution version not set}
hoary hedgehog
同樣,還有一個相關的結構name?messagestring,它僅在引數未設定時返回訊息字串。可以將引數擴充套件為其值的子字串。擴充套件結構name%pattern和name%%pattern分別擴充套件為模式左側的最大和最小子字串。例如,設定變數TIME
$ TIME=10:29:39
以下命令列僅顯示小時值
$ echo the hours is ${TIME%%:*}
the hours is 10
而以下命令列則顯示小時和分鐘
$ echo the hour and minutes are ${TIME%:*}
the hour and minutes are 10:29
結構name#pattern和name##pattern分別擴充套件為模式右側的最大和最小子字串。因此,以下命令列擴充套件為秒
$ echo the seconds are ${TIME##*:}
the seconds are 39
分鐘和秒可以用以下命令提取
$ echo the minutes and seconds are ${TIME#*:}
the minutes and seconds are 29:39
可以使用#name結構求解字串的長度。例如
$ echo ${#TIME}
8
變數可以是一維陣列,並以name[index]的形式引用。可以使用name=(value1 value2 ... )結構分配陣列,例如
DATE=($(date))
$(command)擴充套件為命令列上command的結果。因此,DATE被分配為命令date的輸出,其中每個空格分隔的字串都被分配給陣列中的一個元素。因此,如果我們只想要年份,那麼我們將擴充套件陣列的第六個元素
$ echo ${DATE[5]}
2006
我們可以使用以下分配來更改時間資訊,例如
DATE[3]=19:16:00
$ echo ${DATE[*]}
Wed May 17 19:16:00 NZST 2006
如果我們需要統計已分配陣列元素的數量,那麼我們將使用以下表達式
$ echo ${#DATE[*]}
6
位置引數提供了一種訪問 shell 指令碼引數的方法。它們由數字 1、2、3、... 等引用,其中數字反映了引數在命令列中出現的順序(從左到右)。它們不能像命名引數那樣分配,也就是說,您不能這樣做:1=hello。當 shell 指令碼使用命令列引數呼叫時,位置引數被分配。但是,它們可以使用 set 命令分配
$ set $(uname -rmv)
這將導致uname -rmv的輸出中空格分隔的字串被分配給位置引數。以下語句顯示了所有分配的位置引數的值
$ echo ${*}
2.6.14.4 #1 SMP Thu Dec 22 01:04:35 NZDT 2005 x86_64
以下語句給出分配的位置引數的數量(相當於 C 和 C++ 中的 argc)
$ echo $# 10
如果我們特別想要核心版本,那麼我們將擴充套件位置引數 1
$ echo $1 2.6.14.4
兩位數位置引數需要用大括號括起來。因此,如果我們想要機器的體系結構,我們不能這樣做
$ echo $10 2.6.14.40
上面的表示式擴充套件為位置引數 1 後面跟一個文字 0。正確的方法是
$ echo ${10}
x86_64
最後,位置引數 0 被設定為當前程序的名稱(相當於 argv[0],在本例中應該是 shell 命令本身的名稱)
$ echo $0 -bash
使用者可以訪問特殊引數,但只能由 shell(通常在響應某些事件時)直接賦值。我們已經遇到了引數 * 和 #,它們在命令使用引數(或使用 set 命令)呼叫時被設定。
?引數擴充套件為最後退出程序的返回值。如果我們將命令列語句括在方括號中,它將在子 shell 中執行。以下命令列會派生一個新的 shell 並立即發出 exit 命令。exit 後面的引數是子 shell 的返回值(在本例中為 255)
$ (exit 255)
父程序可以透過擴充套件?來訪問子程序的返回值。如果程序正常終止,則返回值可能為零。但是,如果程序由於某種錯誤條件而終止,則如果程序設定了一個非零返回值,那麼父程序就可以確定終止的原因,這將非常有用。
$ echo $? 255
shell 的程序 ID 儲存在 $ 中。ps 命令顯示我的 shell 的程序 ID 為 10005,這與 $ 的擴充套件結果一致。
$ ps | grep bash 10005 pts/77 00:00:00 bash $ echo $$ 10005
!引數計算為最後一個後臺程序的程序 ID。為了演示,以下語句在後臺呼叫 sleep 命令(睡眠 60 秒)
$ sleep 60 & [1] 24835
後臺程序的程序 ID 會顯示在螢幕上(在本例中為 24835)。!引數的擴充套件確認了這一點。
$ echo $! 24835
程序不會從其父程序繼承環境變數,除非變數被匯出。以下命令列顯示當前程序的程序 ID,然後是 greeting 的值(之前已賦值)
$ echo ${greeting?parameter not set}
hello world
如果我們啟動一個新的 shell 並再次發出命令,我們會看到 greeting 在子程序中沒有設定。
$ bash
$ echo ${greeting?parameter not set}
bash: greeting: parameter not set
終止當前 shell 程序並返回到父程序,然後匯出 greeting。
$ exit $ export greeting
您可以透過鍵入以下內容來確認變數是否設定了 export 屬性。
$ export | grep greeting declare -x greeting="hello world"
現在再次啟動一個新的 shell 並評估 greeting。
$ bash
$ echo ${greeting?parameter not set}
hello world
新的 shell 繼承了變數 greeting 並且可以對其進行評估。即使變數被重新賦值,它也會保留其 export 屬性(直到 shell 終止),但可以使用 typeset 命令將其刪除。
$ typeset +x greeting $ export | grep greeting # yields no result
在 Bash(以及 Kornshell,但不是 Bourne shell)中,可以在一個命令列語句中分配和匯出變數。
$ export greeting="hi there" $ export | grep greeting declare -x greeting="hi there"

