鍍金池/ 教程/ Linux/ shell 學(xué)習(xí)第二十六天----變量與算數(shù)
shell 學(xué)習(xí)四十一天----列出文件 ls 和 od 命令
shell 學(xué)習(xí)小結(jié)
shell 學(xué)習(xí)第二十八天----case 語(yǔ)句
shell 學(xué)習(xí)四十四天----尋找文件
shell 學(xué)習(xí)三十五天----波浪號(hào)展開(kāi)與通配符
shell 學(xué)習(xí)三十八天----執(zhí)行順序和 eval
shell 學(xué)習(xí)四十八天----文件校驗(yàn)和匹配
shell 學(xué)習(xí)四十天----awk 的驚人表現(xiàn)
shell 學(xué)習(xí)第十一天----sed 正則的精確控制
shell 學(xué)習(xí)第十七天----awk 命令
shell 學(xué)習(xí)三十九天----內(nèi)建命令
shell 學(xué)習(xí)四十五天----xargs
shell 學(xué)習(xí)三十七天----引用
shell 學(xué)習(xí)第十六天----join 練習(xí)
shell 學(xué)習(xí)第二十四天----提取開(kāi)頭或結(jié)尾數(shù)行
shell 學(xué)習(xí)第九天----分組
shell 學(xué)習(xí)第五天----基本的 I/O 重定向
shell 學(xué)習(xí)第十五天----使用 cut 選定字段
shell 學(xué)習(xí)四十六天----文件系統(tǒng)的空間信息 df 和 du 命令
shell 學(xué)習(xí)第八天----擴(kuò)展正則表達(dá)式 (ERE)
shell 學(xué)習(xí)第十九天----文本塊排序
shell 學(xué)習(xí)第二十一天----重新格式化段落
shell 學(xué)習(xí)三十六天----命令替換
shell 學(xué)習(xí)第二十天----sort 的其他內(nèi)容以及 uniq 命令
shell 學(xué)習(xí)四十二天----使用 touch 更新文件時(shí)間
shell 學(xué)習(xí)五十一天----top 命令查看進(jìn)程列表
shell 學(xué)習(xí)第一天
shell 學(xué)習(xí)五十四天----進(jìn)程系統(tǒng)調(diào)用的追蹤 strace
shell 學(xué)習(xí)五十天----查看進(jìn)程 ps 命令
shell 學(xué)習(xí)第二十七天----退出狀態(tài)和 if 語(yǔ)句
shell 學(xué)習(xí)第二十三天----打印
shell 學(xué)習(xí)三十三天----關(guān)于重定向
shell 學(xué)習(xí)四十九天----進(jìn)程建立
shell 學(xué)習(xí)第三十天----break,continue,shift,getopts
shell 學(xué)習(xí)五十五天----進(jìn)程記賬
shell 學(xué)習(xí)總結(jié)一
shell 學(xué)習(xí)第二十六天----變量與算數(shù)
shell 學(xué)習(xí)第二十二天----計(jì)算行數(shù), 字?jǐn)?shù)以及字符數(shù)
shell 學(xué)習(xí)五十八天----/proc 文件系統(tǒng)
shell 學(xué)習(xí)第二十五天----神器的管道符
shell 學(xué)習(xí)第三十二天----read 讀取一行
sheel 學(xué)習(xí)第三天
shell 學(xué)習(xí)----小結(jié)
shell 學(xué)習(xí)第十八天----文本排序
shell 學(xué)習(xí)第三十一天----函數(shù)問(wèn)題
shell 學(xué)習(xí)第十天----sed 查找與替換
shell 學(xué)習(xí)四十三天----臨時(shí)性文件的建立與使用
shell 學(xué)習(xí)四十七天----文件比較 cmp,diff,patch
shell 學(xué)習(xí)三十四天----printf 詳解
shell 學(xué)習(xí)五十七天 ----linux 任務(wù)管理,針對(duì)上一講的總結(jié)和擴(kuò)展
shell 學(xué)習(xí)第六天----小結(jié)
shell 學(xué)習(xí)第十三天----sed 案例分析
shell 學(xué)習(xí)第七天----基礎(chǔ)正則表達(dá)式 (BRE)
shell 學(xué)習(xí)第十二天----行與字符串
shell 學(xué)習(xí)小結(jié)四
shell 學(xué)習(xí)第二十九天----循環(huán)
shell 學(xué)習(xí)五十二天----刪除進(jìn)程 kill 命令
shell 學(xué)習(xí)五十六天----延遲進(jìn)程調(diào)度
shell 學(xué)習(xí)第四天----華麗的 printf 輸出
shell 學(xué)習(xí)第十五天----join 連接字段
shell 學(xué)習(xí)完結(jié)篇----希望你能看到
shell 學(xué)習(xí)第二天
shell 學(xué)習(xí)五十三天----捕獲信號(hào) trap

