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

Hello! 歡迎來到小浪云!


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


avatar
小浪云 2024-12-15 135

第三節: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編程易犯的錯誤。

相關閱讀

主站蜘蛛池模板: 在线精品视频免费观看 | 一级一级一片免费高清 | 日本免费观看的视频在线 | 毛片1毛片2毛片3毛片4 | 在线观看亚洲网站 | 中文字幕乱码中文乱码综合 | 国产精品视频999 | 国产高中生粉嫩无套第一次 | 免费看一毛一级毛片视频 | 日韩视频在线观看 | 伊人久久综合热青草 | 成人午夜两性视频免费看 | 日韩视频在线观看 | 夜色www国产精品资源站 | 国产精品久久久久亚洲 | 成人毛片免费观看视频在线 | 久久综合99re久久爱 | 亚洲免费小视频 | 亚洲制服欧美自拍另类 | 亚洲欧美大片 | 久久久影院亚洲精品 | 黄色网址www | 国产一区二区在线视频 | 成人国产在线24小时播放视频 | 精品九九视频 | 国产午夜不卡在线观看视频666 | 国产成人做受免费视频 | 亚洲国产精品区 | 日本美女黄网站 | 欧美亚洲国产激情一区二区 | 国产美女一区二区在线观看 | 国产精在线 | 中文字幕有码在线播放 | 亚洲三级在线 | 男女上下爽无遮挡午夜免费视频 | 久久精品视频网 | 91精品欧美综合在线观看 | 美国特级毛片 | 亚洲精品综合欧美一区二区三区 | 一级毛片免费播放视频 | 荡女妇边被c边呻吟久久 |