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

Hello! 歡迎來到小浪云!


第二節:Bash編程易犯的錯誤


avatar
小浪云 2024-12-12 151

第二節:Bash編程易犯的錯誤

上一篇文章參見 第一節:bash編程易犯的錯誤。

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

你不應該在一個管道中,從一個文件讀的同時,再往相同的文件里面寫,這樣的后果是未知的。

你可以為此創建一個臨時文件,這種做法比較安全可靠:

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

或者,如果你用得是 gnu Sed 4.x 以上的版本,可以使用-i 選項即時修改文件的內容:

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

14. echo $foo

這種看似無害的命令往往會給初學者千萬極大的困擾,他們會懷疑是不是因為 $foo 變量的值是錯誤的。事實卻是因為,$foo 變量在這里沒有使用雙引號,所以在解析的時候會進行單詞拆分和文件名展開,最終導致執行結果與預期大相徑庭:

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

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

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

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

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

 printf "%s " "$foo" 

15. $foo=bar

略過

16. foo = bar

當賦值時,等號兩邊是不允許出現空格的,這同 C 語言不一樣。當你寫下 foo = bar 時,Shell 會將該命令解析成三個單詞,然后第一個單詞 foo 會被認為是一個命令,后面的內容會被當作命令參數。

同樣地,下面的寫法也是錯誤的:

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

正確的寫法應該是這樣的:

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

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

 echo "Hello world How's it going?" 

18. su -c ‘some command’

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

 $ 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 命令執行是否成功,你可以會在錯誤的目錄下執行 bar 命令,這有可能會帶來災難,比如 bar 命令是 rm -rf *。

你必須經常檢查 cd 命令執行是否有錯誤,簡單的做法是:

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

出錯時,cd 命令會報告無法改變當前目錄,同時將錯誤消息輸出到標準錯誤,例如”bash: cd: /foo: No such file or directory”。如果你想要在標準輸出同時輸出自定義的錯誤提示,可以使用復合命令(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 之間需要有一個空格,同時}之前要加上分號。

順便提一下,如果你要在腳本里頻繁改變當前目錄,可以看看 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 

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

20. [ bar == “$foo” ]

正確的用法:

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

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

你不應該在&后面添加分號,刪除它:

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

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

22. cmd1 && cmd2 || cmd3

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

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

但是,這種結構并不是在所有情況下都完全等價于 if…fi 語法。這是因為在&&后面的命令執行結束時也會生成一個返回碼,如果該返回碼不是真值(0代表 true),||后面的命令也會執行,例如:

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

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

其中,((i++))命令執行算術運算,表達式計算的結果為0。這里和 C 語言一樣,表達式的結果為0被認為是 false。所以當 i=0 的時候,((i++))命令執行的返回碼為1(false),從而會執行接下來的((i–))命令。

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

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

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

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

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

23. echo “Hello World!”

在交互式的 Shell 環境下,你執行以上命令會遇到下面的錯誤:

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

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

相關閱讀

主站蜘蛛池模板: 欧美一级大片免费观看 | 欧美极品大肚孕妇孕交 | 亚洲人成在线观看 | 久久综久久美利坚合众国 | 欧洲美女与男人做爰 | 美女又黄又免费的视频 | 免费观看一区二区 | 国产精品三区四区 | 国产成人综合手机在线播放 | 亚洲精品无码不卡在线播放he | a级国产乱理伦片在线 | 手机看片自拍日韩日韩高清 | 91精品久久久久亚洲国产 | 手机看片自拍自自拍日韩免费 | 欧美综合视频在线 | 一区二区欧美视频 | 中文三 级 黄 色 片 | 亚洲视频在线一区 | 国产91成人精品亚洲精品 | 国产一区二区三区亚洲综合 | 理论片我不卡在线观看 | 中国黄色网址大全 | 中文字幕视频免费在线观看 | 免费国内精品久久久久影院 | 99国产精品农村一级毛片 | 亚洲午夜精品一级在线 | 国产精品路边足疗店按摩 | 亚洲无限看 | 亚洲图片偷拍自拍 | 秘书高跟黑色丝袜国产91在线 | 做爰成人五级在线视频| 亚洲国产爱久久全部精品 | 边接电话边做国语高清对白 | 日本精品国产 | 日本免费在线视频 | 国产精品香蕉一区二区三区 | 另类视频一区 | 中文久久| 欧美一区二区三区在线 | 手机国产精品一区二区 | 久久ri精品高清一区二区三区 |