久综合色-久综合网-玖草影视-玖草资源在线-亚洲黄色片子-亚洲黄色片在线观看

Hello! 歡迎來到小浪云!


第二節(jié):Bash編程易犯的錯(cuò)誤


avatar
小浪云 2024-12-12 171

第二節(jié):Bash編程易犯的錯(cuò)誤

上一篇文章參見 第一節(jié):bash編程易犯的錯(cuò)誤。

13. cat file | sed s/foo/bar/ > file

你不應(yīng)該在一個(gè)管道中,從一個(gè)文件讀的同時(shí),再往相同的文件里面寫,這樣的后果是未知的。

你可以為此創(chuàng)建一個(gè)臨時(shí)文件,這種做法比較安全可靠:

 # sed 's/foo/bar/g' file > tmpfile && mv tmpfile file 

或者,如果你用得是 gnu Sed 4.x 以上的版本,可以使用-i 選項(xiàng)即時(shí)修改文件的內(nèi)容:

 # sed -i 's/foo/bar/g' file 

14. echo $foo

這種看似無害的命令往往會給初學(xué)者千萬極大的困擾,他們會懷疑是不是因?yàn)?$foo 變量的值是錯(cuò)誤的。事實(shí)卻是因?yàn)椋?foo 變量在這里沒有使用雙引號,所以在解析的時(shí)候會進(jìn)行單詞拆分和文件名展開,最終導(dǎo)致執(zhí)行結(jié)果與預(yù)期大相徑庭:

 msg="Please enter a file name of the form *.zip" echo $msg 

這里整句話會被拆分成單詞,然后其中的通配符會被展開,例如*.zip。當(dāng)你的用戶看到如下的結(jié)果時(shí),他們會怎樣想:

  Please enter a file name of the form freenfss.zip lw35nfss.zip  再舉一個(gè)例子(假設(shè)當(dāng)前目錄下有以 .zip 結(jié)尾的文件):  var="*.zip"   # var 包括一個(gè)星號,一個(gè)點(diǎn)號和 zip echo "$var"   # 輸出 *.zip echo $var     # 輸出所有以 .zip 結(jié)尾的文件 

實(shí)際上,這里使用 echo 命令并不是絕對的安全。例如,當(dāng)變量的值包含-n時(shí),echo 會認(rèn)為它是一個(gè)合法的選項(xiàng)而不是要輸出的內(nèi)容(當(dāng)然如果你能夠保證不會有-n 這種值,可以放心地使用 echo 命令)。

完全可靠的打印變量值的方法是使用 printf

 printf "%s " "$foo" 

15. $foo=bar

略過

16. foo = bar

當(dāng)賦值時(shí),等號兩邊是不允許出現(xiàn)空格的,這同 C 語言不一樣。當(dāng)你寫下 foo = bar 時(shí),Shell 會將該命令解析成三個(gè)單詞,然后第一個(gè)單詞 foo 會被認(rèn)為是一個(gè)命令,后面的內(nèi)容會被當(dāng)作命令參數(shù)。

同樣地,下面的寫法也是錯(cuò)誤的:

 foo= bar    # WRONG! foo =bar    # WRONG! $foo = bar; # COMPLETELY WRONG! 

正確的寫法應(yīng)該是這樣的:

 foo=bar     # Right. foo="bar"   # more Right. 

17. echo 或者可以使用雙引號,它也可以跨越多行,而且因?yàn)?echo 命令是內(nèi)置命令,相同情況下它會更加高效:

 echo "Hello world How's it going?" 

18. su -c ‘some command’

這種寫法“幾乎”是正確的。問題是,在許多平臺上,su 支持 -c 參數(shù),但是它不一定是你認(rèn)為的。比如,在 OpenBSD 平臺上你這樣執(zhí)行會出錯(cuò):

 $ su -c 'echo hello' su: only the superuser may specify a login class  在這里,-c是用于指定login-class。如果你想要傳遞 -c 'some command' 給 shell,最好在之前顯示地指定 username:  $ su root -c 'some command' # Now it's right. 

