1、shell介紹
shell 俗稱叫做殼,計(jì)算機(jī)的殼層,和內(nèi)核是相對(duì)的,用于和用戶交互,接收用戶指令,調(diào)用相應(yīng)的程序。

因此,把shell分為2大類
1.1、圖形界面shell(Graphical User Interface shell 即 GUI shell)
也就是用戶使用GUI和計(jì)算機(jī)核交互的shell,比如Windows下使用最廣泛的Windows Explorer(Windows資源管理器),Linux下的X Window,以及各種更強(qiáng)大的CDE、GNOME、KDE、 XFCE。
他們都是GUI Shell。
1.2、命令行式shell(Command Line Interface shell ,即CLI shell)
也就是通過(guò)命令行和計(jì)算機(jī)交互的shell。
Windows NT 系統(tǒng)下有 cmd.exe(命令提示字符)和近年來(lái)微軟大力推廣的 Windows PowerShell。
Linux下有bash / sh / ksh / csh/zsh等
一般情況下,習(xí)慣把命令行shell(CLI shell)直接稱做shell,以后,如果沒(méi)有特別說(shuō)明,shell就是指 CLI shell,后文也是主要講Linux下的 CLI shell。
根據(jù)交互方式的不一樣,命令行式shell(CLI shell),又分為交互式shell和非交互式shell。
交互式模式就是shell等待你的輸入,并且執(zhí)行你提交的命令,然后馬上給你反饋。這種也是我們大多數(shù)時(shí)候使用的。
非交互式shell,就是把shell放在寫在一個(gè)文件里面,執(zhí)行的時(shí)候,不與用戶交互,從前往后依次執(zhí)行,執(zhí)行到文件結(jié)尾時(shí),shell也就終止了。
在Linux下 ,各種shell百花齊放,種類繁多,不同的shell,也有不同的優(yōu)缺點(diǎn)。
我們要查看當(dāng)前系統(tǒng)下支持的shell,可以讀取/etc/shells文件。

Bourne Again Shell 用來(lái)替代Bourne shell,也是目前大多數(shù)Linux系統(tǒng)默認(rèn)的shell。
Bourne Shell 是一個(gè)比較老的shell,目前已經(jīng)被/bin/bash所取代,在很多l(xiāng)inux系統(tǒng)上,sh已經(jīng)是一個(gè)指向bash的鏈接了。
下面是CentOS release 6.5 的系統(tǒng)

C shell 使用的是“類C”語(yǔ)法,csh是具有C語(yǔ)言風(fēng)格的一種shell,tcsh是增強(qiáng)版本的csh,目前csh已經(jīng)很少使用了。
最早,bash交互體驗(yàn)很好,csh作為非交互式使用很爽,ksh就吸取了2者的優(yōu)點(diǎn)。
zsh網(wǎng)上說(shuō)的目前使用的人很少,但是感覺(jué)使用的人比較多。
zsh本身是不兼容bash的,但是他可以使用仿真模式(emulation mode)來(lái)模擬bash等,基本可以實(shí)現(xiàn)兼容。
在交互式的使用中,目前很多人都是zsh,因?yàn)閦sh擁有很強(qiáng)大的提示和插件功能,炫酷吊炸天。推薦在終端的交互式使用中使用zsh,再安利一個(gè)插件Oh My Zsh
其實(shí)我個(gè)人的理解是,在終端中使用shell,基本上只是調(diào)用各種命令,比如:curl cat ls等等,基本不會(huì)使用到zsh的編程,所以終端中使用zsh是可以的。但是在寫shell腳本的時(shí)候,需要考慮兼容性,
最主流的還是bash shell,所以,后文我們介紹的shell腳本也是bash shell的。
1
2
#!/bin/bash
echo "Hello World !"
#!:是一個(gè)特殊的標(biāo)記,表明使用啥解釋器來(lái)執(zhí)行,比如這里使用了:/bin/bash 來(lái)執(zhí)行這個(gè)腳本。
#:只用一個(gè)#,就是注釋
echo:輸出
我們把上面的腳本保存成一個(gè)文件, 1.sh 后面的這個(gè)sh是shell腳本的擴(kuò)展名。
然后要怎嚒來(lái)執(zhí)行呢?執(zhí)行一個(gè)shell腳本有很多種方式:
sh 1.sh 這樣可以直接執(zhí)行這個(gè)1.sh
也可以直接 ./1.sh ,但是這種要注意,才編輯好的文件這樣執(zhí)行可能會(huì)報(bào)錯(cuò)