shell 學(xué)習(xí)第二十六天----變量與算數(shù)

變量與算數(shù)

shell 腳本與函數(shù)還有位置參數(shù)的功能;傳統(tǒng)的說(shuō)法應(yīng)該是“命令行參數(shù)”;
shell 為內(nèi)嵌算數(shù)提供了一種標(biāo)記法,稱為算數(shù)展開(kāi)。shell 回對(duì) $((...)) 里的算符表達(dá)式進(jìn)行計(jì)算,再將計(jì)算后的結(jié)構(gòu)放回到命令的文本內(nèi)。

有兩個(gè)相似的命令提供變量的管理,一個(gè)是 readonly,它可以使變量稱為只讀模式;而賦值給它們是被禁止的。在 shell 程序中,這是創(chuàng)建符號(hào)常量的一個(gè)好方法:

days_per_week=7     賦值
readonly days_per_week    設(shè)為只讀模式 
export,readonly

語(yǔ)法:

export name[=word]...
export -p
readonly name[=word]...
readonly =p

用途:

export 用于修改或打印環(huán)境變量,readonly 則使得變量不得修改。

主要選項(xiàng):

  • -p: 打印命令的名稱以及所有被到處 (只讀) 變量的名稱與值,這種方式可使得 shell 重新讀取輸出以便重新建立環(huán)境 (只讀設(shè)置)。

行為模式

使用 -p 選項(xiàng),這兩條命令都會(huì)分別打印他們的名稱以及被到處的或只讀的所有變量。

較常見(jiàn)的命令是 export,用法是將變量放進(jìn)環(huán)境變量里。環(huán)境是一個(gè)名稱與值的簡(jiǎn)單列表,可供所有執(zhí)行中的程序使用。新的進(jìn)程會(huì)從父進(jìn)程繼承環(huán)境,也可以在建立新的紫禁城之前修改它。export 命令可將新變量添加到環(huán)境中:

PATH=$PATH:/usr/local/bin 更新 PATH
export PATH 導(dǎo)出它

使用 export -p 命令可以顯示當(dāng)前環(huán)境

變量可以添加到程序環(huán)境中,但是對(duì) shell 或接下來(lái)的命令不會(huì)一直有效: 將該變量賦值,置于命令名稱與參數(shù)前即可:

PATH=/bin:/usr/bin awk '...' file1 file2

這個(gè) PATH 值只對(duì)后面 awk 起作用,其他命令將使用系統(tǒng) PATH。使用 env 命令顯示所有環(huán)境變量。unset 命令從執(zhí)行中的 shell 中刪除變量與函數(shù)。

案例

清除環(huán)境變量的值使用 unset 命令。如果未定義指定值,則該變量值將被設(shè)為 NULL。
首先使用命令 export TEST="test" 來(lái)增加一個(gè)環(huán)境變量
接著使用命令 env | grep TEST,得到結(jié)果 TEST=test
然后使用命令 unset $TEST 刪除環(huán)境變量 TEST
最后使用命令 env | grep TEST 命令,該命令不會(huì)有輸出,說(shuō)明成功的刪除了。
其中 unset 還可以通過(guò)添加 -f 選項(xiàng)刪除指定的函數(shù)。

unset 的行為模式
如果沒(méi)有提供選項(xiàng),則參數(shù)將視為變量名稱,并告知變量已刪除,如果使用 -f 選項(xiàng),參數(shù)則被視為函數(shù)名稱,并刪除函數(shù)。

注意:myvar= 賦值并不會(huì)將 myvar 刪除,只不過(guò)試講其設(shè)為 null 字符串。相對(duì)的:unset myvar 則會(huì)完全刪除它。這一差異在于”是變量設(shè)置” 以為”是變量設(shè)置,但非 null” 展開(kāi)。

參數(shù)展開(kāi)

var ="hello,world"
echo ${var}
hello,world

其實(shí)這里說(shuō)的參數(shù) (parameter) 不就是我們通常說(shuō)的變量 (variable) 么? 嗯。。其實(shí)大部分時(shí)候這倆名詞的意思基本等同。只不過(guò)在 Shell 中 parameter(參數(shù)) 是 variable(變量) 的超集: 變量名不能以數(shù)字開(kāi)頭,而參數(shù)名可以。比如說(shuō) $1 就表示命令行傳入的第一個(gè)參數(shù)。參數(shù)展開(kāi)是 shell 提供變量值在程序中使用的過(guò)程: 例如,作為新變量的值,或是作為命令行的部分或全部參數(shù)。最簡(jiǎn)單的形式如下所示:

reminder ="Time to go to the dentist"    將值存儲(chǔ)在 reminder 中
sleep 120 等待兩分鐘
echo $reminder 顯示信息

在 shell 下,有更復(fù)雜的形式可用于更特殊的情況。這些形式都是將變量名稱括在花括號(hào)里 (${variable}),然后再增加額外的語(yǔ)法以告訴 shell 該做些什么。花括號(hào)本身也是很好用的,當(dāng)你需要在變量名稱之后馬上跟著一個(gè)可能會(huì)解釋為名稱一部分的字符時(shí),他就派上用場(chǎng)了:

reminder ="Time to go to the dentist"    將值存儲(chǔ)在 reminder 中
sleep 120 等待兩分鐘
echo ${reminder} 顯示信息

警告: 默認(rèn)情況下,未定義的變量會(huì)展開(kāi)為 null(空的) 字符串。程序隨便亂寫(xiě),就可能會(huì)導(dǎo)致災(zāi)難發(fā)生

rm -rf /$MYPROGRAM 如果未設(shè)置 MYPROGRAM,就會(huì)有大災(zāi)難發(fā)生了,所以在寫(xiě) 程序時(shí)一定要小心。

展開(kāi)運(yùn)算符

第一組字符串處理運(yùn)算符用來(lái)測(cè)試變量的存在狀態(tài),且為在某種情況下的允許默認(rèn)值的替換。

替換運(yùn)算符

運(yùn)算符
替換
${varname:=word}
如果 varname 存在且不是 null,則返回它的值;否則,設(shè)置它為 word,并返回其值
用途: 如果變量未定義,則返回默認(rèn)值。
范例: 如果 count 未定義,則 echo ${count:-0} 的值為 0
${varname:word}
如果 varname 存在且不是 null,則返回它的值;否則,設(shè)置它為 word,并返回其值。
用途: 如果變量未定義,則設(shè)置變量為默認(rèn)值。
范例: 如果 count 未定義,echo${count:=0} 輸出為 0
${varname:?message}
如果 varname 存在且非 null,則返回它的值;否則,顯示 varname:message,并退出當(dāng)前的命令或腳本。省略 message 會(huì)出現(xiàn)默認(rèn)信息 parameter null or not set。注意,在交互式 shell 下不需要退出 (在不同的 shell 間會(huì)有不同的行為,用戶需自行注意)。
用途: 為了捕捉由于變量未定義所導(dǎo)致的錯(cuò)誤。
范例:${count:?"undefined"} 將顯示:count:undefined!,且如果 count 未定義,則退出
${varname:+word}
如果 varname 存在且非 null,則返回 word;否則,返回 null。
用途: 未測(cè)試變量的存在。
如果: 如果 count 已定義,則 ${count:+1} 返回 1(也就是真)

該表中每個(gè)運(yùn)算符內(nèi)的冒號(hào) (:) 都是可選的。如果省略冒號(hào),則將每個(gè)定義的“存在且非 null” 部分改為“存在”,也就是說(shuō),運(yùn)算符僅用于測(cè)試變量是否存在。

模式匹配運(yùn)算符