19. cd /foo; bar

如果你不檢查 cd 命令執(zhí)行是否成功,你可以會在錯(cuò)誤的目錄下執(zhí)行 bar 命令,這有可能會帶來災(zāi)難,比如 bar 命令是 rm -rf *。

你必須經(jīng)常檢查 cd 命令執(zhí)行是否有錯(cuò)誤,簡單的做法是:

 cd /foo && bar  如果在 cd 命令后有多個(gè)命令,你可以選擇這樣寫:  cd /foo || exit 1 bar baz bat ... # Lots of commands. 

出錯(cuò)時(shí),cd 命令會報(bào)告無法改變當(dāng)前目錄,同時(shí)將錯(cuò)誤消息輸出到標(biāo)準(zhǔn)錯(cuò)誤,例如”bash: cd: /foo: No such file or directory”。如果你想要在標(biāo)準(zhǔn)輸出同時(shí)輸出自定義的錯(cuò)誤提示,可以使用復(fù)合命令(command grouping):

 cd /net || { echo "Can't read /net. make sure you've logged in to the Samba network, and try again."; exit 1; } do_stuff more_stuff 

注意,在{號和 echo 之間需要有一個(gè)空格,同時(shí)}之前要加上分號。

順便提一下,如果你要在腳本里頻繁改變當(dāng)前目錄,可以看看 pushd/popd/dirs 等命令,可能你在代碼里面寫的 cd/pwd 命令都是沒有必要的。

說到這,比較下下面兩種寫法:

 find ... -type d -print0 | while IFS= read -r -d '' subdir; do    here=$PWD    cd "$subdir" && whatever && ...    cd "$here" done find ... -type d -print0 | while IFS= read -r -d '' subdir; do    (cd "$subdir" || exit; whatever; ...) done 

下面的寫法,在循環(huán)fork 了一個(gè)子 shell 進(jìn)程,子 shell 進(jìn)程中的 cd 命令僅會影響當(dāng)前 shell的環(huán)境變量,所以父進(jìn)程中的環(huán)境命令不會被改變;當(dāng)執(zhí)行到下一次循環(huán)時(shí),無論之前的 cd 命令有沒有執(zhí)行成功,我們會回到相同的當(dāng)前目錄。這種寫法相較前面的用法,代碼更加干凈。

20. [ bar == “$foo” ]

正確的用法:

 [ bar = "$foo" ] && echo yes [[ bar == $foo ]] && echo yes 

21. for i in {1..10}; do ./something &; done

你不應(yīng)該在&后面添加分號,刪除它:

 for i in {1..10}; do ./something & done  或者改成多行的形式:  for i in {1..10}; do     ./something & done 

&和分號一樣也可以用作命令終止符,所以你不要將兩個(gè)混用到一起。一般情況下,分號可以被換行符替換,但是不是所有的換行符都可以用分號替換。

22. cmd1 && cmd2 || cmd3

有些人喜歡把&&和||作為if…then…else…fi 的簡寫語法,在多數(shù)情況下,這種寫法沒有問題。例如:

 [[ -s $errorlog ]] && echo "Uh oh, there were some errors." || echo "Successful." 

但是,這種結(jié)構(gòu)并不是在所有情況下都完全等價(jià)于 if…fi 語法。這是因?yàn)樵?amp;&后面的命令執(zhí)行結(jié)束時(shí)也會生成一個(gè)返回碼,如果該返回碼不是真值(0代表 true),||后面的命令也會執(zhí)行,例如:

 i=0 true && ((i++)) || ((i--)) echo $i # 輸出 0 

看起來上面的結(jié)果應(yīng)該是返回1,但是結(jié)果卻是輸出0,為什么呢?原因是這里 i++ 和 i– 都執(zhí)行了一遍。