這個(gè)是因?yàn)闆](méi)有這個(gè)腳本沒(méi)有執(zhí)行權(quán)限,運(yùn)行 chmod a+x 1.sh 加上執(zhí)行權(quán)限即可。
這里順帶說(shuō)一下,為啥直接運(yùn)行1.sh不行呢?因?yàn)樗J(rèn)是去PATH里面找程序,當(dāng)前目錄,一般都不在PATH里面。所以直接運(yùn)行1.sh就回報(bào)找不到文件。
還可以使用類似curl?http://xxxxx.xxx/xxx.sh|sh?這樣的方式,來(lái)執(zhí)行遠(yuǎn)程的腳本
根據(jù)測(cè)試,#!/bin/bash 的標(biāo)記,只是針對(duì)第二種方式 ./xxx.sh的方式有效。本文中代碼,第一行均為這個(gè)標(biāo)記,為了節(jié)約篇幅,已經(jīng)省略.

執(zhí)行并獲取返回結(jié)果,有點(diǎn)類似JavaScript 的eval函數(shù)。
1
2
3
#!/bin/bash
dt=`date` #反引號(hào)內(nèi)的字符串會(huì)當(dāng)作shell執(zhí)行 ,并且返回結(jié)果。
echo "dt=${dt}"
shell的使用比較簡(jiǎn)單,就像這樣,并且沒(méi)有數(shù)據(jù)類型的概念,所有的變量都可以當(dāng)成字符串來(lái)處理:
1
2
3
#!/bin/bash
myName="tom"
youName="cat"
不需要申明,直接寫就可以了,但是有幾個(gè)點(diǎn)需要特別注意:
等號(hào)兩邊不能有空格!??!特別要注意,非常容易寫錯(cuò)
命名只能使用英文字母,數(shù)字和下劃線,首個(gè)字符不能以數(shù)字開頭。
中間不能有空格,可以使用下劃線(_)。
不能使用標(biāo)點(diǎn)符號(hào)。
不能使用bash里的關(guān)鍵字。
使用變量
ABC="tom"
echo $ABC #使用變量前面加$美元符號(hào)
echo "ABC=$ABC" #可以直接在字符串里面引用
echo "ABC=${ABC}" #但是建議把變量名字用{}包起來(lái)
#只讀變量
ABC="tom"
echo "ABC=${ABC}"
readOnly ABC #設(shè)置只讀
ABC="CAT" #會(huì)報(bào)錯(cuò),因?yàn)樵O(shè)置了只讀,不能修改

刪除變量
ABC="tom"
echo "ABC=${ABC}"
unset ABC #刪除
echo "ABC=$ABC"?
echo "ABC=${ABC}"

從這個(gè)例子當(dāng)中,我們也發(fā)現(xiàn),使用一個(gè)不存在的變量,shell不會(huì)報(bào)錯(cuò),只是當(dāng)作空來(lái)處理。
使用字符串
NAME="tom"
A=my #你甚至可以不用引號(hào),但是字符串當(dāng)中不能有空格,這種方式也不推薦
B='my name is ${NAME}' #變量不會(huì)被解析
C="my name is ${NAME}" #變量會(huì)解析
echo $A
echo $B
echo $C
執(zhí)行結(jié)果

我們可以發(fā)現(xiàn),這個(gè)字符串的單雙號(hào)和PHP的處理非常類似,單引號(hào)不解析變量,雙引號(hào)可以解析變量。但是都可以處理轉(zhuǎn)義符號(hào)。
A='my\nname\nis\ntom'
B="my\nname\nis\ntom"
echo $A
echo $B