運(yùn)算符
替換
例:${path#/*/}
結(jié)果:tolstoy/mem/long.file.name
例:${variable##pattern}
如果模式匹配于變量值的開(kāi)頭處,則刪除匹配的最長(zhǎng)部分,并返回剩下的部分。
例:${path##/*/}
結(jié)果:long.file.name
例:${path%.*}
結(jié)果:/home/tolstoy/mem/long.file
例:${variable%pattern}
如果模式匹配于變量值的結(jié)尾處,則刪除匹配的最短部分,并返回剩下的部分。
例:${variable%%pattern}
如果模式匹配于變量值的結(jié)尾處,則刪除匹配的最長(zhǎng)部分,并返回省下的部分
例:${path%%.*}
結(jié)果:/home/tolstoy/mem/long

案例分析:${parameter#word}{parameter##word}

作用: 從 parameter 頭部開(kāi)始匹配 word,并刪除成功匹配的部分。在構(gòu)造 word 時(shí)可以使用 “*” 表示任意長(zhǎng)度的字符,“?” 表示單位長(zhǎng)度字符,并可用形如 “[a-c]” 的方式制定匹配 “abc” 中的任意字符。

另外,“#” 和 “##” 的區(qū)別在于前置是匹配最短,而后者是最長(zhǎng)匹配;實(shí)際上就是正則表達(dá)式中的 “懶惰” 和 “貪婪” 的概念。

var=br1br2ead
echo ${var$$*br}

輸出:2ead

echo ${var#*br}

輸出:1br2ead

案例

${parameter%word}${parameter%%word}

作用: 與前例相似,唯一不同的是從 $parameter 的為不開(kāi)始匹配。

var="La.Maison.en.Petits.Cubes.avi"
echo ${var%.*}

輸出:La.Maison.en.Petits.Cubes

echo ${var%%.*}

輸出:La

分析: 匹配案例中的”.” 時(shí),shell 會(huì)從 $var 的尾部開(kāi)始查找 “.”,如果是最短匹配 (echo ${var%.*}),則會(huì)找到第一個(gè)”.” 就停止,否則 (echo ${var%%.*}) 會(huì)一直找到最后一個(gè) “.” 才停止。可以看到,這種用法可以分方便的去掉文件后綴,從而得到文件名。

使用 ${#variable} 可以獲得 variable 的長(zhǎng)度:

案例:variable=qwertyuiop;

echo ${#variable}

輸出:10

記憶:

# 匹配的是前面,因?yàn)閿?shù)字正負(fù)號(hào)總是置于數(shù)字之前;% 匹配的是后面,因?yàn)榘俜直确?hào)總是更在數(shù)字的后面。這里用到了兩種匹配模式://,匹配任何位于兩個(gè)斜杠之間的元素;.,匹配點(diǎn)號(hào)之后接著的任何元素。

位置參數(shù)

所謂的位置參數(shù),指的是 shell 腳本的命令行參數(shù);同時(shí)也表示 zaishell 函數(shù)內(nèi)的函數(shù)參數(shù),他們的名稱是以單個(gè)的整數(shù)來(lái)命名。當(dāng)整數(shù)大于 9 時(shí),就應(yīng)該以花括號(hào)括起來(lái):

echo frist arg is $1
echo tenth arg is ${10}

也可以將其與模式匹配運(yùn)算符結(jié)合,應(yīng)用到位置參數(shù):

filename=${1:-/dev/tty} 如果給定參數(shù)則使用它,如無(wú)參數(shù)則使用 /dev/tty

接下來(lái)的特殊 “變量” 提供了對(duì)傳遞的參數(shù)的總數(shù)的訪問(wèn),以及一次對(duì)所有參數(shù)的訪問(wèn):

  • $# : 提供傳遞到 shell 腳本或函數(shù)的參數(shù)總是。當(dāng)你是為了處理選項(xiàng)和參數(shù)而建立循環(huán)時(shí),它會(huì)很有用。

舉例:

while [$# !=0] 以 shift 逐漸減少 $#,循環(huán)將會(huì)終止
do
case $1 in
... 處理第一個(gè)參數(shù)
esac
shift 已開(kāi)第一個(gè)參數(shù)
done
  • $*,$@ : 以此表示所有的命令行參數(shù)。著兩個(gè)參數(shù)可用來(lái)把命令行參數(shù)傳遞給腳本或函數(shù)所執(zhí)行的程序。

  • “$*” : 將所有命令行參數(shù)視為單個(gè)字符串。等同于 “$1 $2 ...” $IFS 的第一個(gè)字符用來(lái)作為分隔符,衣服個(gè)不同的值來(lái)建立字符串。

案例:

printf ”他和 arguments were %s\n” ”$*”

  • “$@” : 將所有的命令韓參數(shù)視為單獨(dú)的而個(gè)體,就業(yè)就單獨(dú)字符串。等同于 “$1” “$2” .... 這是將參數(shù)傳遞給其他程序的最佳凡是,因?yàn)樗麜?huì)保留所有的內(nèi)嵌在每個(gè)參數(shù)里的任何空白。

案例:

lpr “$@” 現(xiàn)實(shí)每一個(gè)文件 shift 命令是用來(lái)” 截去” 來(lái)自列表的位置參數(shù),由左開(kāi)始。一旦執(zhí)行 shift,$1 的初值會(huì)永遠(yuǎn)消失,取而代之的是 $2 的舊值。$2 的值變成 $3 的舊值,依次類(lèi)推。$#的值會(huì)逐次減一。shift 也可使用一個(gè)可選的參數(shù),也就是要位移的參數(shù)的計(jì)數(shù)。單純的 shift 等同于 shift 1。

案例:

set -- hello “hi there” greetings 結(jié)束選項(xiàng)部分,自 hello 開(kāi)始新的參數(shù) echo $# 顯示計(jì)數(shù)值

for i in $* 循環(huán)處理每一個(gè)參數(shù)
\> do echo i is $i        
\> done

輸出:

i is hello i is hi i is there i is greeting

注意,內(nèi)嵌的空白已消失

使用命令:for i in $@在沒(méi)有雙引號(hào)的額情況下,$@和 $* 得到的結(jié)果一樣

\> do echo i is $i
\> done

加了雙引號(hào) for i in ”$*” $* 表示一個(gè)字符串

\> do echo i in $i
\> done

輸出:

i in hello hi there greeting

加了雙引號(hào) for i in “$@” $@保留真正的參數(shù)值

輸出:

i in hello
i in hi there
i in greeting

使用命令 shift 截去第一個(gè)參數(shù)

echo there are now $# arguments

輸出:there are now 2arguments 證明第一個(gè)參數(shù)已經(jīng)消失

使用命令:

for i in ”$@”

輸出為:

i in hi there
i in greeting

特殊變量

POSIX 中的內(nèi)置變量

變量
意義
\#
表示變量的個(gè)數(shù),常用于循環(huán)
@
當(dāng)前命令行所有參數(shù),置于雙引號(hào)中,表示個(gè)別命令
*
當(dāng)前命令行所有參數(shù)。置于雙引號(hào)中,表示將命令行所有參數(shù)當(dāng)做一個(gè)單獨(dú)參數(shù)
-(連字號(hào))
在引用數(shù)給予 shell 的選項(xiàng)
?
表示上一個(gè)命令退出的狀態(tài)
$
表示當(dāng)前進(jìn)程編號(hào)
0
表示當(dāng)前進(jìn)程名稱
!
表示最近一個(gè)后臺(tái)命令的進(jìn)程編號(hào)
HOME
表示當(dāng)前用戶的根目錄
IFS
表示內(nèi)部的字符分隔符
LANG
當(dāng)前 locale 默認(rèn)名稱
PATH
環(huán)境變量
PPID
父進(jìn)程編號(hào)
PWD
當(dāng)前工作目錄
特殊變量 $$ 可在編寫(xiě)腳本時(shí)用來(lái)建立具有唯一性的文件名 (多半是臨時(shí)的),這是根據(jù) shell 的進(jìn)程編號(hào)建立文件名。不過(guò)系統(tǒng)中還有一個(gè) mktemp 也能做同樣的事情。

算數(shù)展開(kāi)

shell 的算數(shù)運(yùn)算符與 C 語(yǔ)言里的差不多,優(yōu)先級(jí)與順序也相同。

運(yùn)算符
意義
順序
++ --
增加以減少,可前置也可放在結(jié)尾
由左至右
+ - ! ~
一元的正好與符號(hào);邏輯與位的取反
由右至左
* / %
乘 除 取余
由左至右
+ -
加 減
由左至右
 <<>>
向左位移,向右位移
由左至右
<<=> >=
比較
由左至右
== !=
相等不相等
由左至右
&
位的 AND
由左至右
^
韋德 Exclusive OR
由左至右
|
位的 OR
由左至右
&&
邏輯的 AND
由左至右
||
邏輯的 OR
由左至右
?:
條件表達(dá)式
由右至左
= += -= *= /=&= ^= <<=>>= |=
賦值運(yùn)算符
由右至左

該表的運(yùn)算符的優(yōu)先級(jí)由高排列至最低。可利用圓括號(hào)將子表達(dá)式語(yǔ)句括起來(lái)。像 C 一樣:關(guān)系運(yùn)算符 (<,<=,>,>=,== 與!=) 產(chǎn)生數(shù)字結(jié)果中,1 為真,0 為假。

例如:

$((3>2)) 的值為 1;echo $(((3>2)||(4<=1))) 也為 1,因?yàn)橹鴥蓚€(gè)子表達(dá)式里有一個(gè)為真。 對(duì)邏輯的 AND 與 OR 運(yùn)算符而言,任何非 0 值函數(shù)都為真:echo $((3&&4)) 3 與 4 都為 “真” ++ 和 -- 運(yùn)算符不用說(shuō)了。++ 與 -- 運(yùn)算符是可選的;實(shí)際上,所有支持 ${{...}} 的 shell,都可以讓用戶在提供變量名稱時(shí),無(wú)須前置 $ 符號(hào)。