其中,((i++))命令執(zhí)行算術(shù)運(yùn)算,表達(dá)式計(jì)算的結(jié)果為0。這里和 C 語言一樣,表達(dá)式的結(jié)果為0被認(rèn)為是 false。所以當(dāng) i=0 的時(shí)候,((i++))命令執(zhí)行的返回碼為1(false),從而會執(zhí)行接下來的((i–))命令。

如果我們在這里使用前綴自增運(yùn)算符的話,返回的結(jié)果恰恰為1,因?yàn)?(++i))執(zhí)行的返回碼是0(true):

 i=0 true && (( ++i )) || (( --i )) echo $i # Prints 1 

不過在你無法保證 y 的執(zhí)行結(jié)果是,絕對不要依靠 x && y || z這種寫法。上面這種巧合,在 i 初始化為-1時(shí)也會有問題。

如果你喜歡代碼更加安全健壯,建議使用 if…fi 語法:

 i=0 if true; then    ((i++)) else    ((i--)) fi  echo $i # 輸出 1 

23. echo “Hello World!”

在交互式的 Shell 環(huán)境下,你執(zhí)行以上命令會遇到下面的錯(cuò)誤:

 bash: !": event not found  這是因?yàn)椋谀J(rèn)的交互式 Shell 環(huán)境下,Bash 發(fā)現(xiàn)感嘆號時(shí)會執(zhí)行歷史命令展開。在 Shell 腳本中,這種行為是被禁止的,所以不會發(fā)生錯(cuò)誤。  不幸地是,你認(rèn)為明顯正確地修復(fù)方法,也不能工作,你會發(fā)現(xiàn)反斜杠并沒有轉(zhuǎn)義感嘆號:  # echo "hi!" hi!  最簡單地方法是禁用 histexpand 選項(xiàng),你可以通過 set +H 或者 set +o histexpand 命令來完成。  下面四種寫法都可以解決:  # 1. 使用單引號  echo 'Hello World!'  # 2. 禁用 histexpand 選項(xiàng)  set +H echo "Hello World!"  # 3. 重置 histchars  histchars=  # 4. 控制 shell 展開的順序,命令行歷史展開是在單詞拆分之前執(zhí)行的  # 參見:Bash man 手冊的History Expansion一節(jié)  exmark='!'  echo "Hello, world$exmark"  

由于篇幅限制,本系列文章會分成多篇文章,下一篇參見第節(jié):Bash編程易犯的錯(cuò)誤。

相關(guān)閱讀

主站蜘蛛池模板: 国产主播福利片在线观看 | 欧美区一区 | 久久免费视频播放 | 亚洲免费网站在线观看 | 国产视频三级 | 久草视频免费在线播放 | 成人自拍视频 | 国产偷国产偷亚洲高清在线 | 亚洲狠狠综合久久 | 欧美巨大另类极品videohd | 国产男女在线观看 | 国产日韩一区二区三区在线观看 | 日韩欧美国产高清在线观看 | 2019在线亚洲成年视频网站 | 91成年人免费视频 | 欧美一区二区三区视频在线 | 精品国产一区二区二三区在线观看 | 久久久久久久久久久大尺度免费视频 | 国产精品日韩欧美 | 99精品国产一区二区三区 | 色网址在线 | 亚洲依依成人综合在线网址 | 成年女人免费视频 | 欧日韩美香蕉在线观看 | 亚洲毛片免费观看 | 国产日韩久久 | 国产久草视频在线 | 国内交换一区二区三区 | 亚州在线视频 | 欧美做爰野外在线视频观看 | 九九成人免费视频 | 黄.www| 亚洲久草| 久久成人免费网站 | 日韩在线一区二区三区视频 | 黄色成人在线网站 | 亚洲性影院 | 无内丝袜透明在线播放 | 加勒比综合网 | 国产视频网站在线观看 | 性欧美一级毛片欧美片 |