拼接字符串
其實(shí)shell拼接字符串,大概就是2種
一是直接在雙引號(hào)內(nèi)應(yīng)用變量,類似模版字符串
二是直接把字符串寫在一起,不需要類似Java鏈接字符串的“+” 和PHP鏈接字符串的“.”
NAME="TOM"
#使用雙引號(hào)拼接
echo "hello, "$NAME" !" #直接寫在一起,沒(méi)有字符串連接符
echo "hello, ${NAME} !" #填充模版
#使用單引號(hào)拼接
echo 'hello, '$NAME' !' #直接寫在一起,沒(méi)有字符串連接符
echo 'hello, ${NAME} !' #上面已經(jīng)提高過(guò),單引號(hào)里面的變量是不會(huì)解析的

強(qiáng)大的字符串處理
shell中簡(jiǎn)單的處理字符串,可以直接使用各種標(biāo)記,只是比較難記憶,要用的時(shí)候,可以查一下。
ABC="my name is tom,his name is cat"
echo "字符串長(zhǎng)度=${#ABC}" # 取字符串長(zhǎng)度
echo "截取=${ABC:11}" # 截取字符串, 從11開始到結(jié)束
echo "截取=${ABC:11:3}" # 截取字符串, 從11開始3個(gè)字符串
echo "默認(rèn)值=${XXX-default}" #如果XXX不存在,默認(rèn)值是default
echo "默認(rèn)值=${XXX-$ABC}" #如果XXX不存在,默認(rèn)值是變量ABC
echo "從開頭刪除最短匹配=${ABC#my}" # 從開頭刪除 my 匹配的最短字符串
echo "從開頭刪除最長(zhǎng)匹配=${ABC##my*tom}" # 從開頭刪除 my 匹配的最長(zhǎng)字符串
echo "從結(jié)尾刪除最短匹配=${ABC%cat}" # 從結(jié)尾刪除 cat 匹配的最短字符串
echo "從結(jié)尾刪除最長(zhǎng)匹配=${ABC%%,*t}" # 從結(jié)尾刪除 ,*t 匹配的最長(zhǎng)字符串
echo "替換第一個(gè)=${ABC/is/are}" #替換第一個(gè)is
echo "替換所有=${ABC//is/are}" #替換所有的is

這里只是介紹了比較常用的一些字符串處理,實(shí)際shell支持的還有很多。
Bash Shell 也是支持?jǐn)?shù)組的,與絕大部分語(yǔ)言一樣,數(shù)組下標(biāo)從0開始。不過(guò)需要注意的是,它只支持一維數(shù)組。
定義一個(gè)數(shù)組,用小括號(hào)闊氣來(lái),當(dāng)中用“空格”分割,就像下面這樣:
1
array=("item0" "item1" "item2")
也可以根據(jù)下標(biāo)來(lái)定義元素
array[0]="new_item0"
array[1]="new_item1"
array[2]="new_item2"
array[4]="new_item4" #數(shù)組下標(biāo)可以是不連續(xù)的
讀取數(shù)組元素,和變量類似
echo ${array[0]}
echo "array[0]=${array[0]}"
獲取數(shù)組所有的元素
echo "數(shù)組的元素為: ${array[*]}"
echo "數(shù)組的元素為: ${array[@]}"
獲取數(shù)組的長(zhǎng)度
echo "數(shù)組的長(zhǎng)度為: ${#array[*]}"
echo "數(shù)組的長(zhǎng)度為: ${#array[@]}"
在上文中,其實(shí)我們已經(jīng)到多次,就是:echo “字符串” 來(lái)輸出,一個(gè)很簡(jiǎn)單的例子
echo "Hello world!"
如果當(dāng)中包含特殊符號(hào),可以使用轉(zhuǎn)義等:
echo "Hello \nworld!"
echo "\"Hello\""
echo '"Hello"' #當(dāng)然,也可以這樣,單引號(hào)不轉(zhuǎn)義,上文提到過(guò)
echo `date` #打印執(zhí)行date的結(jié)果
echo -n "123" #加-n? 表示不在末尾輸出換行
echo "456"
echo -e "\a處理特殊符號(hào)" #-e 處理特殊符號(hào)
-n?讓echo輸出結(jié)束以后,在默認(rèn)不輸出換行符
-e?讓echo處理特殊符號(hào),比如:
符號(hào)作用
\a發(fā)出警告聲
\b刪除前一個(gè)字符
\c后不加上換行符號(hào)
\f換行但光標(biāo)仍舊停留在原來(lái)的位置
\n換行且光標(biāo)移至行首
\r光標(biāo)移至行首,但不換行
\t插入tab
上面的特殊符號(hào),寫到mac的shell腳本里面要注意,執(zhí)行的時(shí)候,要用bash執(zhí)行才有效 ,sh無(wú)效。
當(dāng)然,你也可以玩一點(diǎn)更有趣的,就是我們隨時(shí)在終端中看到的五顏六色的文字:
echo -e "\033[31m 紅色前景 \033[0m 缺省顏色"
echo -e "\033[41m 紅色背景 \033[0m 缺省顏色"

