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.