您好,登錄后才能下訂單哦!
這篇文章將為大家詳細講解有關shell腳本基礎有哪些,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。
第一招 HelloWorld
第一式:echo
echo "Hello World"
echo -n "Hello World" # 不帶換行
echo -e '\e[0;33;1mHello\e[0m World' # 帶顏色的玩法
echo -e '\e[0;33;4mHello\e[0m World' # 帶顏色+下劃線
echo -e '\e[0;33;5mHello\e[0m World' # 帶顏色+閃爍
格式為 \e[背景色;前景色;高亮格式m,請閱讀詳細文檔后使用正確的姿勢進行裝逼。
第二招 判斷
第一式:if
if true
then
echo "Hello World"
else
echo "Bug"
fi
if false
then
echo "Hello World"
elif true
then
echo "Bug"
else
echo "Bee"
fi
判斷原理
if、elif會執行它后面跟著的命令,然后看返回值是否為0,如果為0則執行then下面的語句塊,
否則執行else下面的語句塊。
[casheywen@ubuntu:~]$ true
[casheywen@ubuntu:~]$ echo $?
0
[casheywen@ubuntu:~]$ false
[casheywen@ubuntu:~]$ echo $?
1
注:
1.true、false事實上也為一個命令,true的返回碼必為0,false的返回碼必為1
2.$?為shell內置變量,用于存放上一個命令的返回碼
第二式:test、[ ] 和 ` `
test、[ ]、` `實際上都是shell中的命令,執行之后會返回1或0,而這幾個命令與if相結合可以達到我們所
需要的許多判斷功能,例如測試字符串是否為空的三種寫法:
s=""
if [ -z ${s} ]
then
echo "empty"
fi
if [[ -z ${s} ]]
then
echo "empty"
fi
if test -z ${s}
then
echo "empty"
fi
事實上,if后的[ ]、` `、test命令都是可以單獨執行的,而根據if的判斷原理,后續執行哪個分支也是由
[ ]、` `、test的返回值來決定的,以下是單獨執行它們的效果:
[casheywen@ubuntu:~]$ s=""
[casheywen@ubuntu:~]$ [ -z "${s}" ]
[casheywen@ubuntu:~]$ echo $?
0
[casheywen@ubuntu:~]$ s="abc"
[casheywen@ubuntu:~]$ test -z "${s}"
[casheywen@ubuntu:~]$ echo $?
1
[casheywen@ubuntu:~]$ s="123"
[casheywen@ubuntu:~]$ [[ 100 -lt ${s} ]]
[casheywen@ubuntu:~]$ echo $?
0
在性能方面[ ]和test性能基本相同,` `性能是最高的,為前兩者的5倍左右(以-d運算符測試),所以建議
盡量使用` `提高腳本性能。
文件測試
以下為本教程的《入門篇》,適于初學者快速入門以及老手查缺補漏。
第一招 HelloWorld
第一式:echo
echo "Hello World"
echo -n "Hello World" # 不帶換行
echo -e '\e[0;33;1mHello\e[0m World' # 帶顏色的玩法
echo -e '\e[0;33;4mHello\e[0m World' # 帶顏色+下劃線
echo -e '\e[0;33;5mHello\e[0m World' # 帶顏色+閃爍
格式為 \e[背景色;前景色;高亮格式m,請閱讀詳細文檔后使用正確的姿勢進行裝逼。
第二招 判斷
第一式:if
if true
then
echo "Hello World"
else
echo "Bug"
fi
if false
then
echo "Hello World"
elif true
then
echo "Bug"
else
echo "Bee"
fi
判斷原理
if、elif會執行它后面跟著的命令,然后看返回值是否為0,如果為0則執行then下面的語句塊,
否則執行else下面的語句塊。
[casheywen@ubuntu:~]$ true
[casheywen@ubuntu:~]$ echo $?
0
[casheywen@ubuntu:~]$ false
[casheywen@ubuntu:~]$ echo $?
1
注:
1.true、false事實上也為一個命令,true的返回碼必為0,false的返回碼必為1
2.$?為shell內置變量,用于存放上一個命令的返回碼
第二式:test、[ ] 和 ` `
test、[ ]、` `實際上都是shell中的命令,執行之后會返回1或0,而這幾個命令與if相結合可以達到我們所
需要的許多判斷功能,例如測試字符串是否為空的三種寫法:
s=""
if [ -z ${s} ]
then
echo "empty"
fi
if [[ -z ${s} ]]
then
echo "empty"
fi
if test -z ${s}
then
echo "empty"
fi
事實上,if后的[ ]、` `、test命令都是可以單獨執行的,而根據if的判斷原理,后續執行哪個分支也是由
[ ]、` `、test的返回值來決定的,以下是單獨執行它們的效果:
[casheywen@ubuntu:~]$ s=""
[casheywen@ubuntu:~]$ [ -z "${s}" ]
[casheywen@ubuntu:~]$ echo $?
0
[casheywen@ubuntu:~]$ s="abc"
[casheywen@ubuntu:~]$ test -z "${s}"
[casheywen@ubuntu:~]$ echo $?
1
[casheywen@ubuntu:~]$ s="123"
[casheywen@ubuntu:~]$ [[ 100 -lt ${s} ]]
[casheywen@ubuntu:~]$ echo $?
0
在性能方面[ ]和test性能基本相同,` `性能是最高的,為前兩者的5倍左右(以-d運算符測試),所以建議
盡量使用` `提高腳本性能。
文件測試:
字符串比較:
注意: 1.在字符串兩邊加上""防止出錯;
2.<和>是字符串比較,不要錯用成整數比較;
3.如果是在[ ]中使用<和>,需要將它們寫成\<和\>。
整數比較:
第三式:&&、||:
注:只有` `才允許把&&寫在里面
|\|\|可以用來對兩個判斷語句求或| |---| |if [ -n "abc" ] \|\| [ -n "aa" ]| |if [[ -n "abc" ]] \|\| [[ -n "aa" ]]| |if test -n "abc" \|\| test -n "aa"| |if [[ -n "abc" \|\| -n "aa" ]]|
注:只有` `才允許把||寫在里面
小技巧
&&、||還可以用來拼接命令,達到按前一個命令成功與否來決定是否執行后一個命令的效果
cd /data && ls # 當`cd /data`返回0(即成功)時才執行后面的`ls` cd /data || cd /root # 當`cd /data`返回非0(即失敗)時才執行后面的`cd /root`
第三招:循環
第一式:for
for i in {1..100}
do
echo ${i}
done
注:
1.{1..100}屬于通配的一種寫法,展開會是1 2 3 ... 100(1~100以空格隔開)這樣的字串。
2.例如for i in 1 2 3;這樣的語句,for會將1、2、3依次賦值于i進行循環,而對于通配的情況,for則會將通配展開后將里面的每一項依次賦值于i進行循環。
for i in `seq 100`
do
echo ${i}
done
for i in `seq 1 2 100`
do
echo ${i}
done
注:
1.seq本身為一個命令,用于輸出數字組成的序列,如seq 100會生成并輸出1 2 3 ...100(1~100以換行符隔開)這樣的序列,而seq 1 2 100則會生成并輸出1 3 5 ...99(以1開始,2為公差的等差數列中小于100的項,以換行符隔開)。
2.反引號(')之間的命令會被執行,其輸出結果會轉換成一個變量,故上面的for in會依次取出seq的執行結果賦值于i進行循環。
for ((i = 0; i < 100; i++))
do
echo ${i}
done
for ((i = 0; i < 100; i+= 2))
do
echo ${i}
done
注:
以上與C語言式的for循環語法基本相同,區別在于雙重括號:(( ))
第二式:while、until
i=0
while [[ ${i} -lt 100 ]]
do
echo ${i}
((i++))
done
i=0
until [[ ${i} -ge 100 ]]
do
echo ${i}
((i++))
done
注:
while和until的判斷原理與if是類似的,它會執行并它后面跟著的命令,不同點在于:
while是后面語句返回值為0,則執行循環中的語句塊,否則跳出循環;
until則是后面語句返回值非0,則執行循環中的語句塊,否則跳出循環。
第四招:變量
第一式:整數
整數的運算
方法較多,此處只列舉最淺顯易懂,并且效率最高的辦法——直接將符合C語言語法的表達式放到(( ))中即可達到對整數的計算目的:
echo $(( 1+1 )) # 最簡單的1+1
echo $(( (1+2)*3/4 )) # 表達式中還可以帶括號
echo $(( 1<<32 )) # 左移右移也支持,但僅限于-4294967296~4294967296之間的數值
echo $(( 1&3 )) # &、^、|、~ 這樣的位操作亦支持
(( i=1+2 )) # 將1+2計算出結果后賦值給i,后續若`echo ${i}`會得到3
(( i++ )) # 變量i自增1
(( i+=3 )) # 變量i自增3
# ... # 還有很多,不再詳列
注:
進行整數運算的方法還有:expr、$[]、let等shell等內置命令,也可調用bc、python等外部工具進行更復雜的數學運算
第二式:字符串
替換
[casheywen@ubuntu:~]# s="i hate hate you"
[casheywen@ubuntu:~]# echo ${s/hate/love}
i love hate you
[casheywen@ubuntu:~]# echo ${s//hate/love}
i love love you
獲取字符串
[casheywen@ubuntu:~]# s="0123456789"
[casheywen@ubuntu:~]# echo ${s:3}
3456789
[casheywen@ubuntu:~]# echo ${s::3}
012
[casheywen@ubuntu:~]# echo ${s:0:3}
012
[casheywen@ubuntu:~]# echo ${s:2:5}
23456
通配刪除
通配刪除,即按通配符,刪除掉字符串中符合條件的一部分
注:
1.此處通配規則參考通配符一覽表
2.最小通配和最大通配的區別:
最小通配:符合通配的最小子串
最大通配:符合通配的最大子串 例如string值為/00/01/02/dir,對于通配/*/,其最小通配為/00/,而最大通配/00/01/02/
[casheywen@ubuntu:~]# s="/00/01/02/dir"
[casheywen@ubuntu:~]# echo ${s#/*/}
01/02/dir
[casheywen@ubuntu:~]# echo ${s##/*/}
dir
[casheywen@ubuntu:~]#
[casheywen@ubuntu:~]# s="abc/cde/efg"
[casheywen@ubuntu:~]# echo ${s%/*}
abc/cde
[casheywen@ubuntu:~]#echo ${s%%/*}
abc
[casheywen@ubuntu:~]#
[casheywen@ubuntu:~]# s="/00/01/02/dir"
[casheywen@ubuntu:~]# echo ${s#/*/}
01/02/dir
[casheywen@ubuntu:~]# echo ${s##/*/}
dir
[casheywen@ubuntu:~]# s="abc/cde/efg"
[casheywen@ubuntu:~]# echo ${s%/*}
abc/cde
[casheywen@ubuntu:~]# echo ${s%%/*}
abc
小技巧
獲取文件名:${path##*/} (相當于basename命令的功能)
獲取目錄名:${path%/*} (相當于dirname命令的功能)
獲取后綴名:${path##*.}
[casheywen@ubuntu:~]# s="/root/test/dir/subdir/abc.txt"
[casheywen@ubuntu:~]# echo ${s##*/}
abc.txt
[casheywen@ubuntu:~]# echo ${s%/*}
/root/test/dir/subdir
[casheywen@ubuntu:~]# echo ${s##*.}
txt
第三式:數組
普通數組
a=() # 空數組
a=(1 2 3) # 元素為1,2,3的數組
echo ${#a[*]} # 數組長度
echo ${a[2]} # 下標為2的元素值(下標從0開始)
a[1]=0 # 給下標為1的元素賦值
# 遍歷數組
for i in ${a[*]}
do
echo ${i}
done
unset a # 清空數組
關聯數組
關聯數組可以用于存儲key-value型的數據,其功能相當于C++中的map或python中的dict。
declare -A a # 聲明關聯數組(必須有此句)
a=(["apple"]="a1" ["banana"]="b2" ["carrot"]="c3") # 初始化關聯數組
echo ${#a[*]} # 獲取元素個數
echo ${a["carrot"]} # 獲取元素值
a["durian"]="d4" # 插入或修改元素
echo ${!a[*]} # 獲取所有的key
unset a["banana"] # 刪除元素
# 遍歷數組(僅value)
for i in ${a[*]}
do
echo ${i}
done
# 遍歷數組(key和value)
for key in ${!a[*]}
do
echo "${key} ==> ${a[${key}]}"
done
unset a # 清空數組
注:
1.關聯數組需要bash 4.0以上版本才支持,選用需慎重。查看bash版本用bash --version
2.關聯數組必須用declare -A顯示聲明類型,否則數值會出錯。
第四式:將命令執行結果存入變量
、、與$( )
LINE_CNT=`wc -l test.txt`
LINE_CNT=$(wc -l test.txt)
以上命令均可把wc -l test.txt的結果存入LINE_CNT變量中
注:
、和$( )都只將命令行標準輸出的內容存入變量,如果需要將標準錯誤內容存入變量,需要用到重定向。
換行符處理
如果命令執行結果有多行內容,存入變量并打印時換行符會丟失:
[casheywen@ubuntu:~]# cat test.txt
a
b
c
[casheywen@ubuntu:~]# CONTENT=`cat test.txt`
[casheywen@ubuntu:~]# echo ${CONTENT}
a
b
c
若需要保留換行符,則在打印時必須加上"":
[casheywen@ubuntu:~]# CONTENT=`cat test.txt`
[casheywen@ubuntu:~]# echo "${CONTENT}"
a
b
c
第五招:重定向
標準輸入流、標準輸出流、標準錯誤流
重定向方式一覽表
第一式:重定向標準輸出流(stdout)
把程序打印的內容輸出到文件
# 以下兩種方式都會將`Hello World`寫入到hello.txt(若不存在則創建)
echo "Hello World" > hello.txt # hello.txt原有的將被覆蓋
echo "Hello World" >> hello.txt # hello.txt原有內容后追加`Hello World`
第二式:重定向標準錯誤流(stderr)
把程序的錯誤信息輸出到文件
例如文件路徑中不存在+++這個文件:
[casheywen@ubuntu:~]# ls +++
ls: cannot access +++: No such file or directory
[casheywen@ubuntu:~]# ls +++ > out.txt
ls: cannot access +++: No such file or directory
上面的ls +++后輸出的內容為標準錯誤流中的錯誤信息,所以即使用> out.txt重定向標準輸入,錯誤信息仍然被打印到了屏幕。
# 以下兩種方式都會將`ls +++`輸出的錯誤信息輸出到`err.txt`(若不存在則創建)
ls +++ 2> err.txt # err.txt原有內容將被覆蓋
ls +++ 2>> err.txt # err.txt原有內容后追加內容
第三式:重定向標準輸入流(stdin)
1.讓程序從文件讀取輸入
以默認從標準輸入讀 取表達式,并進行數學計算的命令bc為例:
[casheywen@ubuntu:~]# bc -q
1+1
2
注:
1.1+1為鍵盤輸入的內容,2為bc命令打印的計算結果
2.bc后的-q參數用于禁止輸出歡迎信息
3.以上重定向方法格式為命令< 文件路徑
如果我需要把已經存在文件exp.txt中的一個表達式輸入到bc中進行計算,可以采用重定向標準輸入流的方法:
bc -q < exp.txt
注:
1.當exp.txt中內容為1+1時,以上語句輸出2
2.由于bc命令本身支持從文件輸入,如不使用重定向,也可用bc exp.txt達到相同效果
2.將變量中內容作為程序輸入
EXP="1+1"
bc -q <<< "${EXP}"
注:
1.以上代碼等同于執行bc并輸入1+1,得到的輸出為2。
2.以上重定向方法格式為命令 <<< 變量內容
3.將當前shell腳本中的多行內容作為程序的輸入
例如在shell中內嵌多行python代碼:
python << EOF
print 'hello from python'
print 'hello' + 'world'
EOF
# 內容中支持shell變量
MSG="shell variable"
python << EOF
print '${MSG}'
EOF
注:
1.以上用法可以方便地將某個程序需要的多行輸入內容直接包含在當前腳本中
2.支持變量,可以動態地改變多行輸入的內容
3.以上重定向方法格式為:命令 << EOF (換行)...(換行) EOF,其中的EOF換成其它字符串也是有效的,如:命令 << ABC (換行)...(換行) ABC的,但通用習慣都使用EOF
第六招:管道
第一式:管道的基本功能
管道的寫法為 cmd1 | cmd2,功能是依次執行cmd1和cmd2,并將cmd1的標準輸出作為cmd2的標準輸入,例如:
echo "1+1" | bc
這里 echo "1+1" 會將1+1輸出到標準輸出,而管道會將echo輸出的1+1作為bc命令的標準輸入,這樣bc會讀取到1+1,最終得到計算結果2打印到屏幕。
注:
1.管道可以多級拼接:cmd1 | cmd2 | cmd3 | ...
2.管道的返回值為最后一級命令的返回值
第二式:管道與while、read組合
LINE_NO=0
cat test.txt | while read LINE
do
(( LINE_NO++ ))
echo "${LINE_NO} ${LINE}"
done
# echo "${LINE_NO}"
以上代碼可以將test.txt中每一行標上行標后輸出。
注:
1.read命令用于從標準輸入讀取一行并賦值給一個或多個變量,如read LINE會從標準輸入讀取一行并將整行內容賦值給LINE變量,read A B則會從標準輸入讀入一行并將這行的第1、2列分別賦值給A、B兩個變量(分割符默認為空格或tab,可給IFS賦值來更改分割符)
2.末尾注釋掉的echo "${LINE_NO}"若執行會輸出0,原因是管道中的while語句是執行在子進程中的,不會改變父進程中LINE_NO變量的值
第三式:管道與xargs組合
find . -type f -name *.log | xargs rm
以上代碼可以將當前目錄及子目錄所有后綴名為.log的文件
find . -type f -name *.log | xargs -i mv {} /data/log
以上代碼可以將當前目錄及子目錄中所有后綴名為.log的文件移動到/data/log中
注:xargs可以從標準輸入讀取內容,以之構建并執行另一個命令行
xargs直接接命令名稱,則將從標準輸入讀取的所有內容合并為一行構建命令行并執行
xargs加上-i參數,則會每讀取一行就構建并執行一個命令行,構建命令行時會將{}替換為該行的內容
[casheywen@ubuntu:~]# cat test.txt
a
b
c
[casheywen@ubuntu:~]# cat test.txt | xargs echo rm
rm a b c
[casheywen@ubuntu:~]# cat test.txt | xargs -i echo rm {}
rm a
rm b
rm c
上例展示了xargs構建命令的原理,如果去掉xargs后的echo,則會執行打印出來的命令
第七招:通配
shell通配的原理 如果你的當前目錄中有1.txt 2.txt 3.txt三個文件,那么當你執行ls *.txt這條命令,shell究竟為你做了什么?
其實shell會先讀取當前目錄,然后按*.txt的通配條件過濾得到1.txt 2.txt 3.txt這個文件列表,然后將這個列表作為參數傳給ls,即ls *.txt相當于ls 1.txt 2.txt 3.txt,ls命令本身并不會得到*.txt這樣的參數。
注:
僅當目錄中沒有符合*.txt通配的文件,shell才會將*.txt這個字符串當作參數直接傳給ls命令 所以如果需要列出當前目錄中所有的txt文件,我們使用echo *.txt也同樣可以達到目的:
[casheywen@ubuntu:~]# ls *.txt
1.txt 2.txt 3.txt
[casheywen@ubuntu:~]# echo *.txt
1.txt 2.txt 3.txt
注:
對于{ }通配shell不會讀取目錄并過濾獲得文件列表。詳細請參考下文。 通配符一覽表
注:
1.*、?、[ ]的通配都會按讀取目錄并過濾的方式展開通配項目
2.{ }則不會有讀取目錄的過程,它是通過枚舉所有符合條件的通配項直接展開的
[casheywen@ubuntu:~]# ls
1.txt 2.txt 3.txt
[casheywen@ubuntu:~]# echo *.txt
1.txt 2.txt 3.txt
[casheywen@ubuntu:~]# echo {1..5}.txt
1.txt 2.txt 3.txt 4.txt 5.txt
[casheywen@ubuntu:~]# ls {1..5}.txt
ls: cannot access 4.txt: No such file or directory
ls: cannot access 5.txt: No such file or directory
1.txt 2.txt 3.txt
由上面的命令可見,*通配的結果與目錄中存在哪些文件有關系,而{ }的通配結果與目錄中存在哪些文件無關。若用{ }進行通配,則有可能將不存在的文件路徑作為命令行參數傳給程序。
*第一式:``**
*用于通配文件名或目錄名中某一部分為任意內容:
rm *.log # 刪除當前目錄中所有后綴名為.log的文件
rm */log/*.log # 刪除所有二級log目錄中后綴名為.log的文件
第二式:[ ]
[ ]用于通配文件名或目錄名中某個字符為限定范圍內或限定范圍外的值:
rm Program[1-9]*.log # 刪除當前目錄中以Program跟著一個1到9的數字開頭,并以.log為后綴名的文件
du -sh /[^udp]* # 對根目錄中所有不以u、d、p開頭的文件夾求取總大小
第三式:?
?用于通配文件名中某處一個任意值的字符:
rm L????.txt # 通配一個文件名以L開頭,后面跟著4個字符,并以.txt結尾的文件:如LAB01.txt
第四式:{ }
{ }也為通配符,用于通配在它枚舉范圍內的值,由于它是直接展開的,我們可以將它用于批量創建目錄或文件,也可以用于生成序列:
批量生成目錄
[casheywen@ubuntu:~]# ls
[casheywen@ubuntu:~]# mkdir dir{0..2}{0..2}
[casheywen@ubuntu:~]# ls
dir00 dir01 dir02 dir10 dir11 dir12 dir20 dir21 dir22
生成序列
{ }生成的序列常用于for循環
for ip in 192.168.234.{1..255}
do
ping ${ip} -w 1 &> /dev/null && echo ${ip} is Alive
done
關于“shell腳本基礎有哪些”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,使各位可以學到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。