歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux基礎 >> 關於Linux

簡潔的bash編程技巧

簡潔的bash編程技巧   1) 檢查命令執行是否成功     第一種寫法,比較常見:   echo   abcdee | grep   -q abcd        if   [ $? -eq   0 ]; then       echo   "Found"   else       echo   "Not found"   fi   簡潔的寫法:   if   echo  abcdee | grep   -q abc; then       echo   "Found"   else       echo   "Not found"   fi   當然你也可以不要if/else,不過這樣可讀性比較差:   [Sun  Nov 04 05:58 AM] [kodango@devops] ~/workspace   $ echo   abcdee | grep   -q abc && echo   "Found"  || echo   "Not found"   Found       2) 將標准輸出與標准錯誤輸出重定向到/dev/null 第一種寫法,比較常見:     1   grep   "abc"  test.txt  1>/dev/null   2>&1   常見的錯誤寫法:     1   grep   "abc"  test.txt  2>&1 1>/dev/null   簡潔的寫法:     1   grep   "abc"  test.txt  &> /dev/null   3) awk的使用     舉一個實際的例子,獲取Xen DomU的id。     常見的寫法:     1   sudo   xm li | grep   vm_name | awk   '{print $2}'   簡潔的寫法:     1   sudo   xm li | awk   '/vm_name/{print $2}'   4) 將一個文本的所有行用逗號連接起來     假設文件內容如下所示:     [Sat  Nov 03 10:04 PM] [kodango@devops] ~/workspace   $ cat   /tmp/test.txt   1   2   3   使用Sed命令:     1   2   3   [Sat  Nov 03 10:14 PM] [kodango@devops] ~/workspace   $ sed   ':a;$!N;s/\n/,/;ta'  /tmp/test.txt   1,2,3   簡潔的寫法:     1   2   3   [Sat  Nov 03 10:04 PM] [kodango@devops] ~/workspace   $ paste   -sd, /tmp/test.txt   1,2,3   5) 過濾重復行     假設文件內容如下所示:     [Sat  Nov 03 10:16 PM] [kodango@devops] ~/workspace   $ sort   /tmp/test.txt       常用的方法:     [Sat  Nov 03 10:16 PM] [kodango@devops] ~/workspace   $ sort   /tmp/test.txt  | uniq   1   2   3   簡單的寫法:     [Sat  Nov 03 10:16 PM] [kodango@devops] ~/workspace   $ sort   /tmp/test.txt  -u     6) grep查找單詞     假設一個文本的每一行是一個ip地址,例如   [Sat  Nov 03 10:20 PM] [kodango@devops] ~/workspace   $ cat   /tmp/ip.list   10.0.0.1   10.0.0.12   10.0.0.123   使用grep查找是否包括10.0.0.1這個ip地址。常見的寫法:     [Sat  Nov 03 10:22 PM] [kodango@devops] ~/workspace   $ grep   '10.0.0.1\>'  /tmp/ip.list   10.0.0.1   簡單的方法(其實這方法不見得簡單,只是為了說明-w這個參數還是很有用的)     1   2   3   [Sat  Nov 03 10:23 PM] [kodango@devops] ~/workspace   $ grep   -w '10.0.0.1'   /tmp/ip.list   10.0.0.1   順便grep的-n/-H/-v/-f/-c這幾參數都很有用。     7) 臨時設置環境變量     常見的寫法:   [Sat  Nov 03 10:26 PM] [kodango@devops] ~/workspace   $ export   LC_ALL=zh_CN.UTF-8         [六  11月 03 10:26 下午] [kodango@devops] ~/workspace   $ date   2012年  11月 03日 星期六 22:26:55 CST   簡潔的寫法:   [六  11月 03 10:26 下午] [kodango@devops] ~/workspace   $ unset   LC_ALL        [Sat  Nov 03 10:27 PM] [kodango@devops] ~/workspace   $  LC_ALL=zh_CN.UTF-8 date   2012年  11月 03日 星期六 22:27:43 CST   在命令之前加上環境變更的設置,只是臨時改變當前執行命令的環境。     8) $1,$2…等位置參數的使用     假設只想使用$2,$3..這幾個參數,常見的做法是:     1   2   shift   echo   "$@"   為什麼不這樣寫呢?     1   echo   "${@:2}"   9)退而求其次的寫法     相信大家會有這種需求,當一個參數值沒有提供時,可以使用默認值。常見的寫法是:   arg=$1        if   [ -z "$arg"   ]; then      arg=0   fi   簡潔的寫法是這樣的:     1   arg=${1:-0}   10)bash特殊參數–的用法     假設要用grep查找字符串中是否包含-i,我們會這樣嘗試:   [Sat  Nov 03 10:45 PM] [kodango@devops] ~/workspace   $ echo   'abc-i'  | grep   "-i"   Usage: grep   [OPTION]... PATTERN [FILE]...   Try 'grep  --help'  for  more  information.        [Sat  Nov 03 10:45 PM] [kodango@devops] ~/workspace   $ echo   'abc-i'  | grep   "\-i"   abc-i   簡潔的方法是:     1   2   3   [Sat  Nov 03 10:45 PM] [kodango@devops] ~/workspace   $ echo   'abc-i'  | grep   -- -i   abc-i   bash中–後面的參數不會被當作選項解析。     11)函數的返回值默認是最後一行語句的返回值     #  Check whether an item is a function   #  $1: the function name   #  Return: 0(yes) or 1(no)   function   is_function()   {       local   func_name=$1       test   "`type -t $1 2>/dev/null`"  = "function"   }   不要畫蛇添足再在後面加一行return $?了。     12) 將printf格式化的結果賦值給變量     例如將數字轉換成其十六進制形式,常見的寫法是:     1   2   [Sat  Nov 03 10:55 PM] [kodango@devops] ~/workspace   $  var=$(printf   '%%%02x'  111)   簡單的寫法是:     1   2   [Sat  Nov 03 10:54 PM] [kodango@devops] ~/workspace   $ printf   -v   var '%%%02x'   111   看看printf的help   [Sat  Nov 03 10:53 PM] [kodango@devops] ~/workspace   $  help printf   | grep   -A 1 -B 1 -- -v   printf: printf   [-v   var] format   [arguments]       Formats  and prints ARGUMENTS under control of the FORMAT.   --       Options:         -v   var    assign the output to shell variable VAR rather than               display  it on the standard output   13)打印文件行     打印文件的第一行:     1   head   -1 test.txt   打印文件的第2行:     1   sed   -n '2p'   test.txt   打印文件的第2到5行:     1   sed   -n '2,5p'   test.txt   打印文件的第2行始(包括第2行在內)5行的內容:     1   sed   -n '2,+4p'   test.txt   打印倒數第二行:     1   2   $ tail   -2 test.txt  | head   -1   $  tac test.txt  | sed   -n '2p'   14)善用let或者(())命令做算術運算     如何對一個數字做++運算,可能你會這樣用:     1   2   a=1   a=`expr   a + 1`   為何不用你熟悉的:     1   2   3   a=1   let   a++   let   a+=2   15)獲取軟連接指定的真實文件名     如果你不知道,你可能會這樣獲取:     1   2   3   [Sat  Nov 03 11:12 PM] [kodango@devops] ~/workspace   $ ls   -l /usr/bin/python   | awk   -F'->'   '{print $2}'  | tr   -d '  '   /usr/bin/python2   如果你知道有一個叫readlink的命令,那麼:     1   2   3   [Sat  Nov 03 11:13 PM] [kodango@devops] ~/workspace   $  readlink /usr/bin/python   /usr/bin/python2   16)獲取一個字符的ASCII碼   [Sat  Nov 03 11:14 PM] [kodango@devops] ~/workspace   $ printf   '%02x'  "'+"   2b   [Sat  Nov 03 11:30 PM] [kodango@devops] ~/workspace   $ echo   -n '+'   | od -tx1 -An | tr   -d '  '   2b   17)清空一個文件     常見的用法:     1   echo   ""  > test.txt   簡單的寫法:     1   > test.txt   18) 不要忘記有here document     下面一段代碼:   grep   -v   1 /tmp/test.txt  | while   read  line; do       let   a++       echo   --$line--   done        echo   a:$a   執行後有什麼問題嗎?   [Sun  Nov 04 05:35 AM] [kodango@devops] ~/workspace   $  sh test.sh   --2--   --3--   a:   發現a這個變量沒有被賦值,為什麼呢?因為管道後面的代碼是在在一個子shell中執行的,所做的任何更改都不會對當前shell有影響,自然a這個變量就不會有賦值了。     換一種思路,可以這樣做:   grep   -v   1 /tmp/test.txt  > /tmp/test.tmp        while   read  line; do       let   a++       echo   --$line--   done   < /tmp/test.tmp        echo   a:$a   rm   -f /tmp/test.tmp   不過多了一個臨時文件,最後還要刪除。這裡其實可以用到here document:   b=1   while   read  line2; do       let   b++       echo   ??$line2??   done   < < EOF   `grep   -v   1 /tmp/test.txt`   EOF        echo   b: $b   here document往往用於需要輸出一大段文本的地方,例如腳本的help函數。     19)刪除字符串中的第一個或者最後一個字符     假設字符串為:     1   2   [Sun  Nov 04 10:21 AM] [kodango@devops] ~/workspace   $  str="aremoveb"   可能你第一個想法是通過sed或者其它命令來完成這個功能,但是其實有很簡單的方法:   [Sun  Nov 04 10:24 AM] [kodango@devops] ~/workspace   $ echo   "${str#?}"   removeb        [Sun  Nov 04 10:24 AM] [kodango@devops] ~/workspace   $ echo   "${str%?}"   aremove   類似地,你也可以刪除2個、3個、4個……     有沒有一次性刪除第一個和最後一個字符的方法呢?答案當然是肯定的:     1   2   3   [Sun  Nov 04 10:26 AM] [kodango@devops] ~/workspace   $ echo   "${str:1:-1}"   remove   關於這些變量替換的內容在bash的man手冊中都有說明。     20)使用逗號join數組元素     假設數組元素沒有空格,可以用這種方法:   [Sun  Nov 04 10:14 AM] [kodango@devops] ~/workspace   $  a=(1 2 3)    $  b="${a[*]}"        [Sun  Nov 04 10:15 AM] [kodango@devops] ~/workspace   $ echo   ${b//   /,}   1,2,3   假設數組元素包含有空格,可以借用printf命令來達到:   [Sun  Nov 04 10:15 AM] [kodango@devops] ~/workspace   $  a=(1 "2  3"  4)        [Sun  Nov 04 10:15 AM] [kodango@devops] ~/workspace   $ printf   ",%s"  "${a[@]}"  | cut   -c2-      1,2  3,4   21) Shell中的多進程     在命令行下,我們會在命令行後面加上&符號來讓該命令在後台執行,在shell腳本中,使用”(cmd)”可以讓fork一個子shell來執行該命令。利用這兩點,可以實現shell的多線程:   job_num=10        function   do_work()   {       echo   "Do work.."   }        for   ((i=0; i<job_num ;i++)); do       echo   "Fork job $i"       (do_work)  &   done        wait   #  wait for all job done   echo   "All job have been done!"   注意最後的wait命令,作用是等待所有子進程結束。     22) bash中alias的使用     alias其實是給常用的命令定一個別名,比如很多人會定義一下的一個別名:     1   alias   ll='ls  -l'   以後就可以使用ll,實際展開後執行的是ls -l。     現在很多發行版都會帶幾個默認的別名,比如:   alias   grep='grep  --color=auto'   # 帶顏色顯示   alias   ls='ls  --color=auto'  # 同上   alias   rm='rm  -i'   # 刪除文件需要確認   alias在某些方面確實提高了很大的效率,但是也是有隱患的,這點可以看我以前的一篇文章終端下肉眼看不見的東西。那麼如何不要展開alias,而是用本來的意思呢?答案是使用轉義:     1   2   \ls   \grep   在命令前面加一個反斜槓後就可以了。     這裡要插一段故事,前兩天我在shell腳本中定義了下面的一個alias,假設位於文件util.sh:   #!/bin/bash   ...   alias   ssh='ssh  -o StrictHostKeyChecking=no -o LogLevel=quiet -o BatchMode=yes'   ...   後面這串ssh選項是為了去掉一些warning的信息,不提示輸入密碼等等。具體可以看ssh的文檔說明。我自己測試的時候好好的,當時我同事跑得時候卻依然有報Warning。我對比了下我們兩個人的用法:     1   2   sh  util.sh  #  我的   ./util.sh   #  他的   大家應該知道,直接./util.sh執行,shell會去找腳本第一行的shebang中給定的解釋器去執行改腳本,所以第二種用法相當於直接用bash來執行。那想必是bash/sh對alias是否默認展開這一點上是有區別的了(可能是bash版本的問題,RHEL 5U4)。翻閱了下Bash的man手冊,發現可以通過設置expand_aliases選項來打開alias展開的功能,默認在非交互式Shell下是關閉的(什麼是交互式登錄Shell)。     修改下util.sh,打開這個選項就Ok了:   #!/bin/bash   ...   #  Expand aliases in script   shopt   -s expand_aliases   alias   ssh='ssh  -o StrictHostKeyChecking=no -o LogLevel=quiet -o BatchMode=yes'   ...   23)awk打印除第一列之外的其他列     awk用來截取輸入行中的某幾列很有用,當時如果要排除某幾列呢?     例如有如下的一個文件:   $ cat   /tmp/test.txt   1  2 3 4 5   10  20 30 40 50   可以用下面的代碼解決(來源):     1   2   3   $ awk   '{$1="";print $0}'  /tmp/test.txt    2  3 4 5    20  30 40 50   但是前面多了一個空格,可以用cut命令稍微調整下:     1   2   3   $ awk   '{$1="";print $0}'  /tmp/test.txt  | cut   -c2-   2  3 4 5   20  30 40 50   附幾則小技巧:     1)sudo iptables -L -n | vim -     2)grep -v xxx | vim -      3)echo $’\”     4)set — 1 2 3; echo “$@”     5)搜索stackoverflow/superuser等站點
Copyright © Linux教程網 All Rights Reserved