其中
\033[是一個(gè)特殊標(biāo)記,表示終端轉(zhuǎn)義開始,
31m表示使用紅色字體,你也可以使用其他顏色,[30-39]是前景顏色,[40-49]是背景顏色。
\033[0m回復(fù)到缺省設(shè)置
還可以有一些其他的動(dòng)作
echo -e "\033[2J" #清除屏幕
echo -e "\033[0q" #關(guān)閉所有的鍵盤指示燈
echo -e "\033[1q" #設(shè)置"滾動(dòng)鎖定"指示燈(Scroll Lock)
echo -e "\033[2q" #設(shè)置"數(shù)值鎖定"指示燈(Num Lock)
echo -e "\033[1m" #設(shè)置高亮度
echo -e "\033[4m" #下劃線
echo -e "\033[7m" #反顯
echo -e "\033[y;xH" #設(shè)置光標(biāo)位置
其他更多的特殊碼請(qǐng)自行查詢。
有輸出,必然有輸入,read命令接收標(biāo)準(zhǔn)輸入的輸入。
read name
echo "my name is ${name}"
可以使用-p給一個(gè)輸入提示
read -p "please input your name:" name
echo "my name is ${name}"
如果沒(méi)有指定輸入的變量,會(huì)把輸入放在環(huán)境標(biāo)量REPLY中
read -p "please input your name:"
echo "my name is ${REPLY}"
計(jì)時(shí)輸入,如果一段時(shí)間沒(méi)有輸入 ,就直接返回,使用-t 加時(shí)間
read -t 3 -p "please input your name in 3 senconds:" name
指定輸入字符個(gè)數(shù),使用-n ,后面的是輸入字符個(gè)數(shù)
read -n 1 -p "Are you sure [Y/N]?" isYes
默讀(輸入不再監(jiān)視器上顯示),加一個(gè)-s參數(shù)。
read? -s? -p "Enter your password:" password
echo已經(jīng)比較強(qiáng)大,但是有的時(shí)候,我們需要用到字符串模版輸出,printf就比較好用了,他類似C里面的printf程序。
語(yǔ)法是:printf format-string [arguments…]
比如我們要輸出一個(gè)表格
printf "%-10s %-8s %-4s\n" 姓名 性別 體重kg?
printf "%-10s %-8s %-4.2f\n" 郭靖 男 66.1234
printf "%-10s %-8s %-4.2f\n" 楊過(guò) 男 48.6543
printf "%-10s %-8s %-4.2f\n" 郭芙 女 47.9876
運(yùn)行結(jié)果

%s %c %d %f都是格式替代符
%-10s 指一個(gè)寬度為10個(gè)字符(-表示左對(duì)齊,沒(méi)有則表示右對(duì)齊),至少顯示10字符寬度,如果不足則自動(dòng)以空格填充,超過(guò)不限制。
%-4.2f 指格式化為小數(shù),其中.2指保留2位小數(shù)。
大多數(shù) UNIX 系統(tǒng)命令從你的終端接受輸入并將所產(chǎn)生的輸出發(fā)送回到您的終端。一個(gè)命令通常從一個(gè)叫標(biāo)準(zhǔn)輸入的地方讀取輸入,默認(rèn)情況下,這恰好是你的終端。同樣,一個(gè)命令通常將其輸出寫入到標(biāo)準(zhǔn)輸出,默認(rèn)情況下,這也是你的終端。
命令作用
command > file將輸出重定向到 file。
command < file將輸入重定向到 file。
command >> file將輸出以追加的方式重定向到 file。
n > file將文件描述符為 n 的文件重定向到 file。
n >> file將文件描述符為 n 的文件以追加的方式重定向到 file。
n >& m將輸出文件 m 和 n 合并。
n <& m將輸入文件 m 和 n 合并。
<< tag將開始標(biāo)記 tag 和結(jié)束標(biāo)記 tag 之間的內(nèi)容作為輸入。
需要注意的是文件描述符 0 通常是標(biāo)準(zhǔn)輸入(STDIN),1 是標(biāo)準(zhǔn)輸出(STDOUT),2 是標(biāo)準(zhǔn)錯(cuò)誤輸出(STDERR)。
輸出到文件
1
2
echo "test">text.txt #直接輸出
echo "test">>text.txt #追加在text.txt后面
重定向輸入
read a <<EOF
"測(cè)試"
EOF
echo "a=$a"
來(lái)個(gè)比較過(guò)分的
cat? < 1.sh > text.txt
把1.sh文件的內(nèi)容出入到cat,然后cat在輸出到text.txt中,相當(dāng)于,把1.sh的內(nèi)容輸出到text.txt中了
還有一種用法,把標(biāo)準(zhǔn)錯(cuò)誤直接輸出到標(biāo)準(zhǔn)輸出,并且輸出到文件file
command > file 2>&1
/dev/null 文件
這個(gè)是一個(gè)特殊文件,他是一個(gè)黑洞,寫入到它的內(nèi)容都會(huì)被丟棄,如果我們不關(guān)心程序的輸出,可以這樣
command > /dev/null 2>&1
和其他語(yǔ)言一樣,shell也有條件判斷
單分支:
if condition
then
? ? command1
? ? command2
? ? ...
fi
雙分支:
if condition
then
? ? command1
? ? command2
? ? ...
else
? ? command
fi
多分支:
if condition1
then
? ? command1
elif condition2
then
? ? command2
else
? ? commandN
fi
比如
if [ "2" == "2" ]; then # "2" 的2邊都有空格,不能省略 ,寫在一行,條件后面加一個(gè)分號(hào)
echo "2==2"
else
echo "2!=2"
fi
需要特別注意:[ “2” == “2” ] 其中的”==”兩邊都有空格,不能省略,否則結(jié)果不正確。
判斷普通文件是否存在
if [ -f "1.sh" ]; then # 判斷一個(gè)普通文件是否存在
echo "1.sh 存在"
fi
判斷目錄是否存在
if [ -d "1.sh" ]; then # 判斷一個(gè)目錄是否存在
echo "1.sh 存在"
fi
判斷字符串長(zhǎng)度為0
a=""
if [ -z $a ]; then
echo "a為空"
fi
在shell中,有幾個(gè)符號(hào)要非常注意,用的也比較多,不要搞混了,搞混了,邏輯運(yùn)算很容易出錯(cuò)
命令組
括號(hào)中的命令將會(huì)新開一個(gè)子shell順序執(zhí)行,所以括號(hào)中的變量不能夠被腳本余下的部分使用。括號(hào)中多個(gè)命令之間用分號(hào)隔開,最后一個(gè)命令可以沒(méi)有分號(hào),各命令和括號(hào)之間不必有空格。
a="123"
(echo "123";a="456";echo "a=$a")
echo "a=$a

命令替換
發(fā)現(xiàn)了$(cmd)結(jié)構(gòu),便將$(cmd)中的cmd執(zhí)行一次,得到其標(biāo)準(zhǔn)輸出,再將此輸出放到原來(lái)命令。
用于初始化數(shù)組
如:array=(a b c d)
運(yùn)算擴(kuò)展,比如,你可以
a=$((4+5))
echo "a=$a"
做數(shù)值運(yùn)算,重新定義變量
1
2
3
a=5
((a++))
echo "a=$a"
用于算術(shù)運(yùn)算比較
if ((1+1>1));then
? echo "1+1>1"
fi
用于字符串比較
需要注意,用于字符串比較,運(yùn)算符只能是 ==和!=,需要注意,運(yùn)算符號(hào)2邊必須有空格,不然結(jié)果不正確?。?!比如:
if [ "2" == "2" ]; then # "2" 的2邊都有空格,不能省略
echo "2==2"
else
echo "2!=2"
fi
用于整數(shù)比較
需要注意,整數(shù)比較,只能用-eq,-gt這種形式,不能直接使用大于(>)小于(<)符號(hào)。只能用于整形。
if [ 2 -eq 2 ]; then
echo "2==2"
else
echo "2!=2"
fi
符號(hào)表
符號(hào)運(yùn)算
-eq等于
-ne不等于
-gt大于
-ge大于等于
-lt小于
-le小于等于
多個(gè)邏輯組合
-a?表示and 與運(yùn)算
-o?表示or 或運(yùn)算
if [ "2" == "2" -a "1" == "1" ]; then #注意,在這里,不能是[ "2" == "2" ] -a [ "1" == "1" ] 會(huì)報(bào)錯(cuò)
echo "ok"
fi
[[是 bash 程序語(yǔ)言的關(guān)鍵字。并不是一個(gè)命令,[[ ]] 結(jié)構(gòu)比[ ]結(jié)構(gòu)更加通用。
字符串匹配時(shí)甚至支持簡(jiǎn)單的正則表達(dá)式
if [[ "123" == 12* ]]; then #右邊是正則不需要引號(hào)
? ? echo "ok"
fi
if [[? 2.1 > 1.1 ]]; then
? ? echo "ok"
fi
多個(gè)邏輯判斷
可以直接使用&&、||做邏輯運(yùn)算,并且可以在多個(gè)[[]]之間進(jìn)行運(yùn)算
if [[? 1.1 > 1.1 ]] || [[ 1.1 == 1.1 ]]; then
? ? echo "ok"
fi
統(tǒng)配擴(kuò)展
1
touch file_{1..5}.txt #創(chuàng)建new_1.txt new_2.txt new_3.txt new_4.txt new_5.txt? 5個(gè)文件
語(yǔ)法格式為:
for a in "item1" "item2" "item3"
do
? echo $a
done
輸出當(dāng)前目錄下 .sh結(jié)尾的文件
for a in `ls ./`
do
? if [[ $a == *.sh ]]
? then
? ? echo $a
? fi
done
語(yǔ)法
while condition
do
? ? command
done
我們要輸出1-10000
int=1;
while(($int<=10000))
do
? echo $int
? ((int++))
done
語(yǔ)法
until condition
do
? ? command
done
用法類似,這里不再贅述。
循環(huán)中 continue命令與break作用和其他語(yǔ)言中類似。
case和其他語(yǔ)言switch類型,多分支,選擇一個(gè)匹配。匹配發(fā)現(xiàn)取值符合某一模式后,其間所有命令開始執(zhí)行直至 ;;,有點(diǎn)類型Java的break。如果無(wú)一匹配模式,使用星號(hào) * 捕獲該值,再執(zhí)行后面的命令。
echo '輸入 1 到 4 之間的數(shù)字:'
echo '你輸入的數(shù)字為:'
read aNum
case $aNum in
? ? 1)? echo '你選擇了 1'
? ? ;;
? ? 2)? echo '你選擇了 2'
? ? ;;
? ? 3)? echo '你選擇了 3'
? ? ;;
? ? 4)? echo '你選擇了 4'
? ? ;;
? ? *)? echo '你沒(méi)有輸入 1 到 4 之間的數(shù)字'
? ? ;;
esac
shell也可以用戶定義函數(shù),然后在shell腳本中可以隨便調(diào)用。
注意:所有函數(shù)在使用前必須定義。這意味著必須將函數(shù)放在腳本開始部分,直至shell解釋器首次發(fā)現(xiàn)它時(shí),才可以使用。調(diào)用函數(shù)僅使用其函數(shù)名即可。
語(yǔ)法格式如下:
[function] funname()
{
? ? cmd....
? ? [return int]
}
一個(gè)最簡(jiǎn)單的函數(shù)
Line(){
? echo "--------分割線--------"
}
echo "123"
Line
echo "456"
在Shell中,調(diào)用函數(shù)時(shí)可以向其傳遞參數(shù)。
在函數(shù)體內(nèi)部,通過(guò) $n 的形式來(lái)獲取參數(shù)的值,例如,$1表示第一個(gè)參數(shù),$2表示第二個(gè)參數(shù)…
調(diào)用的時(shí)候 ,函數(shù)名,參數(shù)直接用空格分割開。
帶參數(shù)的函數(shù)示例:
out(){
? echo "1-->$1"
? echo "2-->$2"
}
out 1 2 #調(diào)用的之后
還有一些其他的特殊符號(hào)需要注意
符號(hào)作用
$#傳遞到腳本的參數(shù)個(gè)數(shù)
$*以一個(gè)單字符串顯示所有向腳本傳遞的參數(shù)
$$腳本運(yùn)行的當(dāng)前進(jìn)程ID號(hào)
$!后臺(tái)運(yùn)行的最后一個(gè)進(jìn)程的ID號(hào)
$@與$*相同,但是使用時(shí)加引號(hào),并在引號(hào)中返回每個(gè)參數(shù)。
$?顯示最后命令的退出狀態(tài)。0表示沒(méi)有錯(cuò)誤,其他任何值表明有錯(cuò)誤。
所以我們可以寫一個(gè)代碼參數(shù),返回值的函數(shù)
out(){
echo "全部參數(shù)$*"
? for item in $*
? do
? ? echo "$item"
? done
? return $# #這類返回參數(shù)個(gè)數(shù),返回值必須是整數(shù)
}
out this is perfect
echo "函數(shù)返回值:$?"
我們可以在執(zhí)行 Shell 腳本時(shí),向腳本傳遞參數(shù),腳本內(nèi)獲取參數(shù)的格式為:$n。n 代表一個(gè)數(shù)字,1 為執(zhí)行腳本的第一個(gè)參數(shù),2 為執(zhí)行腳本的第二個(gè)參數(shù),以此類推……
除了參數(shù)可以使用特殊符號(hào),也可以使用上文中函數(shù)所使用的特殊符號(hào),這里不再贅述
echo "執(zhí)行的文件名:$0";
echo "全部參數(shù):$*"
echo "參數(shù)個(gè)數(shù):$#"
echo "第一個(gè)參數(shù)為:$1";
echo "第二個(gè)參數(shù)為:$2";
echo "第三個(gè)參數(shù)為:$3";

