一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

主題 109: Shell、腳本、編程和編譯

 dazheng 2007-04-02

LPI 102 考試準(zhǔn)備,主題 109: Shell、腳本、編程和編譯

初級(jí)管理(LPIC-1)主題 109

developerWorks
第 2 頁(yè),共 6 頁(yè)


對(duì)本教程的評(píng)價(jià)

幫助我們改進(jìn)這些內(nèi)容


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è)命令的退出碼




回頁(yè)首


設(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
                        

注意:

  1. 在這些操作開始時(shí),Bash shell 的 PID 是 30576。

  2. 第二個(gè) Bash shell 的 PID 是 16353,其父 shell 的 PID 是 30576,也就是原來(lái)的 Bash shell。

  3. 我們?cè)诘诙€(gè) Bash shell 中創(chuàng)建了 VAR1、VAR2 和 VAR3 三個(gè)變量,但是只導(dǎo)出了 VAR2 和 VAR3。

  4. 在 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

  5. 現(xiàn)在回到第二個(gè) Bash shell 中,我們可以看到 VAR1、VAR2 和 VAR3。

  6. 最后,當(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
                        





回頁(yè)首


取消變量

可以使用 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í)也是如此。





回頁(yè)首


配置文件

在登錄 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ì)使用該文件。





回頁(yè)首


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 顯示了 whichvi 的別名。


清單 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、mvrm 命令的時(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‘
                        





回頁(yè)首


命令列表

在之前的教程 “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)單地將 lsdu 命令序列賦值給別名 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"
                        

終于成功了。





回頁(yè)首


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ū)分文件和目錄
使用 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 還有很多工具可以使用,因此可以嘗試使用 seqprintf 命令來(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)在,讓我們使用 seqprintf 命令來(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ù)拿?。使?testtest 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ù)了。





回頁(yè)首


定制擊鍵組合

您在終端會(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è)。





回頁(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 腳本。





回頁(yè)首

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多

    成年女人下边潮喷毛片免费| 日韩成人免费性生活视频| 中文字幕一区二区三区大片| 日本熟妇五十一区二区三区| 午夜精品福利视频观看| 国产精品成人一区二区在线| 国产精品熟女乱色一区二区| 国产传媒精品视频一区| 中文字幕中文字幕一区二区| 国产精品白丝一区二区| 国产老熟女乱子人伦视频| 国产欧美日韩精品一区二区| 日本一二三区不卡免费| 亚洲最新的黄色录像在线| 国产丝袜极品黑色高跟鞋| 久久91精品国产亚洲| 熟女高潮一区二区三区| 欧美午夜色视频国产精品| 国产成人精品午夜福利av免费| 国产日韩欧美专区一区| 一区二区三区在线不卡免费| 国产美女网红精品演绎| 久久精品免费视看国产成人| 女生更色还是男生更色| 国产不卡免费高清视频| 国产精品一区二区视频| 很黄很污在线免费观看| 日本不卡一区视频欧美| 欧美又大又黄刺激视频| 麻豆欧美精品国产综合久久| 开心五月激情综合婷婷色| 国产美女网红精品演绎| 欧美日韩最近中国黄片| 久久99国产精品果冻传媒| 国产精品丝袜美腿一区二区| 成人亚洲国产精品一区不卡| 午夜精品一区二区av| 亚洲一区二区精品久久av| 99亚洲综合精品成人网色播| 国产成人精品在线一区二区三区| 日韩欧美在线看一卡一卡|