bash/shell编程学习(2)
先來(lái)復(fù)習(xí)上節(jié)重定向的用法:
1.快速清空文件
cat demo.txt < /dev/null注:linux中有一個(gè)經(jīng)典名言【一切皆文件】,/dev/null可以認(rèn)為是一個(gè)特殊的空文件,更形象點(diǎn),可以理解為科幻片中的黑洞,任何信息重向定輸出到它后,便有去無(wú)回,當(dāng)然黑洞里也沒(méi)有信息能出來(lái)。
綜合來(lái)講,上面的意思就是利用<將黑洞做為demo.txt的標(biāo)準(zhǔn)輸入,黑洞里沒(méi)任何內(nèi)容,任何文件里的內(nèi)容被它吞噬了,自然也沒(méi)就沒(méi)東西能剩下了,所以最終就是demo.txt被黑洞洗空了。
/dev/null 還有其它用法,比如用它可以讓nohup不生成nohup.out文件,見(jiàn):http://www.cnblogs.com/yjmyzz/p/4831182.html?
?
2.執(zhí)行時(shí)輸出源碼
#!/bin/bash -v printf '%0.2f\n' 12.12334執(zhí)行結(jié)果如下:
#!/bin/bash -v printf '%0.2f\n' 12.12334 12.12注意:第3行輸出結(jié)果之前,把源碼也打印出來(lái)了,秘密在于第1行最后的 -v 參數(shù)
?
3.調(diào)試模式
#!/bin/bash -x printf '%0.2f\n' 12.12334 echo 'hello'執(zhí)行結(jié)果如下:
+ printf '%0.2f\n' 12.12334 12.12 + echo hello hello注意:第一行后面的參數(shù)變成了-x,加上這個(gè)后,執(zhí)行時(shí),每一行代碼在執(zhí)行前,會(huì)先輸出對(duì)應(yīng)的源碼,并且以+開(kāi)頭,十分方便調(diào)試。
?
4. if與test及[]
4.1 數(shù)字判斷
#!/bin/bash -x i=$1 #變量i的值取第1個(gè)參數(shù)的值 if test $i -gt 89; then #如果i>89echo 'A' elif test $i -gt 79; then #如果i>79echo 'B' elif test $i -eq 60 -o $i -gt 60;then #如果i=60或i>60(即:i>=60)echo 'C' elif test $i -gt 0;then #如果i>0echo 'D' elif test $i -lt 0;then #如果i<0echo 'invalid' else #i==0的情況echo 'zero' fi注:if test 條件; then 語(yǔ)句 fi 這是基本格式,注意條件后的;不可省略,另外結(jié)束符號(hào)是fi(即:把if倒過(guò)來(lái),有點(diǎn)回文的理念),另外要記住一堆縮寫(xiě)
-lt 即-Less Than的縮寫(xiě),表示小于
-gt 即-Greater Than的縮寫(xiě),表示大于
-eq 即-equal的縮寫(xiě),表示等于,此外還有
-ne 即-Not Equal的縮寫(xiě),表示不等于
-o 即-or,表示前后二個(gè)邏輯判斷是『或』的關(guān)系,類似的
-a 即-and,表示前后二個(gè)邏輯判斷是『與』的關(guān)系
elif 即else if的縮寫(xiě)
上面的示例運(yùn)行結(jié)果:
./demo.sh 90 + i=90 + test 90 -gt 89 + echo A Atest語(yǔ)句還有一個(gè)簡(jiǎn)化的寫(xiě)法,即把"test 條件"變成" [ 條件 ] ",注意二端的方括號(hào)左右都要加一個(gè)空格,所以上面的寫(xiě)法可以改成:
i=$1 if [ $i -gt 89 ]; thenecho 'A' elif [ $i -gt 79 ]; thenecho 'B' elif [ $i -eq 60 -o $i -gt 60 ]; thenecho 'C' elif [ $i -gt 0 ]; thenecho 'D' elif [ $i -lt 0 ]; thenecho 'invalid' elseecho 'zero' fi這樣看起來(lái)就美觀多了,如果不喜歡-o這種邏輯或的寫(xiě)法,第6行也可以換成這樣
elif [ $i -eq 60 ] || [ $i -gt 60 ]; then但是執(zhí)行的細(xì)節(jié)略有區(qū)別,在調(diào)試模式下可以對(duì)比下,用||寫(xiě)法的輸入(測(cè)試用例:61)
./demo2.sh 61 + i=61 + '[' 61 -gt 89 ']' + '[' 61 -gt 79 ']' + '[' 61 -eq 60 ']' + '[' 61 -gt 60 ']' + echo C C而用-o寫(xiě)法的輸出:
./demo2.sh 61 + i=61 + '[' 61 -gt 89 ']' + '[' 61 -gt 79 ']' + '[' 61 -eq 60 -o 61 -gt 60 ']' + echo C C對(duì)比下5-6行可以發(fā)現(xiàn),區(qū)別在于判斷一次,還是判斷二次
4.2 字符串判斷
#!/bin/bash -x str1="abc" if [ -z "$str1" ]; thenecho 'str1 is empty' elseecho 'str1 is not empty' fiprintf "\n"str2="" if [ -n "$str2" ]; thenecho 'str2 is not empty' elseecho 'str2 is empty' fiprintf "\n"if [ "$str1" = "$str2" ]; thenecho 'str1 = str2' elseecho 'str1 <> str2' fi注: -n即-not empty判斷字符串非空,-z即-zero判斷字符串為空,=判斷字符串相同(判斷字符串時(shí),記得要加雙引號(hào))
運(yùn)行結(jié)果:
+ str1=abc + '[' -z abc ']' + echo 'str1 is not empty' str1 is not empty + printf '\n'+ str2= + '[' -n '' ']' + echo 'str2 is empty' str2 is empty + printf '\n'+ '[' abc = '' ']' + echo 'str1 <> str2' str1 <> str24.3 文件及目錄判斷
#!/bin/bash -x if [ -f ~/.bash_profile ]; thenecho '~/.bash_profile is a file' elseecho '~/.bash_profile is not a file' fiprintf '\n'if [ -d ~/ ]; thenecho '~/ is a directory' elseecho '~/ is not a directory' fi-f即判斷是否為file, -d即判斷是否為directory, 輸出結(jié)果:
+ '[' -f /Users/yjmyzz/.bash_profile ']' + echo '~/.bash_profile is a file' ~/.bash_profile is a file + printf '\n'+ '[' -d /Users/yjmyzz/ ']' + echo '~/ is a directory' ~/ is a directory?
5.命令列表
命令1 && 命令2
解釋:如果命令1返回成功,則命令2會(huì)執(zhí)行,示例:
#!/bin/bash ping -c 4 $1 && printf '\n==== %s connected ====\n' $1將上面這段保存成testurl.sh,然后chmod +x testurl.sh,執(zhí)行效果如下:
./testurl.sh www.baidu.com PING www.a.shifen.com (115.239.211.112): 56 data bytes 64 bytes from 115.239.211.112: icmp_seq=0 ttl=50 time=9.950 ms 64 bytes from 115.239.211.112: icmp_seq=1 ttl=50 time=23.994 ms 64 bytes from 115.239.211.112: icmp_seq=2 ttl=50 time=12.272 ms 64 bytes from 115.239.211.112: icmp_seq=3 ttl=50 time=19.717 ms--- www.a.shifen.com ping statistics --- 4 packets transmitted, 4 packets received, 0.0% packet loss round-trip min/avg/max/stddev = 9.950/16.483/23.994/5.641 ms==== www.baidu.com connected ====如果把后面的參數(shù) ,換成某個(gè)不能訪問(wèn)的網(wǎng)址,比如在偉大的墻內(nèi),可以試下:
./testurl.sh www.google.com PING www.google.com (216.58.197.100): 56 data bytes Request timeout for icmp_seq 0 Request timeout for icmp_seq 1 Request timeout for icmp_seq 2--- www.google.com ping statistics --- 4 packets transmitted, 0 packets received, 100.0% packet loss命令1 || 命令2
解釋:這個(gè)正好跟&&相反,如果命令1返回失敗,則執(zhí)行命令2
#!/bin/bash ping -c 4 $1 || printf '\n==== %s connect fail ====\n' $1把這個(gè)保存成testurl2.sh ,然后重復(fù)剛才的測(cè)試
./testurl2.sh www.google.com PING www.google.com (216.58.199.4): 56 data bytes Request timeout for icmp_seq 0 Request timeout for icmp_seq 1 Request timeout for icmp_seq 2--- www.google.com ping statistics --- 4 packets transmitted, 0 packets received, 100.0% packet loss==== www.google.com connect fail ====通過(guò)剛才的測(cè)試,相信大家已經(jīng)掌握&&與||的用法了,那么問(wèn)題來(lái)了,如何判斷前一個(gè)命令的執(zhí)行結(jié)果是【成功】還是【失敗】呢?
先回憶一下,大學(xué)里《C程序設(shè)計(jì)》里老師講的內(nèi)容,C程序里main函數(shù),如果運(yùn)行成功,最后一般會(huì)約定返回return 0,沒(méi)錯(cuò)bash里就是這么判斷的
(再提一個(gè)問(wèn)題:為什么要跟C扯上關(guān)系?因?yàn)閘inux里的很多bash命令,就是拿C/C++來(lái)開(kāi)發(fā)的),我們可以來(lái)驗(yàn)證下:
#include <stdio.h> #include <stdlib.h> int main(int argc,char **argv){printf("hello world and this function will return 0\n");return 0; }這是一段c語(yǔ)言的代碼,保存成hello1.c,然后輸入gcc -o hello1 hello1.c (mac本上只要安裝了xcode,就已經(jīng)自帶了gcc編譯器),然后會(huì)在當(dāng)前目錄下生成hello1的可執(zhí)行文件,做為對(duì)比,再來(lái)一個(gè)hello2.c
#include <stdio.h> #include <stdlib.h> int main(int argc,char **argv){printf("hello world and this function will return 1\n");return 1; }同樣編譯成hello2,然后測(cè)試:
./hello1 && echo 'hello1 is ok' hello world and this function will return 0 hello1 is ok再來(lái)一個(gè)
./hello2 && echo 'you can not see this' hello world and this function will return 1小結(jié):這跟很多語(yǔ)言里約定1代表true, 0代表false正好是反的,在bash里,如果一個(gè)命令執(zhí)行后返回0,表示成功,返回1表示失敗。
?
6. 檢測(cè)參數(shù)個(gè)數(shù)及類型
最后結(jié)合前面學(xué)到的知識(shí),做一個(gè)小小的綜合練習(xí):
#!/bin/bashecho 'param count: ' $# echo 'first param: ' $1 if [ $# -eq 1 ] && (echo $1 | grep ^[0-9]*$ >/dev/null); thenecho 'param check pass!' elseecho 'only one integer parameter is accepted!' fi上面這段代碼的意思是僅接收1個(gè)整型的參數(shù),將這段代碼保存成check1.sh,然后試著運(yùn)行下:
./check1.sh a b 2 param count: 3 first param: a only one integer parameter is accepted!再試下:
./check1.sh 123 param count: 1 first param: 123 param check pass!第5行的那個(gè)長(zhǎng)長(zhǎng)的if判斷,初次看估計(jì)比較暈,我們來(lái)分解一下:
第一部分
[ $# -eq 1]其中$#表示參數(shù)的個(gè)數(shù),-eq 1 要求參數(shù)個(gè)數(shù)必須等于1
第二部分
(echo $1 | grep ^[0-9]*$ >/dev/null)仍然有點(diǎn)復(fù)雜,再細(xì)分一下,先不管最后的>/dev/null,將其去掉,然后簡(jiǎn)化一下:
grep 用于字符查找及過(guò)濾,見(jiàn)下面的圖:
who用于顯示本機(jī)有哪些用戶登錄了,以及登錄的終端信息,加上管道符|,將輸出結(jié)果傳遞給grep 001 ,最后就從who的一堆結(jié)果中,過(guò)濾出包含001的信息了。
再回過(guò)頭,看下這個(gè):
echo 123 | grep ^[0-9]*$會(huì)輸出123(注:如果mac上將終端改成了zsh,直接運(yùn)行會(huì)報(bào)錯(cuò)zsh: no matches found: ^[0-9]*$,解決辦法:新建一個(gè).sh腳本文件,寫(xiě)在腳本文件里就能運(yùn)行了),grep后的部分是一個(gè)正則表達(dá)式,匹配0-9中的1個(gè)或多個(gè),最后再來(lái)看:
(echo $1 | grep ^[0-9]*$ >/dev/null)現(xiàn)在應(yīng)該能看懂了吧,將1個(gè)參數(shù)輸出,然后做為grep的輸入,正常情況下,如果第1個(gè)參數(shù)為數(shù)字,則會(huì)輸出,但是我們的本意是放在if條件判斷中,并不希望將其輸出,所以最后重定向到黑洞。
結(jié)合前面的命令列表&&,可以將這段if簡(jiǎn)化成終極版本:
#!/bin/bash -x! ([ $# -eq 1 ] && (echo $1 | grep ^[0-9]*$ >/dev/null)) && echo 'only one integer parameter is accecpted ' && exit 1 echo 'param check pass!'就不解釋了,大家自己體會(huì)吧。
轉(zhuǎn)載于:https://www.cnblogs.com/yjmyzz/p/bash-shell-programming-study-2.html
總結(jié)
以上是生活随笔為你收集整理的bash/shell编程学习(2)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 【考研数学】张宇1000题,汤家凤180
- 下一篇: 从零开始学编程系列汇总