shell腳本,他本身的功能并不強(qiáng)大,強(qiáng)大的是他可以調(diào)用其他程序,而在Linux下,系統(tǒng)自帶的就有非常多的強(qiáng)大工具可以調(diào)用。
后臺(tái)執(zhí)行一個(gè)腳本只需要在后面加上&符號(hào)即可,我們先用之前學(xué)習(xí)的,寫一個(gè)腳本,1s輸出一個(gè)數(shù)字
#!/bin/bash
int=1
while :
do
? echo $int
? ((int++))
? sleep 1s #睡眠一秒
done
我們執(zhí)行sh d.sh & 我們發(fā)現(xiàn),的確會(huì)后臺(tái)輸出,但是會(huì)輸出到當(dāng)前控制臺(tái),我們可以用之前學(xué)的重定向,把輸出重定向到文件
sh d.sh > out.log 2>&1 &
這樣就把輸出和錯(cuò)誤重新定向到out.log文件了
但是,我們發(fā)現(xiàn),關(guān)閉終端以后,文件就不輸出了。
當(dāng)我們端口連接遠(yuǎn)程主機(jī)的session或者關(guān)閉當(dāng)前終端的時(shí)候, 會(huì)產(chǎn)生一個(gè)SIGHUP信號(hào) ,導(dǎo)致程序退出,我們可以使用nuhup來(lái)忽略這個(gè)信號(hào) ,達(dá)到真正的后臺(tái)。
nuhup sh d.sh > out.log 2>&1 &
這樣啟動(dòng)程序,就可以打到真正后臺(tái)運(yùn)行了。
那么問(wèn)題來(lái)了,我們驗(yàn)證程序在后臺(tái)運(yùn)行呢?要怎嚒結(jié)束后臺(tái)程序呢?請(qǐng)繼續(xù)看。
在本文中,我們已經(jīng)多次用到cat,他的作用就是讀取文件輸出到標(biāo)準(zhǔn)輸出上,也就是我們的終端。
語(yǔ)法是:
cat [option] file
我們也可以使用:cat -n file ,來(lái)輸出行號(hào)。
類似上面的例子,我們要驗(yàn)證程序是不是在后臺(tái),每一秒輸出一個(gè)數(shù)字到文件,使用cat讀取,需要不斷的多次查看,一次cat只能輸出一次。
tail非常適合查看這種日志類文件,他的作用是讀取文件末尾幾行輸出到標(biāo)準(zhǔn)輸出上。
tail out.log
默認(rèn)顯示10行,可以使用參數(shù)-n指定行數(shù)
tail -20 out.log
顯示文件末尾20行
tail -f out.log
持續(xù)監(jiān)控文件out.log,如果有變化,他會(huì)試試的顯示在我們的屏幕上面。
ps,查詢進(jìn)程
這個(gè)命令參數(shù)比較多,列舉幾個(gè)比較常用的
參數(shù)作用
a顯示終端上的所有進(jìn)程,包括其他用戶的進(jìn)程。
u顯示面向用戶的格式信息。
x顯示沒(méi)有控制終端的進(jìn)程。
一般查詢,使用 ps aux就可以了,查詢出來(lái)比較多,可以篩選一下。
這里我們使用 ps u 就可以查詢出我們剛才開啟的后臺(tái)進(jìn)程了。

