鍍金池/ 教程/ Linux/ shell 學(xué)習(xí)第二十六天----變量與算數(shù)
shell 學(xué)習(xí)四十一天----列出文件 ls 和 od 命令
shell 學(xué)習(xí)小結(jié)
shell 學(xué)習(xí)第二十八天----case 語句
shell 學(xué)習(xí)四十四天----尋找文件
shell 學(xué)習(xí)三十五天----波浪號展開與通配符
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í)第二十四天----提取開頭或結(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 更新文件時間
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 語句
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í)第二十二天----計算行數(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ù)問題
shell 學(xué)習(xí)第十天----sed 查找與替換
shell 學(xué)習(xí)四十三天----臨時性文件的建立與使用
shell 學(xué)習(xí)四十七天----文件比較 cmp,diff,patch
shell 學(xué)習(xí)三十四天----printf 詳解
shell 學(xué)習(xí)五十七天 ----linux 任務(wù)管理,針對上一講的總結(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í)五十三天----捕獲信號 trap

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

變量與算數(shù)

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

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

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

語法:

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

用途:

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

主要選項(xiàng):

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

行為模式

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

較常見的命令是 export,用法是將變量放進(jìn)環(huán)境變量里。環(huán)境是一個名稱與值的簡單列表,可供所有執(zhí)行中的程序使用。新的進(jìn)程會從父進(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)境中,但是對 shell 或接下來的命令不會一直有效: 將該變量賦值,置于命令名稱與參數(shù)前即可:

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

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

案例

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

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

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

參數(shù)展開

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

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

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

在 shell 下,有更復(fù)雜的形式可用于更特殊的情況。這些形式都是將變量名稱括在花括號里 (${variable}),然后再增加額外的語法以告訴 shell 該做些什么?;ɡㄌ柋旧硪彩呛芎糜玫模?dāng)你需要在變量名稱之后馬上跟著一個可能會解釋為名稱一部分的字符時,他就派上用場了:

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

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

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

展開運(yùn)算符

第一組字符串處理運(yùn)算符用來測試變量的存在狀態(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 會出現(xiàn)默認(rèn)信息 parameter null or not set。注意,在交互式 shell 下不需要退出 (在不同的 shell 間會有不同的行為,用戶需自行注意)。
用途: 為了捕捉由于變量未定義所導(dǎo)致的錯誤。
范例:${count:?"undefined"} 將顯示:count:undefined!,且如果 count 未定義,則退出
${varname:+word}
如果 varname 存在且非 null,則返回 word;否則,返回 null。
用途: 未測試變量的存在。
如果: 如果 count 已定義,則 ${count:+1} 返回 1(也就是真)

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

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

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

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

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

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

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

輸出:2ead

echo ${var#*br}

輸出:1br2ead

案例

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

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

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

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

echo ${var%%.*}

輸出:La

分析: 匹配案例中的”.” 時,shell 會從 $var 的尾部開始查找 “.”,如果是最短匹配 (echo ${var%.*}),則會找到第一個”.” 就停止,否則 (echo ${var%%.*}) 會一直找到最后一個 “.” 才停止??梢钥吹剑@種用法可以分方便的去掉文件后綴,從而得到文件名。

使用 ${#variable} 可以獲得 variable 的長度:

案例:variable=qwertyuiop;

echo ${#variable}

輸出:10

記憶:

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

位置參數(shù)

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

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

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

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

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

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

舉例:

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

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

案例:

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

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

案例:

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

案例:

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

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

輸出:

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

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

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

\> do echo i is $i
\> done

加了雙引號 for i in ”$*” $* 表示一個字符串

\> do echo i in $i
\> done

輸出:

i in hello hi there greeting

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

輸出:

i in hello
i in hi there
i in greeting

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

echo there are now $# arguments

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

使用命令:

for i in ”$@”

輸出為:

i in hi there
i in greeting

特殊變量

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

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

算數(shù)展開

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

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

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

例如:

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