章 7. Bash 和 Bash 程序檔

目錄

7.1. 什麼是「外圍程序」?
7.2. 寫入外圍程序程序檔
7.3. 重新指向指令事件
7.4. 使用別名
7.5. 使用 Bash 中的變數
7.6. 分組與組合指令
7.7. 使用通用流程建構元
7.8. 如需更多資訊

摘要

如今,有許多人使用具有圖形使用者介面 (GUI) 的電腦,例如 KDE 或 GNOME 介面。僅管這些介面提供了很多功能,但使用它們執行自動任務時,還是會有限制。外圍程序是 GUI 的有效補充,本章概述了外圍程序 (以 Bash 為例) 的一些方面。

7.1. 什麼是「外圍程序」?

一般而言,外圍程序就是 Bash (Bourne again Shell)。本章中提及的「外圍程序」指的是 Bash。實際上,可用的外圍程序不止 Bash (還有 ash、csh、ksh、zsh、…),每個外圍程序都包含不同的功能和特性。如需有關其他外圍程序的詳細資訊,請在 YaST 中搜尋外圍程序

7.1.1. 瞭解 Bash 組態檔案

外圍程序可啟用為︰

  1. 互動式登入外圍程序。使用 --login 選項啟用 Bash 以登入機器,或使用 SSH 登入遠端機器時會採用這種方式。

  2. 「一般」互動式外圍程序。啟動 xterm、konsole、gnome-terminal 或類似工具時通常會採用這種方式。

  3. 非互動式外圍程序。在指令行中呼叫外圍程序程序檔時使用這種方式。

系統會讀取不同的組態檔案,視所使用的外圍程序類型而定。下面的表格顯示了登入與非登入外圍程序組態檔案。

表格 7.1. 登入外圍程序的 Bash 組態檔案

檔案

描述

/etc/profile

請勿修改此檔案,否則您的修改在下次更新時可能會被破坏!

/etc/profile.local

擴充 /etc/profile 時使用此檔案

/etc/profile.d/

包含特定程式的系統級組態檔案

~/.profile

在此處插入登入外圍程序的使用者特定組態


表格 7.2. 非登入外圍程序的 Bash 組態檔案

/etc/bash.bashrc

請勿修改此檔案,否則您的修改在下次更新時可能會被破坏!

/etc/bash.bashrc.local

使用此檔案只能插入 Bash 的系統級修改

~/.bashrc

在此處插入使用者特定的組態


此外,Bash 還使用其他檔案︰

表格 7.3. Bash 的特殊檔案

檔案

描述

~/.bash_history

包含您鍵入的所有指令清單

~/.bash_logout

登出時執行


7.1.2. 目錄結構

下表概述了 Linux 系統中最重要的較高層級目錄。下列清單中提供了關於目錄與重要子目錄的更多詳細資訊。

表格 7.4. 標準目錄網路樹的綜覽

目錄

內容

/

根目錄 — 目錄樹的起點。

/bin

基本的二進位檔案,例如系統管理員與一般使用者都需要使用的指令。通常還包含 Bash 等外圍程序。

/boot

開機載入程式的靜態檔案。

/dev

存取主機特定設備所需的檔案。

/etc

主機特定系統的組態檔案。

/home

存放系統中所有擁有帳戶之使用者的主目錄。但是,root 的主目錄不在 /home 中,而是位於 /root 內。

/lib

基本的共享程式庫與核心模組。

/media

抽取式媒體的定點。

/mnt

用於暫時掛接檔案系統的定點。

/opt

附加應用程式軟體套件。

/root

超級使用者 root 的主目錄。

/sbin

基本的系統二進位檔案。

/srv

系統所提供之服務的資料。

/tmp

暫存檔案。

/usr

包含唯讀資料的次要階層。

/var

可變資料,例如記錄檔案。

/windows

僅當系統中同時安裝了 Microsoft Windows* 與 Linux 才可以使用。包含 Windows 資料。


以下清單提供了更多詳細資訊,以及目錄中包含的檔案與子目錄的一些範例︰

/bin

包含 root 及其他使用者可能會使用的基本外圍程序指令。這些指令包括 lsmkdircpmvrm 以及 rmdir/bin 還包含 SUSE Linux Enterprise Desktop 中的預設外圍程序 Bash。

/boot

包含開機所需的資料,例如開機載入程式、核心及核心開始執行使用者模式程式之前所使用的其他資料。

/dev

存放代表硬體元件的設備檔案。

/etc

包含控制 X Window System 等程式的操作的本地組態檔案。/etc/init.d 子目錄包含開機期間執行的程序檔。

