Shell 定制
本節(jié)介紹了初級(jí)管理(LPIC-1)考試 102 的 1.109.1 主題的內(nèi)容。這個(gè)主題的權(quán)值為 5。
在本節(jié)中,我們將學(xué)習(xí)如何:
- 設(shè)置并取消環(huán)境變量
- 使用配置文件在登錄或派生新 shell 時(shí)設(shè)置環(huán)境變量
- 對(duì)經(jīng)常使用的命令序列編寫 shell 函數(shù)
- 使用命令列表
Shell 和環(huán)境
在出現(xiàn)圖形界面之前,程序員都是使用打字機(jī)終端或 ASCII 顯示終端連接到 UNIX® 系統(tǒng)的。用戶可以使用打字機(jī)終端輸入命令,輸出結(jié)果通常會(huì)被打印到連續(xù)的紙張上。大部分 ASCII 顯示終端都是每行 80 個(gè)字符,每屏 25 行,不過(guò)也有比這更大或更小的終端。程序員輸入一條命令并按下回車鍵之后,系統(tǒng)就會(huì)解釋并執(zhí)行這條命令。
盡管在當(dāng)今這個(gè)使用拖拽式圖形界面的時(shí)代,這一切看起來(lái)似乎太過(guò)原始,但是與原來(lái)編寫程序、打卡、對(duì)卡迭(card deck)進(jìn)行匯編并運(yùn)行程序的方式相比,這已經(jīng)是非常大的一個(gè)進(jìn)步了。隨著編輯器的出現(xiàn),程序員甚至可以作為卡像來(lái)創(chuàng)建程序,并在終端會(huì)話中編譯程序。
在終端中輸入的字節(jié)流向 shell 提供了一個(gè)標(biāo)準(zhǔn)輸入流,shell 返回的字符流可以打印到紙上,也可以顯示到標(biāo)準(zhǔn)輸出 上。
接受并執(zhí)行命令的程序稱為 shell。它位于您和操作系統(tǒng)之間。UNIX shell 和 Linux shell 的功能都非常強(qiáng)大,可以通過(guò)組合一些基本的函數(shù)來(lái)構(gòu)造非常復(fù)雜的操作。通過(guò)使用編程結(jié)構(gòu)則可以構(gòu)建一些函數(shù)在 shell 中直接執(zhí)行,或者將這些函數(shù)保存成 shell 腳本 的形式,這樣就可以一次次重用這些函數(shù)了。
有時(shí)需要在系統(tǒng)引導(dǎo)之前就執(zhí)行一些命令,以便能夠進(jìn)行終端連接;有時(shí)又需要周期性地執(zhí)行命令,而不管您登錄與否。shell 可以為您完成這些功能。標(biāo)準(zhǔn)輸入和輸出并不需要來(lái)自于(或定向到)終端處的真實(shí)用戶。
在本節(jié)中,將學(xué)習(xí)更多有關(guān) shell 的內(nèi)容。具體來(lái)說(shuō),您將學(xué)習(xí)有關(guān) bash(又稱為 Bourne again)shell 的內(nèi)容,它是對(duì)原來(lái) Bourne shell 的一個(gè)增強(qiáng),另外還提供了其他 shell 所具有的一些特性,以及對(duì) Bourne shell 所做的一些更改以使其更加兼容 POSIX。
POSIX 是 Portable Operating System Interface for uniX 的簡(jiǎn)稱,它是一系列 IEEE 標(biāo)準(zhǔn),總稱為 IEEE 1003。這些標(biāo)準(zhǔn)中的第一個(gè)標(biāo)準(zhǔn)是 IEEE Standard 1003.1-1988,它是在 1988 年發(fā)布的。其他知名的 shell 包括 Korn shell(ksh)、C shell(csh)及其派生產(chǎn)品 tcsh、Almquist shell(ash)及其 Debian 派生產(chǎn)品(dash)。一些腳本常常需要用到上述某個(gè) shell 的特性,所以要對(duì)這些 shell 有一些了解。
您與計(jì)算機(jī)的很多交互特性在這些會(huì)話中都是相同的。回想一下在教程 “LPI 101 考試準(zhǔn)備(主題 103):GNU 和 UNIX 命令” 中,當(dāng)使用 Bash shell 時(shí),就擁有了一個(gè) shell 環(huán)境,它定義了很多內(nèi)容,例如提示符格式、主目錄、工作目錄、shell 名、已經(jīng)打開的文件、已經(jīng)定義的函數(shù)等。每個(gè) shell 進(jìn)程都可以使用這個(gè)環(huán)境。shell(包括 bash)讓您可以創(chuàng)建并修改 shell 變量,并可以將其導(dǎo)出 到環(huán)境中由在 shell 中運(yùn)行的其他進(jìn)程或從當(dāng)前 shell 中派生的其他 shell 使用。
環(huán)境變量和 shell 變量都有名稱。您可以通過(guò)在變量名前加上一個(gè) ‘$‘ 符號(hào)來(lái)引用變量的值。一些常用的 bash 變量如表 3 所示。
表 3. 常用 bash 環(huán)境變量
變量名 |
功能 |
USER |
已登錄用戶的用戶名 |
UID |
已登錄用戶的數(shù)字用戶 id |
HOME |
用戶的主目錄 |
PWD |
當(dāng)前工作目錄 |
SHELL |
shell 名 |
$ |
進(jìn)程 id(或正在運(yùn)行的 Bash shell 進(jìn)程或其他進(jìn)程的 PID) |
PPID |
啟動(dòng)這個(gè)進(jìn)程的進(jìn)程的進(jìn)程 id (即父進(jìn)程的 id) |
|
上一個(gè)命令的退出碼 |
設(shè)置變量
在 Bash shell 中,可以通過(guò)在一個(gè)名字后面緊跟上一個(gè)等號(hào)(=)來(lái)創(chuàng)建或設(shè)置 shell 變量。變量名(或標(biāo)識(shí)符)是由字符、數(shù)字和下劃線構(gòu)成的單詞,它只能由字符或下劃線開頭。變量是大小寫敏感的,例如 var1 和 VAR1 是不同的兩個(gè)變量。按照慣例,變量 —— 尤其是導(dǎo)出后的變量 —— 都采用大寫,不過(guò)這并不是硬性要求。通常,$$ 和 $? 是 shell 參數(shù),而不是變量。它們只能被引用;無(wú)法對(duì)它們進(jìn)行賦值。
在創(chuàng)建 shell 變量時(shí),通常都會(huì)希望將該變量導(dǎo)出 到環(huán)境中,這樣從這個(gè) shell 中啟動(dòng)的其他進(jìn)程也都可以使用該變量了。但所導(dǎo)出的變量對(duì)父 shell 不可用。可以使用 export 命令導(dǎo)出一個(gè)變量名。在 bash 中,可以在一個(gè)步驟中完成賦值和導(dǎo)出。
為了展示賦值和導(dǎo)出操作,讓我們?cè)?Bash shell 中運(yùn)行 bash 命令,然后在這個(gè)新 Bash shell 中在運(yùn)行 Korn shell(ksh)。我們會(huì)使用 ps 命令來(lái)顯示有關(guān)正在運(yùn)行的命令的信息。
清單 1. 設(shè)置并導(dǎo)出 shell 變量
[ian@echidna ian]$ ps -p $$ -o "pid ppid cmd"
PID PPID CMD
30576 30575 -bash
[ian@echidna ian]$ bash
[ian@echidna ian]$ ps -p $$ -o "pid ppid cmd"
PID PPID CMD
16353 30576 bash
[ian@echidna ian]$ VAR1=var1
[ian@echidna ian]$ VAR2=var2
[ian@echidna ian]$ export VAR2
[ian@echidna ian]$ export VAR3=var3
[ian@echidna ian]$ echo $VAR1 $VAR2 $VAR3
var1 var2 var3
[ian@echidna ian]$ echo $VAR1 $VAR2 $VAR3 $SHELL
var1 var2 var3 /bin/bash
[ian@echidna ian]$ ksh
$ ps -p $$ -o "pid ppid cmd"
PID PPID CMD
16448 16353 ksh
$ export VAR4=var4
$ echo $VAR1 $VAR2 $VAR3 $VAR4 $SHELL
var2 var3 var4 /bin/bash
$ exit
$ [ian@echidna ian]$ echo $VAR1 $VAR2 $VAR3 $VAR4 $SHELL
var1 var2 var3 /bin/bash
[ian@echidna ian]$ ps -p $$ -o "pid ppid cmd"
PID PPID CMD
16353 30576 bash
[ian@echidna ian]$ exit
[ian@echidna ian]$ ps -p $$ -o "pid ppid cmd"
PID PPID CMD
30576 30575 -bash
[ian@echidna ian]$ echo $VAR1 $VAR2 $VAR3 $VAR4 $SHELL
/bin/bash
|
注意:
- 在這些操作開始時(shí),Bash shell 的 PID 是 30576。
- 第二個(gè) Bash shell 的 PID 是 16353,其父 shell 的 PID 是 30576,也就是原來(lái)的 Bash shell。
- 我們?cè)诘诙€(gè) Bash shell 中創(chuàng)建了 VAR1、VAR2 和 VAR3 三個(gè)變量,但是只導(dǎo)出了 VAR2 和 VAR3。
- 在 Korn shell 中,我們創(chuàng)建了 VAR4。
echo 命令只顯示了 VAR2、VAR3 和 VAR4 的值,這就證實(shí)了 VAR1 的確沒(méi)有導(dǎo)出??吹教崾痉淖冎?,SHELL 變量的值卻還未改變,您會(huì)非常奇怪么?通常不能總依賴 SHELL 來(lái)告訴您正在哪個(gè) shell 下運(yùn)行,不過(guò) ps 命令的確可以告訴您實(shí)際的命令。注意 ps 會(huì)在第一個(gè) Bash shell 前面放上一個(gè)連字符(-)來(lái)說(shuō)明這是一個(gè)登錄 shell。
- 現(xiàn)在回到第二個(gè) Bash shell 中,我們可以看到 VAR1、VAR2 和 VAR3。
- 最后,當(dāng)我們返回到原始的 shell 中時(shí),新變量都不存在了。
清單 2 顯示了在這些常用的 bash 變量中可以看到什么。
清單 2. 環(huán)境和 shell 變量
[ian@echidna ian]$ echo $USER $UID
ian 500
[ian@echidna ian]$ echo $SHELL $HOME $PWD
/bin/bash /home/ian /home/ian
[ian@echidna ian]$ (exit 0);echo $?;(exit 4);echo $?
0
4
[ian@echidna ian]$ echo $$ $PPID
30576 30575
|
環(huán)境和 C shell
在諸如 C 和 tcsh shell 之類的 shell 中,可以使用 set 命令在 shell 中設(shè)置變量,使用 setenv 命令來(lái)設(shè)置并導(dǎo)出變量。清單 3 中給出的語(yǔ)法與 export 命令的語(yǔ)法稍有不同。請(qǐng)注意在使用 set 命令時(shí)使用的等號(hào)(=)。
清單 3. 在 C shell 中設(shè)置環(huán)境變量
ian@attic4:~$ echo $VAR1 $VAR2
ian@attic4:~$ csh
% set VAR1=var1
% setenv VAR2 var2
% echo $VAR1 $VAR2
var1 var2
% bash
ian@attic4:~$ echo $VAR1 $VAR2
var2
|
取消變量
可以使用 unset 命令從 Bash shell 中清除變量??梢允褂?-v 選項(xiàng)來(lái)確保刪除變量定義。函數(shù)可以使用與變量相同的名字,因此如果希望清除函數(shù)定義,就請(qǐng)使用 -f 選項(xiàng)。在沒(méi)有使用 -f 或 -v 的情況下,如果存在這樣一個(gè)變量,那么 bash 的 unset 命令就會(huì)清除變量定義;否則,如果存在這樣一個(gè)函數(shù),這個(gè)命令就清除函數(shù)定義(函數(shù)將在后面的 Shell 函數(shù) 一節(jié)中更詳細(xì)地加以介紹)。
清單 4. bash unset 命令
ian@attic4:~$ VAR1=var1
ian@attic4:~$ VAR2=var2
ian@attic4:~$ echo $VAR1 $VAR2
var1 var2
ian@attic4:~$ unset VAR1
ian@attic4:~$ echo $VAR1 $VAR2
var2
ian@attic4:~$ unset -v VAR2
ian@attic4:~$ echo $VAR1 $VAR2
|
默認(rèn)情況下,bash 會(huì)將取消的變量視為該變量的值為空,因此您可能會(huì)納悶為什么一定要取消變量,為什么不僅僅為其賦一個(gè)空值呢。如果引用了未定義的變量,Bash 和很多其他 shell 都會(huì)允許您生成一個(gè)錯(cuò)誤。使用命令 set -u 可以針對(duì)引用未定義的變量的情況生成一個(gè)錯(cuò)誤,使用 set +u 可以禁用這種警告,如清單 5 所示。
清單 5. 針對(duì)取消的變量生成錯(cuò)誤
ian@attic4:~$ set -u
ian@attic4:~$ VAR1=var1
ian@attic4:~$ echo $VAR1
var1
ian@attic4:~$ unset VAR1
ian@attic4:~$ echo $VAR1
-bash: VAR1: unbound variable
ian@attic4:~$ VAR1=
ian@attic4:~$ echo $VAR1
ian@attic4:~$ unset VAR1
ian@attic4:~$ echo $VAR1
-bash: VAR1: unbound variable
ian@attic4:~$ unset -v VAR1
ian@attic4:~$ set +u
ian@attic4:~$ echo $VAR1
ian@attic4:~$
|
注意取消一個(gè)不存在的變量并不會(huì)產(chǎn)生錯(cuò)誤,即使在指定 set -u 時(shí)也是如此。
配置文件
在登錄 Linux 系統(tǒng)時(shí),您的 id 就有了一個(gè)默認(rèn) shell,它就是您的登錄 shell。如果這個(gè) shell 是 bash,那么它就會(huì)在您控制系統(tǒng)之前先執(zhí)行幾個(gè)配置腳本。如果存在 /etc/profile 文件,就首先執(zhí)行這個(gè)文件。根據(jù)發(fā)行版的不同,/etc 中的其他腳本也可能會(huì)執(zhí)行,例如 /etc/bash.bashrc 或 /etc/bashrc。這些腳本運(yùn)行之后,如果主目錄中存在腳本,該腳本也會(huì)被執(zhí)行。Bash 會(huì)按照 ~/.bash_profile、~/.bash_login 和 ~/.profile 的順序來(lái)查找文件。最先找到的文件會(huì)首先執(zhí)行。
當(dāng)您登出系統(tǒng)時(shí),如果主目錄中存在 ~/.bash_logout 腳本,bash 就會(huì)執(zhí)行它。
一旦登錄進(jìn)系統(tǒng)并使用 bash,您還可以啟動(dòng)另外一個(gè) shell(稱為交互式 shell)來(lái)運(yùn)行命令,例如在后臺(tái)運(yùn)行命令。在這種情況中,bash 只會(huì)執(zhí)行 ~/.bashrc 腳本(假設(shè)這個(gè)腳本存在)。通??梢允褂萌缜鍐?6 所示的命令在 ~/.bash_profile 檢查這個(gè)腳本,以便可以在登錄時(shí)或在啟動(dòng)交互式 shell 時(shí)執(zhí)行它。
清單 6. 檢查 ~/.bashrc
# include .bashrc if it exists
if [ -f ~/.bashrc ]; then
. ~/.bashrc
fi
|
可以使用 --login 選項(xiàng)強(qiáng)制 bash 像登錄 shell 一樣讀取配置文件。如果不希望執(zhí)行登錄 shell 的配置文件,可以指定 --noprofile 選項(xiàng)。類似地,如果希望對(duì)某個(gè)交互式 shell 不執(zhí)行 ~/.bashrc 文件,可以使用 --norc 選項(xiàng)來(lái)啟動(dòng) bash。也可以通過(guò)指定 --rcfile 選項(xiàng)加上希望使用的文件名來(lái)強(qiáng)制 bash 使用 ~/.bashrc 之外的文件。清單 7 展示了創(chuàng)建一個(gè)名為 testrc 的簡(jiǎn)單文件并使用 --rcfile 選項(xiàng)來(lái)使用這個(gè)文件的例子。注意 VAR1 變量并不是 在外部 shell 中設(shè)置的,而是通過(guò) testrc 文件針對(duì)內(nèi)部 shell 設(shè)置的。
清單 7. 使用 --rcfile 選項(xiàng)
ian@attic4:~$ echo VAR1=var1>testrc
ian@attic4:~$ echo $VAR1
ian@attic4:~$ bash --rcfile testrc
ian@attic4:~$ echo $VAR1
var1
|
以其他方式啟動(dòng) bash
除了前面介紹的這種在終端中運(yùn)行 bash 的標(biāo)準(zhǔn)方法之外,bash 也可以通過(guò)其他方法加以使用。
除非您引用(source) 腳本在當(dāng)前 shell 中運(yùn)行,否則它就會(huì)在自己的非交互式 shell 中運(yùn)行,上面的配置文件都不會(huì)被讀取。然而,如果設(shè)置了 BASH_ENV 變量,那么 bash 就會(huì)對(duì)這個(gè)值進(jìn)行擴(kuò)展,并假設(shè)它是一個(gè)文件名。如果這個(gè)文件存在,那么 bash 就會(huì)在非交互式 shell 中執(zhí)行任何腳本或命令之前先執(zhí)行這個(gè)文件。清單 8 通過(guò)兩個(gè)簡(jiǎn)單的文件展示了這一點(diǎn)。
清單 8. 使用 BASH_ENV
ian@attic4:~$ cat testenv.sh
#!/bin/bash
echo "Testing the environment"
ian@attic4:~$ cat somescript.sh
#!/bin/bash
echo "Doing nothing"
ian@attic4:~$ export BASH_ENV="~/testenv.sh"
ian@attic4:~$ ./somescript.sh
Testing the environment
Doing nothing
|
非交互式 shell 也可以使用 --login 選項(xiàng)啟動(dòng),從而強(qiáng)制配置文件的執(zhí)行。
Bash 也可以使用 --posix 選項(xiàng)以 POSIX 模式啟動(dòng)。這種模式與非交互式 shell 非常類似,只不過(guò)在這種模式下,要執(zhí)行的文件是在 ENV 環(huán)境變量中設(shè)定的。
在 Linux 系統(tǒng)中常常會(huì)使用一個(gè)符號(hào)鏈接來(lái)以 /bin/sh 運(yùn)行 bash。當(dāng) bash 檢測(cè)到它正在以 sh 的名義運(yùn)行時(shí),它就會(huì)試圖遵循老式 Bourne shell 的啟動(dòng)行為,而同時(shí)又可以兼容 POSIX 標(biāo)準(zhǔn)。當(dāng)作為登錄 shell 運(yùn)行時(shí),bash 會(huì)試圖讀取并執(zhí)行 /etc/profile 和 ~/.profile 文件。當(dāng)使用 sh 命令作為一個(gè)交互式 shell 運(yùn)行時(shí),bash 會(huì)試圖執(zhí)行由 ENV 變量指定的文件,與在 POSIX 模式下被調(diào)用時(shí)一樣。當(dāng)作為 sh 交互運(yùn)行時(shí),它只 會(huì)使用由 ENC 變量指定的文件;--rcfile 選項(xiàng)會(huì)一直被忽略。
如果 bash 是由遠(yuǎn)程 shell 守護(hù)進(jìn)程調(diào)用的,那么它的行為就與交互式 shell 非常類似,如果存在 ~/.bashrc 文件就會(huì)使用該文件。
Shell 別名
Bash shell 允許為命令定義一些 別名。使用別名的最常見(jiàn)原因是為了給命令提供其他名字,或者為命令提供一些默認(rèn)參數(shù)。很多年以來(lái),vi 編輯器一直都是 UNIX 和 Linux 系統(tǒng)上的一個(gè)主要工具。vim(Vi IMproved)編輯器與 vi 非常類似,不過(guò)有很多改進(jìn)。因此如果您在使用編輯器時(shí)習(xí)慣于輸入 “vi”,但是實(shí)際上卻更喜歡使用 vim,那么您就可以借助于別名。清單 9 顯示了如何使用 alias 命令來(lái)實(shí)現(xiàn)這種功能。
清單 9. 使用 vi 作為 vim 的別名
[ian@pinguino ~]$ alias vi=‘vim‘
[ian@pinguino ~]$ which vi
alias vi=‘vim‘
/usr/bin/vim
[ian@pinguino ~]$ /usr/bin/which vi
/bin/vi
|
注意在這個(gè)例子中,如果使用 which 命令來(lái)查看 vi 程序的位置,那就會(huì)看到兩行輸出:第一個(gè)是別名,第二個(gè)是 vim 的位置(/usr/bin/vim)。然而,如果使用完整路徑來(lái)執(zhí)行 which 命令(/usr/bin/which ),就可以獲得 vi 命令的位置。如果您猜測(cè)這可能意味著 which 命令本身在這個(gè)系統(tǒng)上就是一個(gè)別名,那么您就猜對(duì)了。
可以使用 alias 命令來(lái)顯示所有的別名(如果沒(méi)使用任何選項(xiàng),或者只使用了 -p 選項(xiàng)),還可以通過(guò)給出別名作為參數(shù)但不進(jìn)行賦值來(lái)顯示一個(gè)或多個(gè)別名。清單 10 顯示了 which 和 vi 的別名。
清單 10. which 和 vi 的別名
[ian@pinguino ~]$ alias which vi
alias which=‘a(chǎn)lias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde‘
alias vi=‘vim‘
|
which 命令的別名有些奇怪。為什么會(huì)將 alias 命令(沒(méi)有參數(shù))的輸出定向到 /usr/bin/which 上呢?如果查看一下 which 命令的手冊(cè)頁(yè),就會(huì)發(fā)現(xiàn) --read-alias 選項(xiàng)通知 which 從標(biāo)準(zhǔn)輸入讀取一個(gè)別名列表,并將匹配項(xiàng)輸出到標(biāo)準(zhǔn)輸出設(shè)備上。這允許 which 命令報(bào)告別名和 PATH 中的命令,這種用法非常常見(jiàn),因此您的發(fā)行版可能已將其作為默認(rèn)設(shè)置了。這是很好的一個(gè)做法,因?yàn)槿绻麆e名和命令名相同,那么 shell 就首先執(zhí)行別名。知道了這一點(diǎn)以后,就可以使用 alias which 來(lái)加以檢查。還可以通過(guò)運(yùn)行 which which 命令來(lái)了解是否為 which 命令設(shè)置了這種別名。 .
別名的另外一種常見(jiàn)用法是自動(dòng)為命令添加參數(shù),正如在上面看到的 which 命令的 --read-alias 和其他幾個(gè)參數(shù)一樣。這種方法也可用在 root 用戶使用 cp 、mv 和 rm 命令的時(shí)候,這樣在刪除或覆蓋文件之前能夠顯示一個(gè)提示。具體用法如清單 11 所示。
清單 11. 為了安全起見(jiàn)添加參數(shù)
[root@pinguino ~]# alias cp mv rm
alias cp=‘cp -i‘
alias mv=‘mv -i‘
alias rm=‘rm -i‘
|
命令列表
在之前的教程 “LPI 101 考試準(zhǔn)備(主題 103):GNU 和 UNIX 命令” 中,您已經(jīng)學(xué)習(xí)了命令序列 或列表。您剛剛又看到了別名中使用的管道(|)操作符,您也可以使用命令列表。舉個(gè)簡(jiǎn)單的例子來(lái)說(shuō),假設(shè)您希望使用一個(gè)命令來(lái)顯示當(dāng)前目錄中的內(nèi)容,以及當(dāng)前目錄及其子目錄所使用的空間。讓我們就將其稱為 lsdu 命令。因此您可以簡(jiǎn)單地將 ls 和 du 命令序列賦值給別名 lsdu。清單 12 給出了實(shí)現(xiàn)這種功能的正確方法和錯(cuò)誤方法。在閱讀之前請(qǐng)仔細(xì)查看一下,并考慮為什么第一次嘗試會(huì)失敗。
清單 12. 命令序列的別名
[ian@pinguino developerworks]$ alias lsdu=ls;du -sh # Wrong way
2.9M .
[ian@pinguino developerworks]$ lsdu
a tutorial new-article.sh new-tutorial.sh readme tools xsl
my-article new-article.vbs new-tutorial.vbs schema web
[ian@pinguino developerworks]$ alias ‘lsdu=ls;du -sh‘ # Right way way
[ian@pinguino developerworks]$ lsdu
a tutorial new-article.sh new-tutorial.sh readme tools xsl
my-article new-article.vbs new-tutorial.vbs schema web
2.9M .
|
在引用構(gòu)成別名的完整序列時(shí)需要非常仔細(xì)。如果使用 shell 變量作為別名的一部分,還需要注意是使用雙引號(hào)還是使用單引號(hào)。您希望在定義或執(zhí)行別名時(shí)讓 shell 對(duì)變量進(jìn)行擴(kuò)展嗎?清單 13 顯示了創(chuàng)建名為 mywd 定制命令來(lái)打印當(dāng)前工作目錄名的錯(cuò)誤方法。
清單 13. 定制 pwd —— 嘗試 1
[ian@pinguino developerworks]$ alias mywd="echo \"My working directory is $PWD\""
[ian@pinguino developerworks]$ mywd
My working directory is /home/ian/developerworks
[ian@pinguino developerworks]$ cd ..
[ian@pinguino ~]$ mywd
My working directory is /home/ian/developerworks
|
注意雙引號(hào)會(huì)導(dǎo)致 bash 在執(zhí)行命令之前就對(duì)變量進(jìn)行擴(kuò)展。清單 14 使用了 alias 命令來(lái)顯示所生成的別名實(shí)際上是什么樣子,從中可以看出我們的錯(cuò)誤是很明顯的。清單 14 還給出了定義這個(gè)別名的正確方法。
清單 14. 定制 pwd —— 嘗試 2
[ian@pinguino developerworks]$ alias mywd
alias mywd=‘echo \"My working directory is $PWD\"‘
[ian@pinguino developerworks]$ mywd
"My working directory is /home/ian/developerworks"
[ian@pinguino developerworks]$ cd ..
[ian@pinguino ~]$ mywd
"My working directory is /home/ian"
|
終于成功了。
Shell 函數(shù)
別名讓您可以對(duì)某個(gè)命令或命令列表選用一種簡(jiǎn)寫或其他名字。此外,還可以添加其他一些內(nèi)容,例如在 which 命令中加上希望查找的程序名。當(dāng) shell 執(zhí)行用戶的輸入時(shí),就會(huì)對(duì)別名進(jìn)行擴(kuò)展;之后輸入的其他內(nèi)容都會(huì)在最后一個(gè)命令或命令列表執(zhí)行之前添加到該擴(kuò)展。這意味著只能在命令或命令列表之后添加參數(shù),也只能在最后一個(gè)命令中使用這些參數(shù)。函數(shù)提供了更多功能,包括對(duì)參數(shù)進(jìn)行處理的能力。函數(shù)是 POSIX shell 定義的一部分,在諸如 bash、dash 和 ksh 之類的 shell 中可以使用,但在 csh 或 tcsh 中不能使用。
在接下來(lái)的幾節(jié)中,將逐步構(gòu)建一個(gè)復(fù)雜的命令:從很小的構(gòu)建塊開始,逐漸在每個(gè)步驟加以完善,并將其轉(zhuǎn)換成一個(gè)函數(shù),以供以后使用。
假想問(wèn)題
可以使用 ls 命令顯示有關(guān)文件系統(tǒng)中目錄和文件的各種信息。假設(shè)您喜歡使用一個(gè)命令,假定就是 ldirs , 來(lái)顯示目錄名,所顯示的內(nèi)容如清單 15 所示。
清單 15. ldirs 命令輸出結(jié)果
[ian@pinguino developerworks]$ ldirs *[st]* tools/*a*
my dw article
schema
tools
tools/java
xsl
|
為了保持簡(jiǎn)單性起見(jiàn),本節(jié)中的例子使用了 developerWorks author package 中的目錄和文件(請(qǐng)參看 參考資料),如果您想為 developerWorks 編寫文章和教程,也可以使用它們。在這些例子中,我們使用了這個(gè)包中提供的 new-article.sh 腳本來(lái)為一篇我們稱之為 “my dw article” 的文章創(chuàng)建一個(gè)模板。
在撰寫本文時(shí),developerWorks author package 的版本是 5.6,因此如果您使用更新的版本,可能會(huì)發(fā)現(xiàn)一些不同之處。或者您也可以只使用自己的文件和目錄。ldirs 命令也可以處理這些內(nèi)容。在 developerWorks author package 提供的工具中,可以找到其他 bash 函數(shù)的例子。
查找目錄項(xiàng)
如果在 ls 命令中使用了上述別名例子所示的顏色選項(xiàng),請(qǐng)暫時(shí)忽略 *[st]* tools/*a* ,這樣就可以看到類似于圖 1 所示的輸出結(jié)果。
圖 1. 使用 ls 命令區(qū)分文件和目錄
在本例中,目錄都是使用深藍(lán)色顯示的,不過(guò)使用在本系列教程中所學(xué)到的知識(shí)還不足以解釋這個(gè)問(wèn)題。不過(guò),使用-l 選項(xiàng)會(huì)對(duì)如何繼續(xù)處理給出一點(diǎn)線索:目錄列表在第一個(gè)位置處有一個(gè) “d” 字符。因此第一個(gè)步驟應(yīng)該是使用 grep 對(duì)這個(gè)長(zhǎng)列表中的內(nèi)容進(jìn)行一些簡(jiǎn)單的過(guò)濾,如清單 16 所示。
清單 16. 使用 grep 過(guò)濾目錄項(xiàng)
[ian@pinguino developerworks]$ ls -l | grep "^d"
drwxrwxr-x 2 ian ian 4096 Jan 24 17:06 my dw article
drwxrwxr-x 2 ian ian 4096 Jan 18 16:23 readme
drwxrwxr-x 3 ian ian 4096 Jan 19 07:41 schema
drwxrwxr-x 3 ian ian 4096 Jan 19 15:08 tools
drwxrwxr-x 3 ian ian 4096 Jan 17 16:03 web
drwxrwxr-x 3 ian ian 4096 Jan 19 10:59 xsl
|
截取目錄項(xiàng)
可以考慮使用 awk 而不是 grep ,來(lái)在一個(gè)步驟中既對(duì)列表進(jìn)行過(guò)濾,又截取每行的最后一部分內(nèi)容,也就是目錄名,如清單 17 所示。
清單 17. 使用 awk 代替 grep 進(jìn)行處理
[ian@pinguino developerworks]$ ls -l | awk ‘/^d/ { print $NF } ‘
article
readme
schema
tools
web
xsl
|
清單 17 中的方法有一個(gè)問(wèn)題:它無(wú)法正確處理名字中有空格的那些目錄名,例如 “my dw article”。就像是 Linux 和我們生活中的大部分事情一樣,解決一個(gè)問(wèn)題通常有很多方法,不過(guò)此處的目標(biāo)是學(xué)習(xí)函數(shù)的知識(shí),因此讓我們回到使用 grep 方法上來(lái)。在本系列文章中我們學(xué)過(guò)的另外一個(gè)工具是 cut ,它可以從一個(gè)文件(包括 stdin)中截取出很多域。現(xiàn)在讓我們?cè)诨剡^(guò)頭來(lái)看一下清單 16,在文件名之前,可以看到 8 個(gè)由空格分隔的域。在之前的命令后面加上 cut 就可以得到如清單 18 所示的輸出結(jié)果。注意 -f9- 選項(xiàng)告訴 cut 打印第 9 個(gè)域以及之后的域的內(nèi)容。
清單 18. 使用 cut 截取名稱
[ian@pinguino developerworks]$ ls -l | grep "^d" | cut -d" " -f9-
my dw article
readme
schema
tools
web
xsl
|
如果我們?cè)?tools 目錄而不是當(dāng)前目錄上執(zhí)行這個(gè)命令,使用這種方法存在的一個(gè)小問(wèn)題就會(huì)變得十分明顯,如清單 19 所示。
清單 19. 使用 cut 存在的問(wèn)題
[ian@pinguino developerworks]$ ls -l tools | grep "^d" | cut -d" " -f9-
11:25 java
[ian@pinguino developerworks]$ ls -ld tools/[fjt]*
-rw-rw-r-- 1 ian ian 4798 Jan 8 14:38 tools/figure1.gif
drwxrwxr-x 2 ian ian 4096 Oct 31 11:25 tools/java
-rw-rw-r-- 1 ian ian 39431 Jan 18 23:31 tools/template-dw-article-5.6.xml
-rw-rw-r-- 1 ian ian 39407 Jan 18 23:32 tools/template-dw-tutorial-5.6.xml
|
時(shí)間戳為什么會(huì)出現(xiàn)呢??jī)蓚€(gè)模板文件都有 5 個(gè)數(shù)字的大小,而 java 目錄的大小則只有 4 個(gè)數(shù)字,因此 cut 會(huì)將多出來(lái)的空格當(dāng)作另外一個(gè)域分隔符來(lái)解釋。
使用 seq 來(lái)查找分割點(diǎn)
cut 命令也可以使用字符位置而不是域來(lái)進(jìn)行分割。除了計(jì)算字符個(gè)數(shù)之外,bash shell 還有很多工具可以使用,因此可以嘗試使用 seq 和 printf 命令來(lái)在長(zhǎng)目錄列表上面打印一個(gè)標(biāo)尺,這樣就可以方便地確定在什么地方對(duì)輸出行的內(nèi)容進(jìn)行分割了。seq 命令最多可以使用 3 個(gè)參數(shù),這就允許您可以打印出給定值之前的所有數(shù)字,或者打印出一個(gè)值到另一個(gè)值之間的所有數(shù)字,又或者打印出從某個(gè)值開始按給定的步值到第三個(gè)數(shù)值結(jié)束的所有數(shù)字。使用 seq 可以實(shí)現(xiàn)的其他有趣功能(包括打印 8 進(jìn)制和 16 進(jìn)制數(shù)字)請(qǐng)參看手冊(cè)頁(yè)?,F(xiàn)在,讓我們使用 seq 和 printf 命令來(lái)打印一個(gè)標(biāo)尺,每 10 個(gè)字符處的位置就標(biāo)記一下,如清單 20 所示。
清單 20. 使用 seq 和 printf 打印標(biāo)尺
[ian@pinguino developerworks]$ printf "....+...%2.d" `seq 10 10 60`;printf "\n";ls -l
....+...10....+...20....+...30....+...40....+...50....+...60
total 88
drwxrwxr-x 2 ian ian 4096 Jan 24 17:06 my dw article
-rwxr--r-- 1 ian ian 215 Sep 27 16:34 new-article.sh
-rwxr--r-- 1 ian ian 1078 Sep 27 16:34 new-article.vbs
-rwxr--r-- 1 ian ian 216 Sep 27 16:34 new-tutorial.sh
-rwxr--r-- 1 ian ian 1079 Sep 27 16:34 new-tutorial.vbs
drwxrwxr-x 2 ian ian 4096 Jan 18 16:23 readme
drwxrwxr-x 3 ian ian 4096 Jan 19 07:41 schema
drwxrwxr-x 3 ian ian 4096 Jan 19 15:08 tools
drwxrwxr-x 3 ian ian 4096 Jan 17 16:03 web
drwxrwxr-x 3 ian ian 4096 Jan 19 10:59 xsl
|
啊哈!現(xiàn)在可以使用 ls -l | grep "^d" | cut -c40- 命令來(lái)截取從位置 40 處開始的內(nèi)容了。我們的第一反應(yīng)是這也沒(méi)有真正解決問(wèn)題,因?yàn)楦蟮奈募廊粫?huì)將正確的分割位置向右移。您可以自己試驗(yàn)一下。
救援的 sed
sed 是 UNIX 和 Linux 工具包中的一個(gè)功能非常強(qiáng)大的編輯過(guò)濾器,它使用了正則表達(dá)式。您知道我們的任務(wù)是從以 “d” 開頭的每一個(gè)輸出行去掉它前面的 8 個(gè)單詞和之后的空格。可以使用 sed 來(lái)實(shí)現(xiàn)這種功能:使用模式匹配表達(dá)式 /^d/ 選擇感興趣的行,并使用替換命令 s/^d\([^ ]* *\)\(8\}// 將前 8 個(gè)單詞替換為空字符串。使用 -n 選項(xiàng)可以只打印那些通過(guò) p 命令指定的行,如清單 21 所示。
清單 21. 使用 sed 截取目錄名
[ian@pinguino developerworks]$ ls -l | sed -ne ‘s/^d\([^ ]* *\)\{8\}//p‘
my dw article
readme
schema
tools
web
xsl
[ian@pinguino developerworks]$ ls -l tools | sed -ne ‘s/^d\([^ ]* *\)\{8\}//p‘
java
|
要學(xué)習(xí)更多有關(guān) sed 的內(nèi)容,請(qǐng)參看 參考資料 一節(jié)的內(nèi)容。
最終的函數(shù)
現(xiàn)在我們已經(jīng)得到滿足 ldirs 函數(shù)功能的復(fù)雜命令了,接下來(lái)應(yīng)該學(xué)習(xí)如何將其編寫成一個(gè)函數(shù)。函數(shù)由函數(shù)名加上后面的 () 構(gòu)成,然后是一系列復(fù)合命令。對(duì)于現(xiàn)在來(lái)說(shuō),復(fù)合命令可以是任何命令或命令列表,使用一個(gè)分號(hào)結(jié)束,并使用一對(duì)花括號(hào)包括起來(lái)(且必須使用空格與其他符號(hào)分隔開來(lái))。在后面 Shell 腳本 一節(jié)中您將學(xué)到其他的復(fù)合命令。
注意:在 Bash shell 中,函數(shù)名前面可以加上單詞 “function”,但這并不是 POSIX 規(guī)范的一部分,諸如 dash 之類的更簡(jiǎn)單的 shell 并不支持這種用法。在 Shell 腳本 一節(jié)中,您將學(xué)習(xí)在使用了不同的 shell 時(shí),如何確保腳本會(huì)被適當(dāng)?shù)?shell 解釋。
在函數(shù)內(nèi)部,可以使用表 4 中給出的 bash 特殊變量來(lái)引用參數(shù)??梢韵衿渌?shell 變量一樣在這些變量前面加上一個(gè) $ 符號(hào)來(lái)引用這些變量。
表 4. 函數(shù)的 Shell 參數(shù)
參數(shù) |
用途 |
0, 1, 2, ... |
從參數(shù) 0 開始的位置參數(shù)。參數(shù) 0 指的是啟動(dòng) bash 的程序名;如果函數(shù)是在一個(gè) shell 腳本中運(yùn)行的,就是這個(gè) shell 腳本的名字。有關(guān)其他可能的信息,請(qǐng)參看 bash 的手冊(cè)頁(yè),例如使用 -c 參數(shù)啟動(dòng) bash 時(shí)的情況。以單引號(hào)或雙引號(hào)括起來(lái)的字符串都會(huì)當(dāng)作一個(gè)參數(shù)傳遞,引號(hào)會(huì)被剝離掉。在雙引號(hào)的情況中,諸如 $HOME 之類的 shell 變量會(huì)在調(diào)用函數(shù)之前被展開。您可能需要使用單引號(hào)或雙引號(hào)來(lái)傳遞參數(shù),這些參數(shù)可以包含對(duì) shell 具有特殊意義的嵌入空格或其他字符。 |
* |
從參數(shù) 1 開始的位置參數(shù)。如果已經(jīng)把雙引號(hào)中的內(nèi)容展開了,那么展開后就是一個(gè)單詞,使用域間分隔符(IFS)特殊變量的第一個(gè)字符來(lái)分隔參數(shù);如果 IFS 為空,就不會(huì)插入任何分隔。默認(rèn)的 IFS 值可以是空白、制表符和換行符。如果 IFS 沒(méi)有設(shè)置,那么所使用的分隔符就是空白,就像默認(rèn)的 IFS 一樣。 |
@ |
從參數(shù) 1 開始的位置參數(shù)。如果已經(jīng)把雙引號(hào)中的內(nèi)容展開了,那么每個(gè)參數(shù)都變成一個(gè)單詞,因此 “$@” 就等于 “$1”“$2”...。如果參數(shù)中可能會(huì)包含嵌入空白,就可以使用這種格式。 |
# |
參數(shù)個(gè)數(shù),不包括參數(shù) 0。 |
注意: 如果參數(shù)多于 9 個(gè),就不能使用 $10 來(lái)引用第 10 個(gè)參數(shù)。而必須首先處理或保存第一個(gè)參數(shù)($1),然后使用 shift 命令來(lái)刪除第 1 個(gè)參數(shù),并將其他參數(shù)下移 1 位,這樣 $10 就變成了 $9,依此類推。$# 的值也同時(shí)會(huì)被更新,從而反應(yīng)剩余參數(shù)的個(gè)數(shù)。
現(xiàn)在可以定義一個(gè)簡(jiǎn)單函數(shù),其功能僅僅是說(shuō)明有多少個(gè)參數(shù),并顯示這些參數(shù);如清單 12 所示。
清單 22. 函數(shù)參數(shù)
[ian@pinguino developerworks]$ testfunc () { echo "$# parameters"; echo "$@"; }
[ian@pinguino developerworks]$ testfunc
0 parameters
[ian@pinguino developerworks]$ testfunc a b c
3 parameters
a b c
[ian@pinguino developerworks]$ testfunc a "b c"
2 parameters
a b c
|
不管使用的是 $*、"$*"、$@ 還是 "$@",在上面這個(gè)函數(shù)的輸出結(jié)果中并沒(méi)有太大區(qū)別,不過(guò)當(dāng)問(wèn)題變得復(fù)雜時(shí),可以肯定區(qū)別將會(huì)變得非常大。
現(xiàn)在,用這個(gè)到目前為止最為復(fù)雜的命令來(lái)創(chuàng)建一個(gè) ldirs 函數(shù),使用 “$@” 表示參數(shù)??梢韵袂懊娴睦右粯訉⑷亢瘮?shù)都輸入到一行中;當(dāng)然 bash 也允許在多行中輸入命令,在這種情況中會(huì)自動(dòng)添加分號(hào),如清單 23 所示。清單 23 還顯示了使用 type 命令來(lái)顯示函數(shù)定義。注意在 type 的輸出結(jié)果中, ls 命令已經(jīng)被它別名的展開值替換掉了。如果需要避免這個(gè)問(wèn)題,可以使用 /bin/ls 而不是單單的 ls 。
清單 23. 第一個(gè) ldirs 函數(shù)
[ian@pinguino developerworks]$ # Enter the function on a single line
[ian@pinguino developerworks]$ ldirs () { ls -l "$@"|sed -ne ‘s/^d\([^ ]* *\)\{8\}//p‘; }
[ian@pinguino developerworks]$ # Enter the function on multiple lines
[ian@pinguino developerworks]$ ldirs ()
> {
> ls -l "$@"|sed -ne ‘s/^d\([^ ]* *\)\{8\}//p‘
> }
[ian@pinguino developerworks]$ type ldirs
ldirs is a function
ldirs ()
{
ls --color=tty -l "$@" | sed -ne ‘s/^d\([^ ]* *\)\{8\}//p‘
}
[ian@pinguino developerworks]$ ldirs
my dw article
readme
schema
tools
web
xsl
[ian@pinguino developerworks]$ ldirs tools
java
|
現(xiàn)在您的函數(shù)似乎已經(jīng)可以正常工作了。但是如果像清單 24 那樣運(yùn)行 ldirs * 會(huì)如何呢?
清單 24. 運(yùn)行 ldirs *
[ian@pinguino developerworks]$ ldirs *
5.6
java
www.ibm.com
5.6
|
感到驚奇嗎?實(shí)際上,您并沒(méi)有找到當(dāng)前目錄中的目錄,而是找到了第 2 級(jí)子目錄的內(nèi)容。查看一下 ls 命令的手冊(cè)頁(yè)或本系列前面的教程就可以理解這是為什么了?;蛘呦袂鍐?25 那樣運(yùn)行 find 命令來(lái)查找第 2 級(jí)子目錄名。
清單 25. 查找第 2 級(jí)子目錄
[ian@pinguino developerworks]$ find . -mindepth 2 -maxdepth 2 -type d
./tools/java
./web/www.ibm.com
./xsl/5.6
./schema/5.6
|
添加測(cè)試
使用通配符暴露了這種方法在邏輯上存在的一個(gè)問(wèn)題。我們忽略了這樣的一個(gè)事實(shí),即不使用任何參數(shù)時(shí) ldirs 顯示的是當(dāng)前目錄的子目錄,而 ldirs tools 顯示的是 tools 目錄中的 java 子目錄,而不是 tools 目錄本身,這與將 ls 命令用于文件而非目錄的情形是一樣的。理想情況下,如果沒(méi)有給定參數(shù),就應(yīng)該使用 ls -l ;如果給定了一些參數(shù),就應(yīng)該使用 ls -ld 命令??梢允褂?test 命令來(lái)測(cè)試參數(shù)個(gè)數(shù),然后使用 && 和 || 來(lái)構(gòu)建一個(gè)命令列表,并執(zhí)行適當(dāng)?shù)拿?。使?test 的 [ test expression ] 格式,您的表達(dá)式可能會(huì)是這樣: { [ $# -gt 0 ] &&/bin/ls -ld "$@" || /bin/ls -l } | sed -ne ... 。
不過(guò)這段代碼還有一個(gè)小問(wèn)題,如果 ls -ld 命令不能找到任何匹配文件或目錄,就會(huì)產(chǎn)生一條錯(cuò)誤消息,并返回一個(gè)非 0 的退出代碼,這會(huì)導(dǎo)致 ls -l 命令也會(huì)被執(zhí)行。這可能并不是我們所期望的。一個(gè)解決的方案是為第一個(gè) ls 命令構(gòu)造一個(gè)復(fù)合命令,這樣如果命令失敗,就可以對(duì)參數(shù)個(gè)數(shù)再次進(jìn)行測(cè)試??梢詫?duì)原來(lái)的函數(shù)進(jìn)行擴(kuò)充來(lái)包含這種功能,現(xiàn)在這個(gè)函數(shù)應(yīng)該如清單 26 所示??梢岳们鍐?26 中的參數(shù)來(lái)嘗試使用該函數(shù),也可以利用您自己的參數(shù)來(lái)體驗(yàn)一下,看這個(gè)函數(shù)是怎樣工作的。
清單 26. 使用 ldirs 處理通配符
[ian@pinguino ~]$ type ldirs
ldirs is a function
ldirs ()
{
{
[ $# -gt 0 ] && {
/bin/ls -ld "$@" || [ $# -gt 0 ]
} || /bin/ls -l
} | sed -ne ‘s/^d\([^ ]* *\)\{8\}//p‘
}
[ian@pinguino developerworks]$ ldirs *
my dw article
readme
schema
tools
web
xsl
[ian@pinguino developerworks]$ ldirs tools/*
tools/java
[ian@pinguino developerworks]$ ldirs *xxx*
/bin/ls: *xxx*: No such file or directory
[ian@pinguino developerworks]$ ldirs *a* *s*
my dw article
readme
schema
schema
tools
xsl
|
最終版本
現(xiàn)在,在清單 26 中給出的這個(gè)例子中,可以看到一個(gè)目錄被列出了兩次。如果希望,可以通過(guò) sort | uniq 對(duì) sed 的輸出結(jié)果進(jìn)行過(guò)濾,從而擴(kuò)充原來(lái)的函數(shù)來(lái)解決這個(gè)問(wèn)題。
從一些基本的構(gòu)造塊開始,現(xiàn)在您已經(jīng)構(gòu)建了一個(gè)非常復(fù)雜的 shell 函數(shù)了。
定制擊鍵組合
您在終端會(huì)話中輸入的擊鍵組合,以及在諸如 FTP 之類的程序中使用的擊鍵組合,都是由 readline 庫(kù)進(jìn)行處理的,并且可以進(jìn)行配置。默認(rèn)情況下,定制文件是主目錄中的 .inputrc 文件;如果系統(tǒng)中存在這個(gè)文件,就會(huì)在 bash 啟動(dòng)過(guò)程中讀取這個(gè)文件??梢酝ㄟ^(guò)設(shè)置 INPUTRC 變量來(lái)配置不同的文件。如果沒(méi)有設(shè)置這個(gè)變量,就會(huì)使用主目錄中的 .inputrc 文件。很多系統(tǒng)在 /etc/inputrc 中都有一個(gè)默認(rèn)的鍵映射,因此您通常會(huì)希望使用 $include 指令來(lái)包含它。
清單 27 展示了如何將 ldirs 函數(shù)綁定到 Ctrl-t 的鍵盤組合上(按下并一直按著 Ctrl 鍵,然后按下 t)。如果希望此命令執(zhí)行時(shí)不使用任何參數(shù),可以在配置行末尾添加 \n。
清單 27. 樣例 .inputrc 文件
# My custom key mappings
$include /etc/inputrc
|
可以通過(guò)先按 Ctrl-x 再按 Ctrl-r 來(lái)強(qiáng)制再次讀取 INPUTRC 文件。注意如果沒(méi)有自己的 .inputrc 文件,有些發(fā)行版會(huì)設(shè)置 INPUTRC=/etc/inputrc,因此如果您在這種系統(tǒng)上創(chuàng)建了 .inputrc 文件,就需要先登出系統(tǒng),然后再登錄一次,這樣才能使用新的定義。只將 INPUTRC 設(shè)置為空或?qū)⑵渲赶蛐挛募粫?huì)重新讀取原來(lái)的文件,而不是新的規(guī)范。
INPUTRC 文件可以包括一些條件規(guī)范。例如,您的鍵盤行為可能會(huì)根據(jù)您使用的是 emacs 編輯模式(bash 默認(rèn)值)還是 vi 模式而有所不同。有關(guān)如何定制鍵盤的更多細(xì)節(jié),請(qǐng)參看 bash 的手冊(cè)頁(yè)。
保存別名和函數(shù)
您可以將自己的別名和函數(shù)添加到自己的 ~/.bashrc 文件中,不過(guò)也可以將它們保存到任何您喜歡的文件中。不管怎樣做,都請(qǐng)記住使用 source 或 . 命令來(lái)引用這些文件,這樣就會(huì)讀取文件的內(nèi)容,并在當(dāng)前環(huán)境中執(zhí)行這個(gè)文件。如果創(chuàng)建了一個(gè)腳本并簡(jiǎn)單執(zhí)行它,那么這個(gè)腳本就是在一個(gè)子 shell 中執(zhí)行的,當(dāng)這個(gè)子 shell 退出并將控制權(quán)返回給您時(shí),所有有價(jià)值的定制就全部丟失了。
在下一節(jié)中,將學(xué)習(xí)如何超越這些簡(jiǎn)單的函數(shù),如何添加一些編程結(jié)構(gòu),例如條件測(cè)試和循環(huán)結(jié)構(gòu),并將它們與多個(gè)函數(shù)結(jié)合起來(lái)來(lái)創(chuàng)建或修改 bash shell 腳本。
|