二十二. 交互式使用Bash Shell:
1. 用set命令設置bash的選項:
下面為set主要選項的列表及其表述:
選項名 | 開關縮寫 | 描述 |
allexport | -a | 打開此開關,所有變量都自動輸出給子Shell。 |
noclobber | -C | 防止重定向時文件被覆蓋。 |
noglob | -d | 在路徑和文件名中,關閉通配符。 |
#打開該選項
/> set -o allexport #等同於set -a
#關閉該選項
/> set +o allexport #等同於set +a
#列出當前所有選項的當前值。
/> set -o
allexport off
braceexpand on
emacs on
errexit off
errtrace off
functrace off
hashall on
histexpand on
... ...
/> set -o noclobber #打開noclobber選項,防止在重定向時原有文件被覆蓋。
/> date > outfile #通過date命令先生成一個文件outfile。
/> ls > outfile #將ls命令的輸出重定向到該文件outfile,shell將提示不能覆蓋已經存在的文件。
-bash: outfile: cannot overwrite existing file
/> set +o noclobber #關閉noclobber選項。
/> ls > outfile #重新將ls的輸出重定向到outfile,成功。
2. 變量:
設置局部變量:
/> name="stephen liu" #注意等號兩邊不要有空格,如果變量值之間存在空格,則需要用雙引號括起
/> echo $name
stephen liu
/> name= #將變量設置為空時,等號后面也不要有空格,直接回車即可。
/> echo $name #name變量為空,因此echo不會有任何輸出。
注意:以上變量的聲明方式均可替換為declare variable=value的形式。
/> declare name="stephen liu"
/> readonly name #將name變量設置為只讀。
/> echo $name
stephen liu
/> name="my wife" #如果針對只讀變量重新賦值,將報錯,提示name是只讀變量。
-bash: name: readonly variable
/> unset name #如果unset只讀變量,將同樣報錯,提示不能unset只讀變量。
-bash: unset: name: cannot unset: readonly variable
設置全局/環境變量:
在當前Shell中創建的全局/環境變量可以直接傳遞給它所有的子Shell,當前創建環境變量的Shell被稱為夫Shell。
/> export allname=john #利用export命令,將其后聲明的變量置為環境變量
/> bash #啟動一個新的子Shell
/> echo $allname #在子Shell中echo變量$allname,發現夫Shell中設置的值被傳遞到子Shell
john
/> declare -x allname2=peter #這里的功能和結果都是和上面的命令相同,只是利用declare -x命令設置環境變量
/> bash
/> echo $allname2
peter
下面的列表將給出常用的內置Shell環境變量:
變量名 | 含義 |
BASH | 表示bash命令的完整路徑名。 |
ENV | 在啟動新bash shell時執行的環境文件名。 |
HOME | 主目錄。 |
LANG | 本地化語言。 |
PATH | 命令搜索路徑,彼此之間冒號分隔。 |
PPID | 父進程PID。 |
PWD | 當前工作目錄,用cd命令設置。 |
3. echo命令:
該命令主要用於將其參數打印到標准輸出。其中-e選項使得echo命令可以無限制地使用轉義序列控制輸出的效果。下面的列表給出常用的轉義序列。
轉義序列 | 功能 |
\c | 不換行打印 |
\n | 換行 |
\t | 制表符 |
\\ | 反斜杠 |
echo還提供了一個常用的-n選項,其功能不輸出換行符。
/> echo The username is $LOGNAME
The username is stephen
#下面命令的輸出中的“/>”表示命令行提示符。
/> echo -e "\tHello World\c"
Hello World />
/> echo -n "Hello World"
Hello World />
4. printf命令:
該命令和C語言中的printf函數的功能相同,都用用來格式化輸出的。格式包括字符串本身和描述打印效果的字符。定義格式的方法和C語言也是完全一樣 的,即在%后面跟一個說明符,如%f表示后面是一個浮點數,%d表示一個整數。printf命令也同樣支持轉義序列符,其常用轉義序列如下:
轉義序列 | 功能 |
\c | 不換行打印 |
\n | 換行 |
\t | 制表符 |
\\ | 反斜杠 |
\" | 雙引號 |
其常用的格式化說明符列表如下:
說明符 | 描述 |
%c | ASCII字符 |
%d,%i | 十進制整數 |
%f | 浮點格式 |
%o | 不帶正負號的八進制值 |
%s | 字符串 |
%u | 不帶正負號的十進制值 |
%x | 不帶正負號的十六進制值,其中使用a-f表示10-15 |
%X | 不帶正負號的十六進制值,其中使用A-F表示10-15 |
%% | 表示%本身 |
下面是printf的一些常用使用方式:
/> printf "The number is %.2f.\n" 100 這里.2f表示保留小數點后兩位
The number is 100.00.
#%-20s表示一個左對齊、寬度為20個字符字符串格式,不足20個字符,右側補充相應數量的空格符。
#%-15s表示一個左對齊、寬度為15個字符字符串格式。
#%10.2f表示右對齊、10個字符長度的浮點數,其中一個是小數點,小數點后面保留兩位。
/> printf "%-20s%-15s%10.2f\n" "Stephen" "Liu" 35
Stephen Liu 35.00
#%10s表示右對齊、寬度為10的字符串,如不足10個字符,左側補充相應數量的空格符。
/> printf "|%10s|\n" hello
| hello|
在printf中還有一些常用的標志符,如上面例子中的符號(-),這里我們再介紹一個比較常用的標識符"#"
#如果#標志和%x/%X搭配使用,在輸出十六進制數字時,前面會加0x/0X前綴。
/> printf "%x %#x\n" 15 15
f 0xf
5. 變量替換運算符:
bash中提供了一組可以同時檢驗和修改變量的特定修改符。這些修改符提供了一個快捷的方法來檢驗變量是不是被設置過,並把輸出結果輸出到一個變量中,見下表:
修改符 | 描述 | 用途 |
${variable:-word} | 如variable被設置且非空,則返回該值,否則返回word,變量值不變。 | 如變量未定義,返回默認值。 |
${variable-word} | 如variable未被設置,則返回word,變量值不變,如果設置變量,則返回變量值,即使變量的值為空值。 | 如變量未設置,返回默認值。 |
${variable:=word} | 如variable被設置且非空,則返回該值,否則設置變量為word,同時返回word。 | 如果變量未定義,則設置其為默認值。 |
${variable=word} | 如variable未設置,則設置變量為word,同時返回word,如果variable被設置且為空,將返回空值,同時variable不變。否則返回variable值,同時variable不變。 | 如果變量未設置,則設置其為默認值。 |
${variable:+word} | 如variable被設置且非空,則返回word,否則返回null,變量值不變。 | 用於測試變量是否存在。 |
${variable+word} | 如variable被設置(即使是空值),則返回word,否則返回空。 | 用於測試變量是否設置。 |
${variable:?word} | 如variable被設置且非空,則返回該值,否則顯示word,然后退出Shell。如果word為空,打印"parameter null or not set" | 為了捕捉由於變量未定義所導致的錯誤。 |
${variable:offset} | 從variable的offset位置開始取,直到末尾。 | |
${variable:offset:length} | 從variable的offset位置開始取length個字符。 |
#${variable:-word}的示例,其C語言表示形式為:
# if (NULL == variable)
# return word;
# else
# return $variable;
/> unset var_name #將變量var_name置為空。
/> var_name=
/> echo ${var_name:-NewValue} #var_name為空,因此返回NewValue
NewValue
/> echo $var_name #var_name的值未變化,仍然為空。
/> var_name=OldValue #給var_name賦值。
/> echo ${var_name:-NewValue} #var_name非空,因此返回var_name的原有值。
OldValue
/> echo $var_name #var_name的值未變化,仍然OldValue。
OldValue
#${variable-word}的示例,其偽碼表示形式為:
# if (variable is NOT set)
# return word;
# else
# return $variable;
/> unset var_name #取消該變量var_name的設置。
/> echo ${var_name-NewValue} #var_name為空,因此返回NewValue
NewValue
/> echo $var_name #var_name的值未變化,仍然為空。
/> var_name=OldValue #給var_name賦值,即便執行var_name=,其結果也是一樣。
/> echo ${var_name-NewValue} #var_name非空,因此返回var_name的原有值。
OldValue
/> echo $var_name #var_name的值未變化,仍然OldValue。
OldValue
#${variable:=word}的示例,其C語言表示形式為:
# if (NULL == variable) {
# variable=word;
# return word;
# } else {
# return $variable;
# }
/> unset var_name #將變量var_name置為空。
/> var_name=
/> echo ${var_name:=NewValue} #var_name為空,設置變量為NewValue同時返回NewValue。
NewValue
/> echo $var_name #var_name的值已經被設置為NewValue。
NewValue
/> var_name=OldValue #給var_name賦值。
/> echo ${var_name:=NewValue} #var_name非空,因此返回var_name的原有值。
OldValue
/> echo $var_name #var_name的值未變化,仍然OldValue。
OldValue
#${variable=word}的示例,其偽碼表示形式為:
# if (variable is NOT set) {
# variable=word;
# return word;
# } else if (variable == NULL) {
# return $variable; //variable is NULL
# } else {
# return $variable;
# }
/> unset var_name #取消該變量var_name的設置。
/> echo ${var_name=NewValue} #var_name未被設置,設置變量為NewValue同時返回NewValue。
NewValue
/> echo $var_name #var_name的值已經被設置為NewValue。
NewValue
/> var_name= #設置變量var_name,並給該變量賦空值。
/> echo ${var_name=NewValue} #var_name被設置,且為空值,返回var_name的原有空值。
/> echo $var_name #var_name的值未變化,仍未空值。
/> var_name=OldValue #給var_name賦值。
/> echo ${var_name=NewValue} #var_name非空,因此返回var_name的原有值。
OldValue
/> echo $var_name #var_name的值未變化,仍然OldValue。
OldValue
#${variable:+word}的示例,其C語言表示形式為:
# if (NULL != variable)
# return word;
# else
# return $variable;
/> var_name=OldValue #設置變量var_name,其值為非空。
/> echo ${var_name:+NewValue} #由於var_name有值,因此返回NewValue
NewValue
/> echo $var_name #var_name的值仍然為遠之OldValue
OldValue
/> unset var_name #將var_name置為空值。
/> var_name=
/> echo ${var_name:+NewValue} #由於var_name為空,因此返回null。
/> echo $var_name #var_name仍然保持原有的空值。
#${variable+word}的示例,其偽碼表示形式為:
# if (variable is set)
# return word;
# else
# return $variable;
/> var_name=OldValue #設置變量var_name,其值為非空。
/> echo ${var_name+NewValue} #由於var_name有值,因此返回NewValue
NewValue
/> echo $var_name #var_name的值仍然為遠之OldValue
OldValue
/> unset var_name #取消對變量var_name的設置。
/> echo ${var_name+NewValue} #返回空值。
/> echo $var_name #var_name仍未被設置。
#${variable:?word}的示例,其C語言表示形式為:
# if (NULL != variable) {
# return variable;
# } else {
# if (NULL != word)
# return "variable : word";
# else
# return "parameter null or not set";
# }
/> var_name=OldValue #設置變量var_name,其值為非空。
/> echo ${var_name:?NewValue} #由於var_name有值,因此返回變量的原有值
OldValue
/> unset var_name #將var_name置為空值。
/> var_name=
/> echo ${var_name:?NewValue} #由於var_name為空,因此返回word。
-bash: var_name: NewValue
/> echo $var_name #var_name仍然保持原有的空值。
/> echo ${var_name:?} #如果word為空,返回下面的輸出。
-bash: var_name: parameter null or not set
#${variable:offset}示例:
/> var_name=notebook
/> echo ${var_name:2}
tebook
/> echo ${var_name:0} #如果offset為0,則取var_name的全部值。
notebook
${variable:offset:length}示例:
/> var_name=notebook
/> echo ${var_name:0:4}
note
/> echo ${var_name:4:4}
book
6. 變量模式匹配運算符:
Shell中還提供了一組模式匹配運算符,見下表:
運算符 | 替換 |
${variable#pattern} | 如果模式匹配變量值的開頭,則刪除匹配的最短部分,並返回剩下的部分,變量原值不變。 |
${variable##pattern} | 如果模式匹配變量值的開頭,則刪除匹配的最長部分,並返回剩下的部分,變量原值不變。 |
${variable%pattern} | 如果模式匹配變量值的結尾,則刪除匹配的最短部分,並返回剩下的部分,變量原值不變。 |
${variable%%pattern} | 如果模式匹配變量值的結尾,則刪除匹配的最長部分,並返回剩下的部分,變量原值不變。 |
${#variable} | 返回變量中字母的數量。 |
#${variable#pattern}示例:
/> pathname="/home/stephen/mycode/test.h"
/> echo ${pathname#/home} #變量pathname開始處匹配/home的最短部分被刪除。
/stephen/mycode/test.h
/> echo $pathname #pathname的原值不變。
/home/stephen/mycode/test.h
#${variable##pattern}示例:
/> pathname="/home/stephen/mycode/test.h"
/> echo ${pathname##*/} #變量pathname開始處匹配*/的最長部分被刪除,*表示任意字符。
test.h
/> echo $pathname #pathname的原值不變。
/home/stephen/mycode/test.h
#${variable%pattern}示例:
/> pathname="/home/stephen/mycode/test.h"
/> echo ${pathname%/*} #變量pathname結尾處匹配/*的最短部分被刪除。
/home/stephen/mycode
/> echo $pathname #pathname的原值不變。
/home/stephen/mycode/test.h
#${variable%%pattern}示例:
/> pathname="/home/stephen/mycode/test.h"
/> echo ${pathname%%/*} #變量pathname結尾處匹配/*的最長部分被刪除,這里所有字符串均被刪除。
/> echo $pathname #pathname的原值不變。
/home/stephen/mycode/test.h
#${#variable}示例:
/> name="stephen liu"
/> echo ${#name}
11
7. Shell中的內置變量:
Shell中提供了一些以$開頭的內置變量,見下表:
變量名 | 描述 |
$? | 表示Shell命令的返回值 |
$$ | 表示當前Shell的pid |
$- | 表示當前Shell的命令行選項 |
$! | 最后一個放入后台作業的PID值 |
$0 | 表示腳本的名字 |
$1--$9 | 表示腳本的第一到九個參數 |
${10} | 表示腳本的第十個參數 |
$# | 表示參數的個數 |
$*,$@ | 表示所有的參數,有雙引號時除外,"$*"表示賦值到一個變量,"$@"表示賦值到多個。 |
所有的內置變量都比較容易理解,因此這里僅給出$*和$@的區別用法:
/> set 'apple pie' pears peaches
/> for i in $*
> do
> echo $i
> done
apple
pie
pears
peaches
/> set 'apple pie' pears peaches
/> for i in $@
> do
> echo $i
> done
apple
pie
pears
peaches
/> set 'apple pie' pears peaches
/> for i in "$*" #將所有參數變量視為一個
> do
> echo $i
> done
apple pie pears peaches
/> set 'apple pie' pears peaches
/> for i in "$@"
> do
> echo $i
> done
apple pie #這里的單引號將兩個單詞合成一個.
pears
peaches
8. 引用:
Shell中提供三種引用字符,分別是:反斜杠、單引號和雙引號,它們可以使Shell中所有元字符失去其特殊功能,而還原其本意。見以下元字符列表:
元字符 | 描述 |
; | 命令分隔符 |
& | 后台處理Shell命令 |
() | 命令組,創建一個子Shell |
{} | 命令組,但是不創建子Shell |
| | 管道 |
< > | 輸入輸出重定向 |
$ | 變量前綴 |
*[]? | 用於文件名擴展的Shell通配符 |
注:單引號和雙引號唯一的區別就是,雙引號內可以包含變量和命令替換,而單引號則不會解釋這些,見如下示例:
/> name=Stephen
/> echo "Hi $name, I'm glad to meet you! " #name變量被替換
Hi Stephen, I'm glad to meet you!
/> echo 'Hi $name, I am glad to meet you! ' #name變量沒有被替換
Hi $name, I am glad to meet you!
/> echo "Hey $name, the time is $(date)" #name變量和date命令均被替換
Hey Stephen, the time is Fri Nov 18 16:27:31 CST 2011
/> echo 'Hey $name, the time is $(date)'
Hey $name, the time is $(date) #name變量和date命令均未被替換
9. 命令替換:
同樣我們需要把命令的輸出結果賦值給一個變量或者需要用字符串替換變量的輸出結果時,我們可以使用變量替換。在Shell中,通常使用反引號的方法進行命令替換。
/> d=`date` #將date命令的執行結果賦值給d變量。
/> echo $d
Fri Nov 18 16:35:28 CST 2011
/> pwd
/home/stephen
/> echo `basename \`pwd\`` #基於反引號的命令替換是可嵌入的,但是嵌入命令的反引號需要使用反斜杠轉義。
stephen
除了反引號可以用於命令替換,這里我們也可以使用$(command)形式用於命令替換。
/> d=$(date)
/> echo $d
Fri Nov 18 16:42:33 CST 2011
/> dirname="$(basename $(pwd))" #和之前的反引號一樣,該方式也支持嵌套。
/> echo $dirname
stephen
10. 數學擴展:
Shell中提供了兩種計算數學表達式的格式:$[ expression ]和$(( expression ))。
/> echo $[5+4-2]
7
/> echo $[5+2*3]
11
/> echo $((5+4-2))
7
/> echo $((5+2*3))
11
事實上,我們也可以在Shell中聲明數值型的變量,這需要在declare命令的后面添加-i選項,如:
/> declare -i num
/> num=5+5 #注意在賦值的過程中,所有的符號之間均沒有空格,如果需要空格,需要在表達式的外面加雙引號
/> echo $num #如果沒有聲明declare -i num,該命令將返回5+5
10
/> num="5 * 5"
/> echo $num
25
/> declare strnum
/> strnum=5+5
/> echo $strnum #由於並未將strnum聲明為數值型,因此該輸出將按字符串方式處理。
5+5
Shell還允許我們以不同進制的方式顯示數值型變量的輸出結果,其格式為:進制+#+變量。
/> declare -i x=017 #017其格式為八進制格式
/> echo $x #缺省是十進制
15
/> x=2#101 #二進制
/> echo $x
5
/> x=8#17 #八進制
/> echo $x
15
/> x=16#b #十六進制
/> echo $x
11
在Shell中還提供了一個內置命令let,專門用於計算數學運算的,見如下示例:
/> let i=5
/> let i=i+1
/> echo $i
6
/> let "i = i + 2"
/> echo $i
8
/> let "i+=1"
/> echo $i
9
11. 數組:
Shell中提供了創建一維數組的能力,你可以把一串數字、名字或者文件放在一個變量中。使用declare的-a選項即可創建它們,或者在變量后面增加下標操作符直接創建。和很多其它開發語言一樣,Shell中的數組也是0開始的,然而不同的是Shell中數組的下標是可以不連續的。獲取數組中某個元素的語法格式為: ${arrayname[index]}。見如下示例:
/> declare -a friends #聲明一個數組變量
/> friends=(sheryl peter louise) #給數組變量賦值
/> echo ${friends[0]} #通過數組下標的方式訪問數組的元素
sheryl
/> echo ${friends[1]}
peter
/> echo ${friends[2]}
louise
/> echo ${friends[*]} #下標中星號表示所有元素。
shery1 peter louise
# ${#array[*]}表示數組中元素的數量,而${#friend[0]}則表示第一個元素的長度。
/> echo ${#friends[*]}
3
/> unset friends #unset array清空整個數組,unset array[index]僅清空指定下標的元素。
/> x[3]=100
/> echo ${x[*]}
100
/> echo ${x[0]} #0下標的元素並沒有被賦值過,因為輸出為空。
/> echo ${x[3]}
100
/> states=(ME [3]=CA [2]=CT) #ME的下標為0。
/> echo ${states[0]}
ME
/> echo ${states[1]} #數組下標為1的位置沒有被賦值過,因此沒有輸出。
/> echo ${states[2]}
CT
/> echo ${states[3]}
CA
12. 函數:
和C語言一樣,Shell中也可以創建自己的自定義函數。其格式如下:
function_name () { commands; commands; }
function function_name { commands; commands; }
function function_name () { commands; commands; }
函數的參數在函數內是以$[0-9]、${10}...,這種局部變量的方式來訪問的。見下面的示例:
#函數的左花括號和命令之間必須有至少一個空格。每個命令的后面都要有一個分號,即便是最后一個命令
/> function greet { echo "Hello $LOGNAME, today is $(date)"; }
#此時函數已經駐留在當前的bash shell中,因此使用函數效率更高。
/> greet
Hello root, today is Fri Nov 18 20:45:10 CST 2011
/> greet() { echo "Hello $LOGNAME, today is $(date)"; }
/> greet
Hello root, today is Fri Nov 18 20:46:40 CST 2011
#welcome函數內部使用了函數參數。
/> function welcome { echo "Hi $1 and $2"; }
/> welcome stephen jane
Hi stephen and jane
#declare -F選項將列出當前Shell中駐留的函數
/> declare -F
declare -f greet
declare -f welcome
#清空指定的函數,使其不在Shell中駐留。
/> unset -f welcome
13. 重定向:
下面的列表為Shell中支持的重新定向操作符。
操作符 | 功能 |
< | 重新定向輸入 |
> | 重新定向輸出 |
>> | 追加輸出 |
2> | 重新定向錯誤 |
&> | 重新定向錯誤和輸出 |
>& | 重新定向錯誤和輸出 |
2>&1 | 重新定向錯誤到標准輸出 |
1>&2 | 重新定向標准輸出到錯誤 |
>| | 重新定向輸出的時候覆蓋noclobber選項 |
#find命令將搜索結果輸出到foundit文件,把錯誤信息輸出到/dev/null
/> find . -name "*.c" -print > foundit 2> /dev/null
#將find命令的搜索結果和錯誤信息均輸出到foundit文件中。
/> find . -name "*.c" -print >& foundit
#同上。
/> find . -name "*.c" -print > foundit 2>&1
#echo命令先將錯誤輸出到errfile,再把信息發送到標准錯誤,該信息標准錯誤與標准輸出合並在一起(errfile中)。
/> echo "File needs an argument" 2> errfile 1>&2
/> cat errfile
File needs an argument