/home/使用者名稱

存放系統中每個擁有帳戶之使用者的個人資料。只有檔案擁有者或系統管理員才能修改位於此處的檔案。依預設,電子郵件目錄與個人桌面組態以隱藏檔案與目錄的形式存放於此。KDE 使用者可在 .kde4 中找到其桌面系統的個人組態資料,而 GNOME 使用者可在 .gconf 中找到該資料。

[Note]網路環境中的主目錄

如果您是在網路環境中工作,您的主目錄可能會對應至檔案系統中 /home 以外的目錄。

/lib

包含啟動系統及執行根檔案系統中指令所需的基本共享程式庫。在 Windows 中,對應的共享程式庫為 DLL 檔案。

/media

包含 CD-ROM、USB 晶片組及數位相機 (若使用 USB) 等抽取式媒體的掛接點。/media 通常存放系統硬碟之外的任何類型磁碟機或光碟機。抽取式媒體插入或連接到系統並進行掛接後,您就可以從此處存取該媒體。

/mnt

此目錄提供了暫時掛接之檔案系統的定點。root 可在此處掛接檔案系統。

/opt

為安裝協力廠商軟體而保留。這裡有選擇性軟體與大型附加程式套件。

/root

root 使用者的主目錄。這裡有 root 的個人資料。

/sbin

s 所指示,此目錄存放適用於超級使用者的公用程式。/sbin 不僅包含 /bin 中的二進位檔案,還包含啟動、還原及復原系統所必需的二進位檔案。

/srv

存放系統所提供之服務的資料,例如 FTP 與 HTTP。

/tmp

需要檔案暫時儲存區的程式會使用此目錄。

[Important]開機時清理 /tmp

系統重新開機後,先前儲存於 /tmp 中的資料無法保證仍然存在。這視情況而定,例如,取決於 /etc/sysconfig/cron 中的設定。

/usr

/usr 與使用者無關,而是 UNIX 系統資源 (UNIX system resource) 的縮寫。/usr 中的資料是靜態的唯讀資料,可依照檔案系統階層標準 (Filesystem Hierarchy Standard, FHS) 在不同的主機之間共享。此目錄包含所有應用程式,並且會在檔案系統中建立次要階層。KDE4 與 GNOME 也位於此處。/usr 存放了許多子目錄,例如 /usr/bin/usr/sbin/usr/local 以及 /usr/share/doc

/usr/bin

包含一般情況下可存取的程式。

/usr/sbin

包含為系統管理員保留的程式,例如修復功能。

/usr/local

在此目錄中,系統管理員可安裝獨立於套裝作業系統的本地延伸。

/usr/share/doc

存放系統的各種文件檔案與版本說明。在 manual 子目錄中,可找到此手冊的線上版本。如果安裝了多種語言,此目錄可能會包含不同語言的手冊版本。

packages 內,可找到系統上安裝之軟體套件所包含的文件。每個套件都有一個子目錄 /usr/share/doc/packages/套件名稱,該目錄通常用於存放套件的讀我檔案,有時也會存放範例、組態檔案或其他程序檔。

如果系統中安裝了 HOWTO,/usr/share/doc 還會包含 howto 子目錄,其中有許多與 Linux 軟體設定及操作相關之任務的其他文件。

/var

/usr 存放的是靜態唯讀資料,而 /var 存放的是系統操作時寫入的資料,因此為可變資料,例如記錄檔案或多工緩衝處理資料。如需 /var/log/ 中包含之最重要記錄檔的綜覽,請參閱表格 28.1 「記錄檔案」

/windows

僅當系統中同時安裝了 Microsoft Windows 與 Linux 才可以使用。包含可在系統的 Windows 分割區上使用的 Windows 資料。您是否可以編輯此目錄中的資料取決於 Windows 分割區使用的檔案系統。如果是 FAT32,則您可以開啟並編輯此目錄中的檔案。如果是 NTFS,SUSE Linux Enterprise Desktop 還允許寫入存取。但是,適用於 NTFS-3g 檔案系統的驅動程式所提供的功能有限。

7.2. 寫入外圍程序程序檔

使用外圍程序程序檔可以方便地完成各種任務︰收集資料、搜尋文字中的單字或片語,以及執行很多其他有用的操作。以下範例顯示了一個列印文字的小型外圍程序程序檔︰

範例 7.1. 列印文字的外圍程序程序檔

#!/bin/sh 1
# Output the following line: 2
echo "Hello World" 3

1

