九色91_成人精品一区二区三区中文字幕_国产精品久久久久一区二区三区_欧美精品久久_国产精品99久久久久久久vr_www.国产视频

Hello! 歡迎來到小浪云!


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


avatar
小浪云 2024-12-15 168

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

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

24. for arg in $*

和大多數 Shell 一樣,Bash 支持依次讀取單個命令行參數的語法。不過這并是$*或者$@,這兩種寫法都不正確,它們只能得到完整的參數列表,并非單獨的一個個參數。

正確的語法是(沒錯要加上引號):

 for arg in "$@" 

# 或者更簡單的寫法

 for arg 

在腳本中遍歷所有參數是一個再普遍不過的需求,所以 for arg 默認等價于 for arg in “$@”。$@使用雙引號后就有特殊的魔力,每個參數展開后成為一個獨立的單詞。(”$@”等價于”$1” “$2” “$3” …)

下面是一個錯誤的例子:

 for x in $*; do    echo "parameter: '$x'" done  執行的結果為:  $ ./myscript 'arg 1' arg2 arg3 parameter: 'arg' parameter: '1' parameter: 'arg2' parameter: 'arg3' 

正確的寫法:

 for x in "$@"; do    echo "parameter: '$x'" done  執行的結果為:  $ ./myscript 'arg 1' arg2 arg3 parameter: 'arg 1' parameter: 'arg2' parameter: 'arg3' 

上面正確的例子中,第一個參數’arg 1’在展開后依然是一個獨立的單詞,而不會被拆分成兩個。

25. function foo()

這種寫法不一定能夠兼容所有 shell,兼容的寫法是:

 foo() {   ... } 

26. echo “~”

波浪號展開(Tilde expansion)僅當~沒有引號的時候發生,在上面的例子中,只會向標準輸出打印~符號,而不是當前用戶的家目錄路徑。

當用引號將路徑參數引起來時,如果要用引號將相對于家目錄的路徑引起來時,推薦使用 $HOME 而不是 ~, 假如 $HOME 目錄是”/home/my photos”,路徑中包含空格。

下面是幾組例子:

 "~/dir with spaces" # expands to "~/dir with spaces" ~"/dir with spaces" # expands to "~/dir with spaces" ~/"dir with spaces" # expands to "/home/my photos/dir with spaces" "$HOME/dir with spaces" # expands to "/home/my photos/dir with spaces" 

27. local varname=$(command)

當在函數中聲明局部變量時,local作為一個獨立的命令,這種奇特的行為有時候可能會導致困擾。比如,當你想要捕獲命令替換的返回碼時,你就不能這樣做。local命令的返回碼會覆蓋它。

這種情況下,你只能分成兩行寫:

 local varname varname=$(command) rc=$? 

28. export foo=~/bar

export 與 local 命令一樣,并不是賦值語句的一部分。因此,在有些 Shell 下(比如Bash),export foo=~/bar會展開,但是有些(比如 dash)卻不行。

下面是兩種比較健壯的寫法:

 foo=~/bar; export foo    # Right! export foo="$HOME/bar"   # Right! 

29. sed ‘s/$foo/good bye/’

單引號內部不會展開 $foo變量,在這里可以換成雙引號:

 foo="hello"; sed "s/$foo/good bye/" 

但是要注意,如果你使用了雙引號,就需要考慮更多轉義的事情,具體可以看Quotes這一頁。.

30. tr [A-Z] [a-z]

這里至少有三個問題。第一個問題是, [A-Z] 和 [a-z] 會被 shell 認為是通配符。如果在當前目錄下沒用文件名為單個字母的文件,這個命令似乎能正確執行,否則會錯誤地執行,也許你會在周末耗費許多小時來修復這個問題。

第二個問題是,這不是 tr 命令正確的寫法,實際上,上面的命令會把[轉換成[,將任意大寫字符轉換成對應的小寫字符,將]轉換成],所以你根本不需要加上括號,這樣第一個問題就可以解決了。

