shell高級技巧-在循環中使用管道的技巧

在Bash Shell中,管道的最後一個命令都是在子Shell中執行的。這意味着在子Shell中賦值的變量對父Shell是無效的。所以當我們將管道輸出傳送到一個循環結構,填入隨後將要使用的變量,那麼就會產生很多問題。一旦循環完成,其所依賴的變量就不存在了。
      [root@xieqichao ~]# cat > test8_1.sh
      #!/bin/sh
      #1. 先將ls -l命令的結果通過管道傳給grep命令作爲管道輸入。
      #2. grep命令過濾掉包含total的行,之後再通過管道將數據傳給while循環。
      #3. while read line命令從grep的輸出中讀取數據。注意,while是管道的最後一個命令,將在子Shell中運行。
      ls -l | grep -v total | while read line
      do
          #4. all變量是在while塊內聲明並賦值的。
          all="$all $line"
          echo $line
      done
      #5. 由於上面的all變量在while內聲明並初始化,而while內的命令都是在子Shell中運行,包括all變量的賦值,因此該變量的值將不會傳遞到while塊外,因爲塊外地命令是它的父Shell中執行。
      echo "all = " $all
      CTRL+D
      [root@xieqichao ~]# ./test8_1.sh
      -rw-r--r--.  1 root root 193 Nov 24 11:25 outfile
      -rwxr-xr-x. 1 root root 284 Nov 24 10:01 test7.sh
      -rwxr-xr-x. 1 root root 108 Nov 24 12:48 test8_1.sh
      all =

      爲了解決該問題,我們可以將while之前的命令結果先輸出到一個臨時文件,之後再將該臨時文件作爲while的重定向輸入,這樣while內部和外部的命令都將在同一個Shell內完成。
      [root@xieqichao ~]# cat > test8_2.sh
      #!/bin/sh
      #1. 這裏我們已經將命令的結果重定向到一個臨時文件中。
      ls -l | grep -v total > outfile
      while read line
      do
          #2. all變量是在while塊內聲明並賦值的。
          all="$all $line"
          echo $line
          #3. 通過重定向輸入的方式,將臨時文件中的內容傳遞給while循環。
      done < outfile
      #4. 刪除該臨時文件。
      rm -f outfile
      #5. 在while塊內聲明和賦值的all變量,其值在循環外部仍然有效。
      echo "all = " $all
      CTRL+D
      [root@xieqichao ~]# ./test8_2.sh
      -rw-r--r--.  1 root root   0 Nov 24 12:58 outfile
      -rwxr-xr-x. 1 root root 284 Nov 24 10:01 test7.sh
      -rwxr-xr-x. 1 root root 140 Nov 24 12:58 test8_2.sh
      all =  -rwxr-xr-x. 1 root root 284 Nov 24 10:01 test7.sh -rwxr-xr-x. 1 root root 135 Nov 24 13:16 test8_2.sh

      上面的方法只是解決了該問題,然而卻帶來了一些新問題,比如臨時文件的產生容易導致性能問題,以及在腳本異常退出時未能及時刪除當前使用的臨時文件,從而導致生成過多的垃圾文件等。下面將再介紹一種方法,該方法將同時解決以上兩種方法同時存在的問題。該方法是通過HERE-Document的方式來替代之前的臨時文件方法。
      [root@xieqichao ~]# cat > test8_3.sh
      #!/bin/sh
      #1. 將命令的結果傳給一個變量    
      OUTFILE=`ls -l | grep -v total`
      while read line
      do
          all="$all $line"
          echo $line
      done <<EOF
      #2. 將該變量作爲該循環的HERE文檔輸入。
      $OUTFILE
      EOF
      #3. 在循環外部輸出循環內聲明並初始化的變量all的值。
      echo "all = " $all
      CTRL+D
      [root@xieqichao ~]# ./test8_3.sh
      -rwxr-xr-x. 1 root root 284 Nov 24 10:01 test7.sh
      -rwxr-xr-x. 1 root root 135 Nov 24 13:16 test8_3.sh
      all =  -rwxr-xr-x. 1 root root 284 Nov 24 10:01 test7.sh -rwxr-xr-x. 1 root root 135 Nov 24 13:16 test8_3.sh
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章