第一行以 Shebang 字元 (#!) 開頭,指出此檔案為程序檔。程序檔透過 Shebang 後面指定的解譯器執行,在此例中為 /bin/sh

2

第二行為備註,以 # 開頭。建議將較為複雜的行設為備註,以便記住其作用。

3

第三行使用內建指令 echo 列印相應的文字。


您需要符合一些先決條件才能執行此程序檔︰

  1. 每個程序檔都應包含一行 Shebang 行 (上面的範例即是如此)。如果程序檔未包含此行,您需要手動呼叫直譯器。

  2. 您可以將程序檔儲存於任何位置。但是,最好將其儲存於外圍程序可以找到的目錄中。外圍程序中的搜尋路徑由環境變數 PATH 決定。一般使用者通常沒有寫入 /usr/bin 的權限。因此,建議將程序檔儲存在使用者目錄 ~/bin/ 中。以上範例名為 hello.sh

  3. 程序檔需要執行權限。使用下列指令設定權限︰

    chmod +x ~/bin/hello.sh

如果滿足了上述所有先決條件,便可以按以下方式執行程序檔︰

  1. 絕對路徑.  執行程序檔時可以使用絕對路徑。在此例中為 ~/bin/hello.sh

  2. 任何位置.  如果 PATH 環境變數包含程序檔所在的目錄,則只需使用 hello.sh 便可執行程序檔。

7.3. 重新指向指令事件

每條指令可以使用三個通道用於輸入或輸出︰

  • 標準輸出.  這是預設的輸出通道。指令進行列印時會使用標準輸出通道。

  • 標準輸入.  如果指令需要使用者或其他指令的輸入,將會使用此通道。

  • 標準錯誤.  指令使用此通道報告錯誤。

要重新指向這些通道,可以使用以下幾種方式︰

指令 > 檔案

將指令輸出儲存為檔案,現有的檔案將會刪除。例如,ls 指令將輸出寫入到檔案 listing.txt 中︰

ls > listing.txt
指令 >> 檔案

將指令輸出附加至檔案。例如,ls 指令將輸出附加至檔案 listing.txt 中︰

ls >> listing.txt
指令 < 檔案

讀取檔案,將其做為指定指令的輸入。例如,read 指令會將檔案內容讀取至變數中︰

read a < foo
指令1 | 指令2

將左邊指令的輸出重新指向為右邊指令的輸入。例如,cat 指令會輸出 /proc/cpuinfo 檔案的內容。再由 grep 使用此輸出內容單獨過濾出包含 cpu 的行︰

cat /proc/cpuinfo | grep cpu

每個通道都有一個檔案描述子︰0 (零) 代表標準輸入,1 代表標準輸出,2 代表標準錯誤。您可以將此檔案描述子插入到 <> 字元的前面。例如,下行將搜尋以 foo 開始的檔案,但透過將檔案重新指向至 /dev/null 隱藏了錯誤︰

find / -name "foo*" 2>/dev/null

7.4. 使用別名

別名為一或多條指令的簡短定義。別名的語法為︰

alias NAME=DEFINITION

例如,下面這一行定義了別名 lt,它會輸出一份較長的清單 (選項 -l),按修改時間排序 (-t),並按相反順序進行列印 (-r)︰

alias lt='ls -ltr'

要檢視所有的別名定義,請使用 alias。若要移除別名,請使用 unalias 和對應的別名名稱。

7.5. 使用 Bash 中的變數

外圍程序變數可以是全域變數或本地變數。您可以在所有外圍程序中存取全域變數或環境變數。與此相反,本地變數僅顯示於目前的外圍程序中。

要檢視所有環境變數,請使用 printenv 指令。如需瞭解變數的值,則將變數名稱做為引數插入︰

printenv PATH

無論是全域變數還是本地變數,都可以使用 echo 進行檢視︰

echo $PATH

要設定本地變數,請使用變數名稱,後面跟上等號,再跟上值︰

PROJECT="SLED"

請不要在等號兩邊插入空格,否則將會出錯。要設定環境變數,請使用 export ︰

export NAME="tux"

若要移除變數,請使用 unset

unset NAME

下表包含了部分可在外圍程序程序檔中使用的常用環境變數︰

表格 7.5. 有用的環境變數

HOME

目前使用者的主目錄

HOST

目前的主機名稱

LANG

工具當地化以後,會使用此環境變數指定的語言。也可將英語設定為 C

PATH

外圍程序的搜尋路徑,即以冒號分隔的目錄清單

PS1

指定在每條指令前列印的一般提示

PS2

指定執行多行指令時列印的輔助提示

PWD

目前的工作目錄

USER

目前的使用者


7.5.1. 使用引數變數

例如,如果您有程序檔 foo.sh,可以按以下格式執行該程序檔︰

foo.sh "Tux Penguin" 2000 

若要存取傳送至程序檔的所有引數,需要使用位置參數。$1 代表第一個引數的位置參數,$2 代表第二個引數的位置參數,依此類推。最多可以使用九個參數。要獲取程序檔名稱,請使用 $0

下面的程序檔 foo.sh 可列印從 1 到 4 的所有引數︰

#!/bin/sh
echo \"$1\" \"$2\" \"$3\" \"$4\"

如果您使用以上引數執行此程序檔,所得結果為︰

"Tux Penguin" "2000" "" ""

7.5.2. 使用變數替代項

變數替代項會從左側或右側將模式套用至變數內容。以下清單包含了可用的語法格式︰

${VAR#pattern}

從左側移除最短的相符項︰

file=/home/tux/book/book.tar.bz2
echo ${file#*/}
home/tux/book/book.tar.bz2
${VAR##pattern}

從左側移除最長的相符項︰

file=/home/tux/book/book.tar.bz2
echo ${file##*/}
book.tar.bz2
${VAR%pattern}

從右側移除最短的相符項︰

file=/home/tux/book/book.tar.bz2
echo ${file%.*}
/home/tux/book/book.tar
${VAR%%pattern}

從右側移除最長的相符項︰

file=/home/tux/book/book.tar.bz2
echo ${file%%.*}
/home/tux/book/book
${VAR/pattern_1/pattern_2}

使用 pattern_2 替代 pattern_1VAR 的內容︰

file=/home/tux/book/book.tar.bz2
echo ${file/tux/wilber}
/home/wilber/book/book.tar.bz2

7.6. 分組與組合指令

外圍程序允許您組合及分組指令,以便按條件執行。每條指令都會傳回決定操作成功與否的離開碼。如果為 0 (零),則說明指令成功,任何其他離開碼都代表特定於指令的錯誤。

以下清單顯示了可對指令分組的方式︰

指令1 ; 指令2

以順序執行指令。不檢查離開碼。下行透過 cat 顯示檔案內容,然後透過 ls 列印其檔案內容,而不管其離開碼為何︰

cat filelist.txt ; ls -l filelist.txt
指令1 && 指令2

如果左邊的指令成功,即會執行右邊的指令 (邏輯「與」)。下行顯示檔案內容,並且僅在前面的指令成功時才會列印其檔案內容 (將其與此清單中的上一個項目進行比較)︰

cat filelist.txt && ls -l filelist.txt
指令1 || 指令2

如果左邊的指令失敗,即會執行右邊的指令 (邏輯「或」)。下行將只會在於 /home/tux/foo 中建立目錄失敗時,才會在 /home/wilber/bar 中建立目錄︰

mkdir /home/tux/foo || mkdir /home/wilber/bar
funcname(){ ... }

建立外圍程序函數。可以使用位置參數存取其引數。下行定義了可列印較短訊息的函數 hello

hello() { echo "Hello $1"; }

可以按以下格式呼叫此函數︰

hello Tux

將會列印︰

Hello Tux

7.7. 使用通用流程建構元

為了控制程序檔的流程,外圍程序包含 whileifforcase 建構元。

7.7.1. If 控制指令

If 指令用於檢查運算式。例如,以下程式碼將測試目前的使用者是否為 Tux︰

if test $USER = "tux"; then
  echo "Hello Tux."
else
  echo "You are not Tux."
fi

測試運算式可以很複雜,也可以很簡單。下面的運算式會檢查檔案 foo.txt 是否存在︰

if test -e /tmp/foo.txt ;
then
  echo "Found foo.txt"
fi

測試運算式也可以縮寫到角括弧中︰

if [ -e /tmp/foo.txt ] ; then
  echo "Found foo.txt"
fi

如需更多有用的運算式,請參閱 http://www.cyberciti.biz/nixcraft/linux/docs/uniqlinuxfeatures/lsst/ch03sec02.html

7.7.2. 使用 For 指令建立迴路

for 迴路可讓您對一組項目執行指令。例如,以下程式碼會列印目前目錄中關於 PNG 檔案的部分資訊︰

for i in *.png; do
 ls -l $i
done

7.8. 如需更多資訊

man 頁面 man sh 中提供了關於 Bash 的重要資訊。以下清單中提供了更多關於此主題的資訊︰