shell环境变量
shell環境變量??
環境變量?
還記得上一章里面﹐我曾經提到過﹕當我們登入系統的時候﹐首先就獲得一 shell﹐而且它也占據一個行程(進程)﹐然后再輸入的命令都屬于這個 shell 的子程序(子進程)。如果您學習夠細心﹐不難發現我們的 shell 都在 /etc/passwd 這個檔里面設定的﹐也就是賬號設定的最后一欄﹐預設是 /bin/bash 。?
事實上﹐當我們獲得一個 shell 之后﹐我們才真正能和系統溝通﹐例如輸入您的命令﹑執行您的程序﹑等等。您也可以在獲得一個 shell 之后﹐再進入另外一個 shell (也就是啟動一個子程序)﹐然后還可以再進入更深一層的 shell (再進入子程序的子程序)﹐直到您輸入 exit 才退回到上一個 shell 里面(退回上一級的父程序)。假如您已經閱讀過上一章所說過的子程序概念﹐應該不難理解。不過﹐您的行為也不是無限制的﹐而且﹐有許多設定都必須事先得到 定義。所以﹐當您獲得 shell 的時候﹐同時也獲得一些環境設定﹐或稱為“環境變量( Environmentvariables)”。?
所謂的?變量( variable )﹐ 就是用特定的名稱(或標簽)保存一定的設定值﹐然后供程序將來使用。例如﹐姓=chen ﹔名=kenny ﹐那么‘姓’和‘名’就是變量名稱﹐而 chen 和 kenny 就是變量所保存的值。由 shell 所定義和管理的變量﹐我們稱為環境變量﹐因為這些變量可以供 shell 所產生的所有子程序使用。環境變量名稱一般都用大寫字母表示﹐例如﹐我們常用的環境變量有這些﹕?
(注:也就是說環境變量,就是供shell所產生的所有子進程使用的變量)
變量名稱
代表意思
HISTCMD
當前命令的記錄編號。
HISTFILE
命令記錄表之存放檔案。
HISTSIZE
命令記錄表體積。
HOME
默認登錄家目錄。
IFS
預設分隔符。
LINENO
當前命令在 shell script 中的行數。
MAIL
郵件信箱的路徑。
MAILCHECK
檢查郵件的秒數。
OLDPWD
上次進入的目錄路徑。
OSTYPE
操作系統類型。
PATH
默認命令搜索路徑。
PPID
父程序之 PID。
PWD
當前工作目錄路徑。
SECONDS
當前 shell 之持續啟動時間。
SHELL
當前 shell 之執行路徑。
TMOUT
自動注銷之最高閑置時間。
UID
使用者之 UID。
$
當前 shell 之 PID。
﹖
最后一個命令之返回狀態。
假如您想看看這些變量值是什么﹐只要在變量名稱前面加上一個“$”符號﹐然后用?echo?命令來查看就可以了﹕?
#?echo$PWD?
/root?
#?echo $$?
1206?
#?echo $??
0?
第一個命令就是將當前目錄的路徑顯示出來﹐和您執行 pwd 命令的結果是一樣的﹔第二個命令將當前這個 shell 的 PID 顯示出來﹐也就是 1206。如果您這時候輸入 kill -9 1206 的話﹐會將當前的 shell 砍掉﹐那您就要重新登錄才能獲得另外一個 shell﹐而它的 PID 也是新的﹔第三行命令是上一個命令的返回狀態﹕如果命令順利執行﹐并沒有錯誤﹐那通常是 0﹔如果命令遇到錯誤﹐那返回狀態則是非 0 ﹐其值視程序設計者而定(我們在后面的 shell script 的時候會介紹)。關于最后一個命令﹐不妨比較一下如下結果﹕?
#?ls mbox?
mbox?
#?echo $??
0?
#?ls no_mbox?
ls: no_mbox: No such file or directory?
#?echo $??
1?
您會發現﹕第一命令成功執行﹐所以其返回狀態是 0 ﹔而第二個命令執行失敗﹐其返回狀態是 1 。假如程序設計者為不同的錯誤設定不同的返回狀態等級﹐那您可以根據返回值推算出問題是哪種錯誤引起的。?
Tips﹕如果您日后寫程序或 script﹐要養成一個習慣﹐為每一種命令結果設定返回狀態。這非常重要﹐尤其在進行 debug 的時候。這個我們在后面學習 script 的時候再談。?(這點很重要要引起重視!)
我們隨時都可以用一個?= (等號)?來定義一個新的變量或改變一個原有變量。例如﹕?
#?MYNAME=kenny?
#?echo $MYNAME?
kenny?
假如您要取消一個定義好的變量﹐那么﹐您可以使用?unset?命令﹕?
#?unset MYNAME?
不過﹐環境變量的特性之一﹐是單向輸出的。也就是說﹕一個 shell 的特定變量﹐只能在這個 shell 里面使用。如果您要分享給同一個 shell 里面的其它程序﹑script﹑命令使用﹐或它們的子程序使用﹐那您必須用?export?命令將這個變量進行輸出。但無論如何﹐如果您在一個子程序中定義了一個變量﹐那么這個變量的值﹐只影響這個子程序本身以及它自己的子程序﹐而永遠不會影像到父程序或父程序產生的其它子程序。?(這也正是我們通常用用export命令修改PATH路徑的原因)
比方說﹐您在一個程序中定義一個新的變量﹐或改變一個原有變量值﹐在程序結束的時候﹐那它所設定的變量均被取消﹔如果您想將變量值分享給該程序所產生的子 程序﹐您必須用 export 命令才能保留這個變量值﹐除非子程序另外重新定義。但無論如何﹐當前程序所定義的變量值﹐是無法傳回父程序那邊的。不妨做做如下的實驗﹕?
#?MYNAME=kenny?
#?echo $MYNAME?
kenny?
#?export MYNAME?
# 設定一個變量。?
#?
# 當前的設定值。?
# 用 export 輸出變數值。
#?/bin/bash?
# 再開一個 shell﹐也就是進入子程序中。
#?echo $MYNAME?
kenny?
#?
# 保留原有設定值。
#?export MYNAME=netman?
#?echo $MYNAME?
netman?
# 重新定義設定值﹐同時也用 export 輸出。?
#?
# 變數值被新值取代。?
#?exit?
# 退出子程序﹐返回父程序。?
#?echo $MYNAME?
kenny?
#?
# 父程序的變量值并沒有改變。
關于變量的另一個特性﹐是的變量值是可以繼承的。也就是說﹐您可以將一個變量值來設定另外一個變量名稱。比方說﹕?
#?FIRST_NAME="Kenny"?
#?MYNAME=$FIRST_NAME
#?echo $MYNAME?
Kenny
# 定義一個變量。?
# 再定義另一個變量﹐但它的值是第一個變數。
#?
# 第二個變量繼承了第一個變數的值。?
另外﹐在定義變量的時候您還要注意一些規則﹕?
?
·????????定義變量時﹐“=”號兩邊沒有空格鍵﹔?
·????????作為變量的名稱﹐只能是字母和數字﹐但不能以數字開頭﹔如果名稱太長﹐可以用“_”分隔﹔?
·????????預先定義的變量均為大寫﹐自定義變量可以混合大小寫﹐以更好區別﹔?
·????????只有 Shell 本身定義的變量才能稱為環境變量;?
·????????如果變量中帶有特殊字符﹐必須先行用“\”符號跳脫﹔?
·????????如果變量中帶有空白﹐必須使用引號﹐或進行跳脫。
關于后兩項﹐或許我們再找些例子來體會一下﹕?
#?TOPIC='Q& A'
# 用單引號保留特殊符號和空白?
#?Q1=What\'s\your\ \"topic\"\?
#?echo $Q1?
What's your "topic"?
?
# 用 \ 將特殊符號(含引號)和空白跳脫出來?
#?
# 跳脫后﹐特殊符號和空白都保留下來。?
#?ANS="Itis $TOPIC."??????????------這個地方引起注意:雙引號中字符串可以引用變量!
#?echo $ANS?????????????????????????------這種用法比較常見,而下面的單引號的情況賓不常見。
It is Q & A.
?
# 用雙引號保留變數值($)?
#?
# 用雙引號﹐顯示出變量值。?
#?WRONG_ANS='Itis "$TOPIC".'?????????????????????-----注意單、雙引號的合理使用
#?echo $WRONG_ANS?
It is "$TOPIC".
?
# 用單引號保留特殊符號和空白(同第一行)?
#?
#?用單引號﹐全部保留﹔同時﹕?
# $ 也當成一般符號保留﹐而非變量值。??????????????------這個地方引起注意,單引號時$當成一般符號保留!
#?ALT_ANS='the $TOPIC'\ is\ "'$TOPIC'"\.?? ------混合了單、雙引號有助于理解。
#?echo $ALT_ANS?
The $TOPIC is 'Q & A'.
# 同時混合單引號﹑雙引號﹑和跳脫字符 \?
#?
# 單引號保留全部﹔雙引號保留變數值﹔?
# \ 將特殊符號跳脫出來。?
我這里解釋一下最后面的例子好了﹕'the $TOPIC is '"$TOPIC"\.。首先用單引號將 'the $TOPIC is ' 這段文字括好﹐其中用 3 個空格鍵和一個 $ 符號﹔然后用雙引號保留 $TOPIC 的變量值﹔最后用 \ 跳脫小數點。?
在引用 " " 和 ' ' 符號的時候﹐基本上﹐ ' ' 所包括的內容﹐會變成單一的字符串﹐任何特殊字符都失去其特殊的功能﹐而變成一般字符而已﹐但其中不能再使用 ' 符號﹐而在 " " 中間﹐則沒有 ' ' 那么嚴格﹐某些特殊字符﹐例如 $ 號﹐仍然保留著它特殊的功能。您不妨實作一下﹐比較看看 echo ' "$HOME" ' 和 echo " '$HOME' " 的差別。?
Tips﹕在 shell 命令行的跳脫字符“ \ ”其實我們會經常用到的。例如﹐您的一個命令太長﹐一直打下去可能超過一行﹐或是想要整潔的輸入命令行﹐您或許想按 Enter 鍵敲到下一行繼續輸入。但是﹐當您敲 Enter 鍵的時候﹐事實上是輸入一個 CR(Carriage-Return) 字符﹐一但 shell 讀到 CR 字符﹐就會嘗試執行這個命令。這時﹐您就可以在輸入 Enter 之前先輸入 \ 符號﹐就能將 CR 字符也跳脫出來﹐這樣 shell 就不會馬上執行命令了。這樣的命令行﹐我們在 script 中經常看到﹐但您必須知道那代表什么意思。?
*對變量值進行過濾:
如果﹐您想對一些變量值進行過濾﹐例如﹕MY_FILE=' ~/tmp/test.sh' ﹐而您想將變數值換成 test.sh (也就是將前面的路徑去掉)﹐那您可以將 $MY_FILE 換成?${MY_FILE##*/}。這是一個變量值字符串過濾﹕## 是用來比對變量前端部份﹐然后 */ 是比對的色樣 (也就是任何字母到 / 之間)﹐然后將最長的部份刪除掉。您可以參考如下范例﹕?
當 FNAME="/home/kenny/tmp/test.1.sh" 的時候﹕?
變量名稱
${FNAME}
顯示變量值的全部。
/home/kenny/tmp/test.1.sh
${FNAME##/*/}
比對變量值開端﹐如果以 /*/ 開頭的話﹐砍掉最長的部份。
? ?? ?? ?? ?? ? test.1.sh
${FNAME#/*/}
比對變量值開端﹐如果以 /*/ 開頭的話﹐砍掉最短的部份。
? ?? ?kenny/tmp/test.1.sh
${FNAME%.*}
比對變量值末端﹐如果以 .* 結尾的話﹐砍掉最短的部份。
/home/kenny/tmp/test.1? ?
${FNAME%%.*}
比對變量值末端﹐如果以 .* 結尾的話﹐砍掉最長的部份。
/home/kenny/tmp/test? ???
${FNAME/sh/bash}
如果在變量值中找到 sh 的話﹐將第一個 sh 換成 bash。
/home/kenny/tmp/test.1.bash
${FNAME//sh/bash}
如果在變量值中找到 sh 的話﹐將全部 sh 換成 bash。
/home/kenny/tmp/test.1.bash
您除了能夠對變量進行過濾之外﹐您也能對變量做出限制﹑和改變其變量值﹕?
------------好好理解,相當不錯!!!
字符串沒設定
空字符串
使用默認值
var=${str-expr}
var=expr
var=
var=$str
var=${str:-expr}
var=expr
var=expr
var=$str
使用其它值
var=${str+expr}
var=expr
var=expr
var=expr
var=${str:+expr}
var=expr
var=
var=expr
設定默認值
var=${str=expr}
str=expr?
var=expr
str 不變?
var=
str 不變?
var=$str
var=${str:=expr}
str=expr?
var=expr
str=expr?
var=expr
str 不變?
var=$str
輸出錯誤
var=${str?expr}
expr 輸出至 stderr?
var=
var=str
var=${str:?expr}
expr 輸出至 stderr?
expr 輸出至 stderr?
var=str
一開始或許比較難理解上面的兩個表格說明的意思﹐真的很混亂~~ 但只要多做一些練習﹐那您就知道怎么使用了。比方說﹕?
# expr=EXPR?
# unset str?
# var=${str=expr}; echo var=$var str=$str expr=$expr?
var=expr str=expr expr=EXPR?
# var=${str:=expr}; echo var=$var str=$str expr=$expr?
var=expr str=expr expr=EXPR?
# str=?
# var=${str=expr}; echo var=$var str=$str expr=$expr?
var= str= expr=EXPR?
# var=${str:=expr}; echo var=$var str=$str expr=$expr?
var=expr str=expr expr=EXPR?
# str=STR?
# var=${str=expr}; echo var=$var str=$str expr=$expr?
var=STR str=STR expr=EXPR?
# var=${str:=expr}; echo var=$var str=$str expr=$expr?
var=STR str=STR expr=EXPR?
#?MYSTRING=test?
#?echo ${MYSTRING?string not set\!}?
test?
#?MYSTRING=?
#?echo ${MYSTRING?string not set\!}?
??
#?unset MYSTRING?
#?echo ${MYSTRING?string not set\!}?
bash: MYSTRING: string not set!?
請記住這些變量的習性﹐日后您要寫 shell script 的時候就不會將變量搞混亂了。假如您想看看當前 shell 的環境變量有哪些﹐您可以輸入?set?命令﹔如果只想檢查 export 出來的變量﹐可以輸入?export?或?env?(前者是 shell 默認的輸出變數)。?
Bash 設定?
到這里﹐您或許會問﹕shell 的環境變量在哪里定義呢﹖可以調整嗎﹖?
嗯﹐第一個問題我不大了解﹐我猜那是 shell 設計者預設定義好的﹐我們一登錄獲得 shell 之后就有了。不過﹐第二個問題﹐我卻可以肯定答復您﹕您可以隨時調整您的環境變量。您可以在進入 shell 之后用在命令行里面重新定義﹐也可以透過一些 shell 配置文件來設定。?
先讓我們看看﹐當您在進行登錄的時候﹐系統會檢查哪些檔案吧﹕?
·? /etc/profile﹕首先﹐系統會檢查這個文件﹐以定義如下這些變量 ﹕PATH﹑USER﹑LOGNAME﹑MAIL﹑HOSTNAME﹑HISTSIZE﹑INPUTRC。如果您會 shell script (我們后面再討論)﹐那您應該看得出這些變量是如何定義的。另外﹐還指定了 umask 和 ulimit 的設定﹕umask 大家應該知道了﹐而 ulmimit 呢﹖它是用來限制一個 shell 做能建立的行程數目﹐以避免系統資源被無限制的消耗。最后﹐它還會檢查并執行 /etc/profile.d/*.sh 那些 script﹐有興趣您可以追蹤看看。? ·? ~/.bash_profile﹕這里會定義好 USERNAME﹑BASH_ENV﹑PATH。其中的 PATH 除了現有的 $PATH 之外﹐還會再加入用戶相關的路徑﹐您會發現 root 和普通賬號的路徑是不一樣的﹔而 BASH_ENV 呢﹐仔細點看﹐是下一個要檢查的檔案﹕? ·? ~/.bashrc﹕在這個檔里面﹐您可以發現一些 alias 設定(哦~~ 原來在這里﹗)。然后﹐您會發現有一行﹕. /etc/bashrc?。在 shell script 中﹐用一個小數點然后然后一個空格鍵再指向另外一個 script﹐意思是同時執行那個 script 并采用那里的變量設定。? ·? /etc/bashrc﹕基本上﹐這里的設定﹐是所有使用者在獲得 shell 的時候都會采用的。這里指定了一些 terminal 設定﹐以及 shell 提示字符等等。? ·? ~/.bash_login﹕如果 ~/.bash_profile 不存在﹐則使用這個檔。? ·? ~/.profile﹕如果 ~/.bash_profile 和 ~/.bash_login 都不存在﹐則使用這個檔。? ·? ~/.bash_logout﹕這個檔通常只有一個命令﹕clear﹐也就是把熒幕顯示的內容清掉。如果您想要在注銷 shell 的時候﹐會執行一些動作﹐例如﹕清空臨時檔(假如您有使用到臨時檔)﹑還原某些設定﹑或是執行某些備份之類的。? |
總結
- 上一篇: 如何查看linux版本
- 下一篇: C语言 条件编译详解