免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: 網中人

[学习共享] shell 十三問? [复制链接]

论坛徽章:
0
发表于 2004-01-23 15:12 |显示全部楼层

shell 十三問?

看来台湾人的解释更加简洁,易懂

论坛徽章:
1
荣誉版主
日期:2011-11-23 16:44:17
发表于 2004-01-30 12:57 |显示全部楼层

shell 十三問?

一口气又从头到尾看了一边,深有感触!
强烈推荐喜欢shell的朋友多多研读,仔细品味!

论坛徽章:
1
荣誉版主
日期:2011-11-23 16:44:17
发表于 2004-01-31 17:20 |显示全部楼层

shell 十三問?

12) 你要 if 還是 case 呢?

放了一個愉快的春節假期,人也變得懶懶散散的... 只是,答應了大家的作業,還是要堅持完成就是了~~~

還記得我們在第 10 章所介紹的 return value 嗎?
是的,接下來介紹的內容與之有關,若你的記憶也被假期的歡樂時光所抵消掉的話,
那,建議您還是先回去溫習溫習再回來...

若你記得  return value ,我想你也應該記得了 && 與 || 是甚麼意思吧?
用這兩個符號再配搭 command group 的話,我們可讓 shell script 變得更加聰明哦。
比方說:
  1. comd1 && {
  2.     comd2
  3.     comd3
  4.     :
  5. } || {
  6.     comd4
  7.     comd5
  8. }
复制代码

意思是說:
    假如 comd1 的 return value 為 true 的話,
    然則執行 comd2 與 comd3 ,
    否則執行 comd4 與 comd5 。


事實上,我們在寫 shell script 的時候,經常需要用到這樣那樣的條件以作出不同的處理動作。
用 && 與 || 的確可以達成條件執行的效果,然而,從"人類語言"上來理解,卻不是那麼直觀。
更多時候,我們還是喜歡用 if .... then ... else ... 這樣的 keyword 來表達條件執行。
在 bash shell 中,我們可以如此修改上一段代碼:
  1. if comd1
  2. then
  3.     comd2
  4.     comd3
  5. else
  6.     comd4
  7.     comd5
  8. fi
复制代码

這也是我們在 shell script 中最常用到的 if 判斷式:
    只要 if 後面的 command line 返回 true 的 return value (我們最常用 test 命令來送出 return value),
    然則就執行 then 後面的命令,否則執行  else 後的命令﹔fi 則是用來結束判斷式的 keyword 。


在 if 判斷式中,else 部份可以不用,但 then 是必需的。
(若 then 後不想跑任何 command ,可用" : " 這個 null command 代替)。
當然,then 或 else 後面,也可以再使用更進一層的條件判斷式,這在 shell script 設計上很常見。
若有多項條件需要"依序"進行判斷的話,那我們則可使用 elif 這樣的 keyword :
  1. if comd1; then
  2.     comd2
  3. elif comd3; then
  4.     comd4
  5. else
  6.     comd5
  7. fi
复制代码

意思是說:
    若 comd1 為 true ,然則執行 comd2 ﹔
    否則再測試 comd3 ,然則執行 comd4 ﹔
    倘若 comd1 與 comd3 均不成立,那就執行 comd5 。


if 判斷式的例子很常見,你可從很多 shell script 中看得到,我這裡就不再舉例子了...

接下來要為大家介紹的是 case 判斷式。
雖然 if 判斷式已可應付大部份的條件執行了,然而,在某些場合中,卻不夠靈活,
尤其是在 string 式樣的判斷上,比方如下:
  1. QQ () {
  2.     echo -n "Do you want to continue? (Yes/No): "
  3.     read YN
  4.     if [ "$YN" = Y -o "$YN" = y -o "$YN" = "Yes" -o "$YN" = "yes" -o "$YN" = "YES" ]
  5.     then
  6.         QQ
  7.     else
  8.         exit 0
  9.     fi
  10. }
  11. QQ
复制代码

從例中,我們看得出來,最麻煩的部份是在於判斷 YN 的值可能有好幾種式樣。
聰明的你或許會如此修改:
  1. ...
  2. if echo "$YN" | grep -q '^[Yy]\([Ee][Ss]\)*$'
  3. ...
复制代码