我們看到我們剛才啟動(dòng)的程序PID為7523,
使用kill命令就可以殺死他了
kill命令比較簡(jiǎn)單,就是根據(jù)PID結(jié)束一個(gè)程序,比如我們已經(jīng)查詢到,我們開的后臺(tái)進(jìn)行是7523,要結(jié)束他可以使用:
kill 7523
以上是常用用法,其實(shí)kill是給程序發(fā)送一個(gè)信號(hào),上面的程序給會(huì)程序發(fā)送一個(gè)SIGTERM信號(hào),程序收到這個(gè)信號(hào),完成資源的釋放,就退出了。
但是也有程序不聽話,收到信號(hào)就是不退出,這個(gè)時(shí)候,就要強(qiáng)制他退出,使用9號(hào)命令(SIGKILL),強(qiáng)制殺死他。
簡(jiǎn)單的說(shuō)
kill PID 是告訴程序,你應(yīng)該退出了,請(qǐng)自己退出。
kill -9 PID ,是直接告訴程序,你被終結(jié)了,這個(gè)命令信號(hào),不能被抓取或者忽略。
shell使用的比較少,但是特別強(qiáng)大;
shell對(duì)語(yǔ)法比較敏感,并且應(yīng)為解釋器很多,每個(gè)解釋器語(yǔ)法標(biāo)準(zhǔn)也可能不完全一致;
使用到的編號(hào)、編碼、參數(shù)特別多,并且都是簡(jiǎn)寫,很多記不住。其實(shí)不用死記硬背,記住有這個(gè)功能就可以了,需要用到的時(shí)候再查詢。