細讀shell-4

 17.   /dev/null

$ ls my.file no.such.file 2>/dev/null 

my.file

若要相反:只想看到 stderr 呢?還不簡單﹗將 stdout 弄到 null 就行:

$ ls my.file no.such.file >/dev/null 

ls: no.such.file: No such file or directory 

除了用 >/dev/null 2>&1 之外,你還可以如此:  

$ ls my.file no.such.file &>/dev/null 

(提示:將 &> 換成 >& 也行啦~~! ) 

再問:那... 有辦法不取消而又"臨時"蓋寫目標檔案嗎? 

$ set -o noclobber 

$ echo "6" >| file.out 

$ cat file.out 

留意到沒有:在 > 後面再加個" | "就好(注意: > | 之間不能有空白哦).... 

再來還有一個難題要你去參透的呢:  

$ echo "some text here" > file 

$ cat < file 

some text here 

$ cat < file > file.bak 

$ cat < file.bak 

some text here 

$ cat < file > file 

$ cat < file

---- 怎麼最後那個 cat 命令看到的 file 竟是空的?﹗ 

$ cat < file > file 之後原本有內容的檔案結果卻被洗掉了﹗ 

這只是 priority 的問題而已

* IO Redirection 中,stdout stderr 的管道會先準備好,纔會從 stdin 讀進資料。

 file 會先將 file 清空,然後纔讀進 < file  

但這時候檔案已經被清空了,因此就變成讀不進任何資料了... 

pipe line 之間,前一個命令的 stderr 是不會接進下一命令的 stdin 的, 

其輸出,若不用 2> 導到 file 去的話,它還是送到監視器上面來﹗ 

這點請你在 pipe line 運用上務必要注意的。 

* cm1 | cm2 | cm3 ... 這段 pipe line 中,若要將 cm2 的結果存到某一檔案呢?

若你寫成 cm1 | cm2 > file | cm3 的話, 

那你肯定會發現 cm3 stdin 是空的﹗(當然啦,你都將水管接到別的水池了﹗

cm1 | cm2 > file ; cm3 < file 

cm1 | cm2 > file ; cm3 < file 

有的,那就是 tee 命令了。

* 所謂 tee 命令是在不影響原本 I/O 的情況下,將 stdout 複製一份到檔案去。 

因此,上面的命令行可以如此打:  

cm1 | cm2 | tee file | cm3 

18.     你要 if 還是 case 呢?  

       comd1 && { 

    comd2 

    comd3 

} || { 

    comd4 

    comd5 

}

若你記得 return value ,我想你也應該記得了 && || 是甚麼意思吧? 

用這兩個符號再配搭 command group 的話,我們可讓 shell script 變得更加聰明哦。 

假如 comd1 return value true 的話, 

然則執行 comd3 comd4  

否則執行 comd4 comd5

改成if   then        else

if comd1 

then 

    comd2 

    comd3 

else 

    comd4 

    comd5 

fi

可使用 elif 這樣的 keyword

if comd1; then 

    comd2 

elif comd3; then 

    comd4 

else 

    comd5 

fi

comd1 true ,然則執行 comd2  

否則再測試 comd3 ,然則執行 comd4  

倘若 comd1 comd3 均不成立,那就執行 comd5

雖然 if 判斷式已可應付大部份的條件執行了,然而,在某些場合中,卻不夠靈活, 

尤其是在 string 式樣的判斷上,比方如下:  

QQ () { 

    echo -n "Do you want to continue? (Yes/No): " 

    read YN 

    if [ "$YN" = Y -o "$YN" = y -o "$YN" = "Yes" -o "$YN" = "yes" -o "$YN" = "YES" ]

    then 

        QQ 

    else 

        exit 0 

    fi 

QQ

從例中,我們看得出來,最麻煩的部份是在於判斷 YN 的值可能有好幾種式樣。 

.. 

if echo "$YN" | grep -q '^[Yy]\([Ee][Ss]\)*$' 

 

 

QQ () { 

    echo -n "Do you want to continue? (Yes/No): " 

    read YN 

   case "$YN" in 

        [Yy]|[Yy][Ee][Ss]) 

            QQ 

            ;; 

        *) 

 

            exit 0 

            ;; 

    esac 

QQ

我們常 case 的判斷式來判斷某一變量在同的值(通常是 string)時作出不同的處理, 

比方說,判斷 script 參數以執行不同的命令。 

若你有興趣、且用 Linux 系統的話,不妨挖一挖 /etc/init.d/* 裏那堆 script 中的 case

法。 

case "$1" in 

  start) 

        start 

        ;; 

  stop) 

        stop 

        ;; 

  status) 

        rhstatus 

        ;; 

  restart|reload) 

        restart 

        ;; 

  condrestart) 

        [ -f /var/lock/subsys/syslog ] && restart || : 

        ;; 

  *) 

        echo $"Usage: $0 {start|stop|status|restart|condrestart}" 

        exit 1 

esac

18.最後要介紹的是 shell script 設計中常見的"循環"(loop)

bash shell 中常用的 loop 有如下三

* for 

* while 

* until 

for loop 是從一個清單列表中讀進變量值,並"依次"的循環執行 do done 之間的命令行。  

for var in one two three four five 

do 

    echo ----------- 

    echo '$var is '$var  

    echo 

done

上例的執行結果將會是:  

1) for 會定義一個叫 var 的變量,其值依次是 one two three four five  

2) 因爲有 5 個變量值,因此 do done 之間的命令行會被循環執行 5 次。 

3) 每次循環均用 echo 產生三行句子。 

而第二行中不在 hard quote 之內的 $var 會依次被替換爲 one two three four

five  

4) 當最後一個變量值處理完畢,循環結束。

for ((i=1;i<=10;i++)) 

do 

   echo "num is $i" 

done

除了 for loop ,上面的例子我們也可改用 while loop 來做到:

num=1 

while [ "$num" -le 10 ]; do 

    echo "num is $num" 

    num=$(($num + 1)) 

done

while loop 的原理與 for loop 稍有不同: 

它不是逐次處理清單中的變量值,而是取決於 while 後面的命令行之 return value  

* 若爲 ture ,則執行 do done 之間的命令,然後重新判斷 while 後的 return value   

* 若爲 false ,則不再執行 do done 之間的命令而結束循環。 

 

分析上例:  

1) while 之前,定義變量 num=1  

2) 然後測試(test) $num 是否小於或等於 10  

3) 結果爲 true ,於是執行 echo 並將 num 的值加一。 

4) 再作第二輪測試,其時 num 的值爲 1+1=2 ,依然小於或等於 10,因此爲

true ,繼續循環。 

5) 直到 num 10+1=11 時,測試纔會失敗... 於是結束循環。

 * while 的測試結果永遠爲 true 的話,那循環將一直永久執行下去:  

* while 相反,until 是在 return value false 時進入循環,否則結束。

因此,前面的例子我們也可以輕鬆的用 until 來寫:

num=1 

until [ ! "$num" -le 10 ]; do 

    echo "num is $num

    num=$(($num + 1)) 

done

或是:  

代碼:

num=1 

until [ "$num" -gt 10 ]; do 

    echo "num is $num" 

    num=$(($num + 1)) 

done 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章