第三個問題是,上面的命令執行結果依賴于當前的 locale,A-Z 或者 a-z 不一定會代表26個 ASCII 字母。實際上,在一些語言環境下,z 位于字母表的中間位置。這個問題的解法,取決于你希望發生的行為是哪一種。

如果你僅希望改變26個英文字母的大小寫(強制 locale為 C):

 LC_COLLATE=C tr A-Z a-z  如果你希望根據實際的語言環境來轉換:  tr '[:upper:]' '[:lower:]' 

31. ps ax | grep gedit

這里的根本問題是正在運行的進程名稱,本質上是不可靠的??赡軙卸鄠€合法的gedit進程,也有可能是別的東西偽裝成gedit進程(改變執行命令名稱是一件簡單的事情 ),更多細節可以看ProcessManagement這一篇文章。

執行以上命令,往往會在結果中包含 grep 進程:

 # ps ax | grep gedit 10530 ?        S      6:23 gedit 32118 pts/0    R+     0:00 grep gedit  這個時候,需要過濾多余的結果:  # ps ax | grep -v grep | grep gedit  上面的寫法比較丑陋,另外一種方法是:  # ps ax | grep [g]edit 

32. printf “$foo”

如果$foo 變量的值中包括或者%符號,上面命令的執行結果可能會出乎你的意料之外。

下面是正確的寫法:

 printf %s "$foo" printf '%s ' "$foo" 

33. for i in {1..$n}

Bash的命令解釋器會優先展開大括號,所以這時大括號{}表達式里面看到的是文字上的$n(沒有展開)。$n 不是一個數值,所以這里的大括號{}并不會展開成數字列表??梢姡@導致很難使用大括號來展開大小只能在運行時才知道的列表。

可以用下面的方法:

 for ((i=1; i< =n; i++)); do ... done 

注:之前我也有寫過一篇文章來介紹這個問題:Shell生成數字序列。

34. if [[ $foo = $bar ]]

在[[內部,當=號右邊的值沒有用引號引起來,bash 會將它當作模式來匹配,而不是一個簡單的字符串。所以,在上面的例子中 ,如果 bar 的值是一個*號,執行的結果永遠是 true。

所以,如果你想檢查兩側的字符串是否相同,等號右側的值一定要用引號引起來。

 if [[ $foo = "$bar" ]] 

如果你確實要執行模式匹配,聰明的做法是取一個更加有意義的變量名(例如$patt),或者加上注釋說明。

35. if [[ $foo =~ ‘some RE’ ]]

同上,如果=~號右側的值加上引號,它會散失特殊的正則表達式含義,而變成一個普通的字符串。

如果你想使用一個長的或者復雜的正則表達式,避免大量的反斜杠轉義,建議把它放在一個變量中:

 re='some RE' if [[ $foo =~ $re ]] 

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

相關閱讀

主站蜘蛛池模板: 国产精品欧美一区二区 | 99精品国自产在线 | 日韩在线小视频 | 神马久久春色视频 | 毛片免费在线 | 成人视屏在线观看 | 日日天天 | 在线看免费 | 99久久精品一区二区毛片吞精 | 九九免费在线视频 | 一区二区三区视频免费看 | 欧美一级二级在线观看 | 欧美激情欧美激情在线五月 | 九九视频网 | 欧美一级久久 | 欧美一级三级在线观看 | 插插插干干干 | 欧美日韩中文在线 | 天天av天天好逼 | 青草视频在线 | 日韩亚洲视频 | 在线观看av网站永久 | 国产精品特级毛片一区二区三区 | 国产精品久久久久久高潮 | 国产精品视频一区二区三区四蜜臂 | 天天色天天色 | 国产一级免费在线观看 | 国产粉嫩尤物极品99综合精品 | 亚洲精品乱码久久久久v最新版 | 91伦理片 | 国产日韩欧美精品一区二区 | 国产精品久久久久久久午夜片 | 1级毛片| 欧美精品一区二区三区四区五区 | 国产在线视频在线观看 | 久久久久国产一级毛片高清网站 | 国产天天操 | chengrenzaixian | 色综合久久天天综合网 | 亚洲黄色在线 | 久久精品中文字幕 |