也就是用 Regular Expression 來簡化代碼。(我們有機會再來介紹 RE)
只是... 是否有其它更方便的方法呢?
有的,就是用 case 判斷式即可:
  1. QQ () {
  2.     echo -n "Do you want to continue? (Yes/No): "
  3.     read YN
  4.    case "$YN" in
  5.         [Yy]|[Yy][Ee][Ss])
  6.             QQ
  7.             ;;
  8.         *)
  9.             exit 0
  10.             ;;
  11.     esac
  12. }
  13. QQ
复制代码

我們常用 case 的判斷式來判斷某一變量在不同的值(通常是 string)時作出不同的處理,
比方說,判斷 script 參數以執行不同的命令。
若你有興趣、且用 Linux 系統的話,不妨挖一挖 /etc/init.d/* 裡那堆 script 中的  case 用法。
如下就是一例:
  1. case "$1" in
  2.   start)
  3.         start
  4.         ;;
  5.   stop)
  6.         stop
  7.         ;;
  8.   status)
  9.         rhstatus
  10.         ;;
  11.   restart|reload)
  12.         restart
  13.         ;;
  14.   condrestart)
  15.         [ -f /var/lock/subsys/syslog ] && restart || :
  16.         ;;
  17.   *)
  18.         echo $"Usage: $0 {start|stop|status|restart|condrestart}"
  19.         exit 1
  20. esac
复制代码

(若你對 positional parameter 的印像已經模糊了,請重看第 9 章吧。)

okay,十三問還剩一問而已,過幾天再來搞定之....  ^_^

[ 本帖最后由 網中人 于 2008-10-30 02:25 编辑 ]

论坛徽章:
0
发表于 2004-02-01 15:10 |显示全部楼层

shell 十三問?

讲的很透彻,support!

论坛徽章:
0
发表于 2004-02-02 14:59 |显示全部楼层

shell 十三問?

向他们学习

论坛徽章:
1
荣誉版主
日期:2011-11-23 16:44:17
发表于 2004-02-03 17:27 |显示全部楼层

shell 十三問?

13) for what?  while 與 until 差在哪?

終於,來到 shell 十三問的最後一問了...  長長吐一口氣~~~~

最後要介紹的是 shell script 設計中常見的"循環"(loop)。
所謂的 loop 就是 script 中的一段在一定條件下反覆執行的代碼。
bash shell  中常用的 loop 有如下三種:
* for
* while
* until

for loop 是從一個清單列表中讀進變量值,並"依次"的循環執行 do 到 done 之間的命令行。
例:
  1. for var in one two three four five
  2. do
  3.     echo -----------
  4.     echo '$var is '$var
  5.     echo
  6. 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 loop 中,變量值的多寡,決定循環的次數。
然而,變量在循環中是否使用則不一定,得視設計需求而定。
倘若 for loop 沒有使用 in 這個 keyword 來指定變量值清單的話,其值將從 $@ (或 $* )中繼承:
  1. for var; do
  2.     ....
  3. done
复制代码

(若你忘記了 positional parameter ,請溫習第 9 章...)

for loop 用於處理"清單"(list)項目非常方便,
其清單除了可明確指定或從 positional parameter 取得之外,
也可從變量替換或命令替換取得... (再一次提醒:別忘了命令行的"重組"特性﹗)
然而,對於一些"累計變化"的項目(如整數加減),for 亦能處理:
  1. for ((i=1;i<=10;i++))
  2. do
  3.    echo "num is $i"
  4. done
复制代码


除了 for loop ,上面的例子我們也可改用  while loop 來做到:
  1. num=1
  2. while [ "$num" -le 10 ]; do
  3.     echo "num is $num"
  4.     num=$(($num + 1))
  5. 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 的話,那循環將一直永久執行下去:
  1. while :; do
  2.     echo looping...
  3. done
复制代码

上例的" : "是 bash 的 null command ,不做任何動作,除了送回 true 的 return value 。
因此這個循環不會結束,稱作死循環。
死循環的產生有可能是故意設計的(如跑 daemon),也可能是設計錯誤。
若要結束死尋環,可透過 signal 來終止(如按下 ctrl-c )。
(關於 process 與 signal ,等日後有機會再補充,十三問暫時略過。)

一旦你能夠理解 while loop 的話,那,就能理解 until loop :
* 與 while 相反,until 是在 return value 為 false 時進入循環,否則結束。
因此,前面的例子我們也可以輕鬆的用  until 來寫:
  1. num=1
  2. until [ ! "$num" -le 10 ]; do
  3.     echo "num is $num"
  4.     num=$(($num + 1))
  5. done
复制代码

或是:
  1. num=1
  2. until [ "$num" -gt 10 ]; do
  3.     echo "num is $num"
  4.     num=$(($num + 1))
  5. done
复制代码


okay ,關於 bash 的三個常用的 loop 暫時介紹到這裡。
在結束本章之前,再跟大家補充兩個與 loop 有關的命令:
*  break
* continue
這兩個命令常用在複合式循環裡,也就是在 do ... done 之間又有更進一層的 loop ,
當然,用在單一循環中也未嘗不可啦...  ^_^

break 是用來打斷循環,也就是"強迫結束" 循環。
若 break 後面指定一個數值 n 的話,則"從裡向外"打斷第 n 個循環,
預設值為 break 1 ,也就是打斷當前的循環。
在使用 break 時需要注意的是, 它與 return 及 exit 是不同的:
* break 是結束 loop
* return 是結束 function
* exit 是結束 script/shell

而 continue 則與 break 相反:強迫進入下一次循環動作。
若你理解不來的話,那你可簡單的看成:在 continue 到 done 之間的句子略過而返回循環頂端...
與 break 相同的是:continue 後面也可指定一個數值 n ,以決定繼續哪一層(從裡向外計算)的循環,
預設值為 continue 1 ,也就是繼續當前的循環。

在 shell script 設計中,若能善用 loop ,將能大幅度提高 script 在複雜條件下的處理能力。
請多加練習吧....


-----------

好了,該是到了結束的時候了。
婆婆媽媽的跟大家囉唆了一堆關於 shell 的基礎概念,
目的不是要告訴大家"答案",而是要帶給大家"啟發"...
在日後關於 shell 的討論中,我或許會經常用"鏈接"方式指引回來十三問中的內容,
以便我們在進行技術探討時彼此能有一些討論基礎,而不至於各說各話、徒費時力。
但,更希望十三問能帶給你更多的思考與樂趣,至為重要的是透過實作來加深理解。

是的,我很重視"實作"與"獨立思考"這兩項學習要素,若你能夠掌握其中真義,那請容我說聲:
--- 恭喜﹗十三問你沒白看了﹗  ^_^


p.s.
至於補充問題部份,我暫時不寫了。而是希望:
1) 大家擴充題目。
2) 一起來寫心得。

Good luck and happy studying!

[ 本帖最后由 網中人 于 2008-10-30 02:26 编辑 ]

论坛徽章:
0
发表于 2004-02-05 14:54 |显示全部楼层

shell 十三問?

good article & thx a lot

论坛徽章:
0
发表于 2004-02-05 22:38 |显示全部楼层

shell 十三問?

真是太好了,十分精辟。只是我有一问。
for ((i=1;i<=10;i++))
do
   echo "num is $i"
done
这个例子好像不行啊。我用bash和sh执行都不行。
用bash的错误提示是:
mfor: line 1: syntax error near unexpected token `(('
mfor: line 1: `for ((i=1;i<=10;i++)) '
用sh的错误提示是:
mfor: syntax error at line 1: `(' unexpected
还请指点一下。

论坛徽章:
1
荣誉版主
日期:2011-11-23 16:44:17
发表于 2004-02-06 00:01 |显示全部楼层

shell 十三問?

請問你是用 bash 嗎?
若你寫成 script 的話,確定第一行有定義 interpreter :
#!/bin/bash

论坛徽章:
0
发表于 2004-02-06 12:24 |显示全部楼层

shell 十三問?

原帖由 "網中人" 发表:
請問你是用 bash 嗎?
若你寫成 script 的話,確定第一行有定義 interpreter :
#!/bin/bash

谢谢,已经解决了,原来是掉了一个!号。 不好意思。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

SACC2019中国系统架构师大会

【数字转型 架构演进】SACC2019中国系统架构师大会,8.5折限时优惠重磅来袭!
2019年10月31日~11月2日第11届中国系统架构师大会(SACC2019)将在北京隆重召开。四大主线并行的演讲模式,1个主会场、20个技术专场、超千人参与的会议规模,100+来自互联网、金融、制造业、电商等领域的嘉宾阵容,将为广大参会者提供一场最具价值的技术交流盛会。

限时8.5折扣期:2019年9月30日前


----------------------------------------

大会官网>>
  

北京盛拓优讯信息技术有限公司. 版权所有 16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122
中国互联网协会会员  联系我们:huangweiwei@it168.com
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP