Linux Shell進階技巧(三)

來源:互聯網
上載者:User

十三、格式化輸出指定使用者的當前運行進程:

      在這個例子中,我們通過指令碼參數的形式,將使用者列表傳遞給該指令碼,指令碼在讀取參數後,以樹的形式將使用者列表中使用者的所屬進程列印出來。
      /> cat > test13.sh
      #!/bin/sh
      #1. 迴圈讀取指令碼參數,構造egrep可以識別的使用者列表變數(基於grep的擴充Regex)。
      #2. userlist變數尚未賦值,則直接使用第一個參數為它賦值。
      #3. 如果已經賦值,且指令碼參數中存在多個使用者,這裡需要在每個使用者名稱之間加一個豎線,在egrep中,豎線是分割的元素之間是或的關係。
      #4. shift命令向左移動一個指令碼的位置參數,這樣可以使迴圈中始終操作第一個參數。
      while [ $# -gt 0 ]

      do
          if [ -z "$userlist" ]; then
              userlist="$1"
          else
              userlist="$userlist|$1"
          fi
           shift
      done
      #5. 如果沒有使用者列表,則搜尋所有使用者的進程。
      #6. "^ *($userlist) ": 下面的調用方式,該正則的展開形式為"^ *(root|avahi|postfix|rpc|dbus) "。其含義為,以0個或多個空格開頭,之後將是root、avahi、postfix、rpc或dbus之中的任何一個字串,後面再跟隨一個空格。
      if [ -z "$userlist" ]; then
          userlist="."
      else
          userlist="^ *($userlist) "
      fi
      #7. ps命令輸出所有進程的user和命令資訊,將結果傳遞給sed命令,sed將刪除ps的title部分。
      #8. egrep過濾所有進程記錄中,包含指定使用者列表的進程記錄,再將過濾後的結果傳遞給sort命令。
      #9. sort命令中的-b選項將忽略前置空格,並以user,再以進程名排序,將結果傳遞個uniq命令。
      #10.uniq命令將合并重複記錄,-c選項將會使每條記錄前加重複的行數。
      #11.第二個sort將再做一次排序,先以user,再以重複計數由大到小,最後以進程名排序。將結果傳給awk命令。
      #12.awk命令將資料進行格式化,並重複資料刪除的user。
      ps -eo user,comm | sed -e 1d | egrep "$userlist" |
          sort -b -k1,1 -k2,2 | uniq -c | sort -b -k2,2 -k1nr,1 -k3,3 |
              awk ' { user = (lastuser == $2) ? " " : $2;
                        lastuser = $2;
                        printf("%-15s\t%2d\t%s\n",user,$1,$3)
              }'
      CTRL+D
      /> ./test13.sh root avahi postfix rpc dbus
      avahi             2      avahi-daemon
      dbus             1      dbus-daemon
      postfix          1      pickup
                          1      qmgr
      root              5      mingetty
                          3      udevd
                          2      sort
                          2      sshd
      ... ...
      rpc               1      rpcbind

十四、用指令碼完成which命令的準系統:

      我們經常會在指令碼中調用其他的應用程式,為了保證指令碼具有更好的健壯性,以及錯誤提示的準確性,我們可能需要在執行前驗證該命令是否存在,或者說是否可以被執行。這首先要確認該命令是否位於PATH變數包含的目錄中,再有就是該檔案是否為可執行檔。
      /> cat > test14.sh
      #!/bin/sh
      #1. 該函數用於判斷參數1中的命令是否位於參數2所包含的目錄列表中。需要說明的是,函數裡面的$1和$2是指函數的參數,而不是指令碼的參數,後面也是如此。
      #2. cmd=$1和path=$2,將參數賦給有意義的變數名,是一個很好的習慣。
      #3. 由於PATH環境變數中,目錄之間的分隔字元是冒號,因此這裡需要臨時將IFS設定為冒號,函數結束後再還原。
      #4. 在for迴圈中,逐個變數目錄列表中的目錄,以判斷該命令是否存在,且為可執行程式。
      isInPath() {
          cmd=$1        path=$2      result=1
          oldIFS=$IFS   IFS=":"
          for dir in $path
          do
              if [ -x $dir/$cmd ]; then
                  result=0
              fi
          done
          IFS=oldifs
          return $result
      }
      #5. 檢查命令是否存在的主功能函數,先判斷是否為絕對路徑,即$var變數的第一個字元是否為/,如果是,再判斷它是否有可執行許可權。
      #6. 如果不是絕對路徑,通過isInPath函數判斷是否該命令在PATH環境變數指定的目錄中。
      checkCommand() {
          var=$1
          if [ ! -z "$var" ]; then
              if [ "${var:0:1}" = "/" ]; then
                  if [ ! -x $var ]; then
                      return 1
                  fi
              elif ! isInPath $var $PATH ; then
                  return 2
              fi
          fi
      }
      #7. 指令碼參數的合法性驗證。
      if [ $# -ne 1 ]; then
          echo "Usage: $0 command" >&2;
      fi
      #8. 根據傳回值列印不同的資訊。我們可以在這雷根據我們的需求完成不同的工作。
      checkCommand $1
      case $? in
      0) echo "$1 found in PATH." ;;
      1) echo "$1 not found or not executable." ;;
      2) echo "$1 not found in PATH." ;;
      esac
      exit 0
      CTRL+D
      /> ./test14.sh echo
      echo found in PATH.
      /> ./test14.sh MyTest
      MyTest not found in PATH.
      /> ./test14.sh /bin/MyTest
      /bin/MyTest not found or not executable.

十五、驗證輸入資訊是否合法:

      這裡給出的例子是驗證使用者輸入的資訊是否都是數字和字母。需要說明的是,之所以將其收集到該系列中,主要是因為它實現的方式比較巧妙。
      /> cat > test15.sh
      #!/bin/sh
      echo -n "Enter your input: "
      read input
      #1. 事實上,這裡的巧妙之處就是先用sed替換了非法部分,之後再將替換後的結果與原字串比較。這種寫法也比較容易擴充。    
      parsed_input=`echo $input | sed 's/[^[:alnum:]]//g'`
      if [ "$parsed_input" != "$input" ]; then
          echo "Your input must consist of only letters and numbers."
      else
          echo "Input is OK."
      fi
      CTRL+D
      /> ./test15.sh
      Enter your input: hello123
      Input is OK.
      /> ./test15.sh
      Enter your input: hello world
      Your input must consist of only letters and numbers.

十六、整數驗證:

      整數的重要特徵就是只是包含數字0到9和負號(-)。
      /> cat > test16.sh
      #!/bin/sh
      #1. 判斷變數number的第一個字元是否為負號(-),如果只是則刪除該負號,並將刪除後的結果賦值給left_number變數。
      #2. "${number#-}"的具體含義,可以參考該系列部落格中"Linux Shell常用技巧(十一)",搜尋索引鍵"變數模式比對運算子"即可。
      number=$1
      if [ "${number:0:1}" = "-" ]; then
          left_number="${number#-}"
      else
          left_number=$number
      fi
      #3. 將left_number變數中所有的數字都替換掉,因此如果返回的字串變數為空白,則表示left_number所包含的字元均為數字。
      nodigits=`echo $left_number | sed 's/[[:digit:]]//g'`
      if [ "$nodigits" != "" ]; then
          echo "Invalid number format!"
      else
          echo "You are valid number."
      fi
      CTRL+D
      /> ./test16.sh -123
      You are valid number.
      /> ./test16.sh 123e
      Invalid number format!
   
十七、判斷指定的年份是否為閏年:

      這裡我們先列出閏年的規則:
      1. 不能被4整除的年一定不是閏年;
      2. 可以同時整除4和400的年一定是閏年;
      3. 可以整除4和100,但是不能整除400的年,不是閏年;
      4. 其他可以整除的年都是閏年。
      #!/bin/sh   
      year=$1
      if [ "$((year % 4))" -ne 0 ]; then
          echo "This is not a leap year."
          exit 1
      elif [ "$((year % 400))" -eq 0 ]; then
          echo "This is a leap year."
          exit 0
      elif [ "$((year % 100))" -eq 0 ]; then
          echo "This is not a leap year."
          exit 1
      else
          echo "This is a leap year."
          exit 0
      fi
      CTRL+D
      /> ./test17.sh 1933
      This is not a leap year.
      /> ./test17.sh 1936
      This is a leap year.
           
十八、將單列顯示轉換為多列顯示:

      我們經常會在顯示時將單行的輸出,格式化為多行的輸出,通常情況下,為了完成該操作,我們將加入更多的代碼,將輸出的結果存入數組或臨時檔案,之後再重新遍曆它們,從而實現單行轉多行的目的。在這裡我們介紹一個使用xargs命令的技巧,可以用更簡單、更高效的方式來完成該功能。   
      /> cat > test18.sh

      #!/bin/sh
      #1. passwd檔案中,有可能在一行內出現一個或者多個空白字元,因此在直接使用cat命令的結果時,for迴圈會被空白字元切開,從而導致一行的文本被當做多次for迴圈的輸入,這樣我們不得不在sed命令中,將cat輸出的每行文本進行全域替換,將空白字元替換為%20。事實上,我們當然可以將cat /etc/passwd的輸出以管道的形式傳遞給cut命令,這裡之所以這樣寫,主要是為了示範一旦出現類似的問題該如果巧妙的處理。
      #2. 這裡將for迴圈的輸出以管道的形式傳遞給sort命令,sort命令將基於user排序。
      #3. -xargs -n 2是這個技巧的重點,它將sort的輸出進行合并,-n選項後面的數字參數將提示xargs命令將多少次輸出合并為一次輸出,並傳遞給其後面的命令。在本例中,xargs會將從sort得到的每兩行資料合併為一行,中間用空格符分離,之後再將合并後的資料傳遞給後面的awk命令。事實上,對於awk而言,你也可以簡單的認為xargs減少了對它(awk)的一半調用。
      #4. 如果打算在一行內顯示3行或更多的行,可以將-n後面的數字修改為3或其它更高的數字。你還可以修改awk中的print命令,使用更為複雜列印輸出命令,以得到更為可讀的輸出效果。
      for line in `cat /etc/passwd | sed 's/ /%20/g'`
      do
          user=`echo $line | cut -d: -f1`
          echo $user
      done | \
          sort -k1,1 | \
          xargs -n 2 | \
          awk '{print $1, $2}'
      CTRL+D
      /> ./test18.sh
      abrt adm
      apache avahi
      avahi-autoipd bin
      daemon daihw
      dbus ftp
      games gdm
      gopher haldaemon
      halt lp
      mail nobody
      ntp operator
      postfix pulse
      root rtkit
      saslauth shutdown
      sshd sync
      tcpdump usbmuxd
      uucp vcsa

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.