茫茫網海中的冷日
         
茫茫網海中的冷日
發生過的事,不可能遺忘,只是想不起來而已!
 恭喜您是本站第 1664698 位訪客!  登入  | 註冊
主選單

Google 自訂搜尋

Goole 廣告

隨機相片
IMG_00026.jpg

授權條款

使用者登入
使用者名稱:

密碼:


忘了密碼?

現在就註冊!

小企鵝開談 : [轉貼]Linux Shell 迴圈 while 的三個範例

發表者 討論內容
冷日
(冷日)
Webmaster
  • 註冊日: 2008/2/19
  • 來自:
  • 發表數: 15766
[轉貼]Linux Shell 迴圈 while 的三個範例
[Shell Script] Day11-迴圈 while 的三個範例
pajace2001

在介紹完 while 迴圈的三個樣子之後,緊接著當然是對這三個樣子作範例囉!這次的範例應該會有趣一些~
while] 迴圈能有什麼樣的應用呢?其實應用非常多,而且很常用到。

比如說,我想執行一個測試程式,我希望他跑個10小時,那該怎麼做?
當然就是用 while 啦!

比如說我想要編輯一份文件,在文件中若出現關鍵字,我就需要根據那關鍵字查詢對應表,在接著將查到的結果插入該文件關鍵字那行之下,也是可以用 while 來達成。

以下就根據昨天介紹的三個 while樣式來寫三個例子吧。

第一種:在條件成立時,就會不斷執行迴圈內容
#!/bin/bash

echo -n "請問你要幾個[妹]:"
read MA

INDEX=1
# 當條件成立,就會不斷執行(le表示小於或等於)
while [ $INDEX -le $MA ]
do
		# 輸出 妹
        echo -n "妹 "
		# INDEX 的值會加1
        (( INDEX++ ))
done
echo ""

echo "已經給你 $MA 個妹囉 了!"

執行結果:


第二種:無窮迴圈,直到外力介入才會停止
(在這次的範例中是以 Ctrl + C 來終止迴圈,下次的範例會用另一種方式來終止)
#!/bin/bash

echo "按下 Ctrl + C 中斷…"

LENGTH=0
while :
do
        echo -ne "\r["
        sleep 0.2
        while [ $LENGTH -le 10 ]
        do
                sleep 0.1
                echo -n ">"
                (( LENGTH++ ))
        done
        LENGTH=0
        echo -en "\r                          "
done

看看結果,在沒按下Ctrl+C 時,他是不會停的:

第三種:輸入一文字檔,在迴圈中一次只讀取一行:
首先我們先準備我們要輸入的文字檔:『story.txt』,內容是:

再來是我們的範例程式,我們會讀取每一行,接著在每一行前面加上行號:
#!/bin/bash

echo -n "請輸入要讀取的文字檔名稱:"
read FILE_NAME

INDEX=1
while read line
do
        echo "$INDEX: $line"
        (( INDEX++ ))
done <$FILE_NAME

執行結果:

有沒有覺得很簡單阿!!就是這麼簡單!! 讚

原文出處:[Shell Script] Day11-迴圈 while 的三個範例 - iT 邦幫忙::一起幫忙解決難題,拯救 IT 人的一天
冷日
(冷日)
Webmaster
  • 註冊日: 2008/2/19
  • 來自:
  • 發表數: 15766
[轉貼]Linux Shell 迴圈 (loop)
12.5 迴圈 (loop)

除了 if...then...fi 這種條件判斷式之外,迴圈可能是程式當中最重要的一環了~ 迴圈可以不斷的執行某個程式段落,直到使用者設定的條件達成為止。 所以,重點是那個『條件的達成』是什麼。除了這種依據判斷式達成與否的不定迴圈之外, 還有另外一種已經固定要跑多少次的迴圈形態,可稱為固定迴圈的形態呢!底下我們就來談一談:

12.5.1 while do done, until do done (不定迴圈)

一般來說,不定迴圈最常見的就是底下這兩種狀態了:
while [ condition ]  <==中括號內的狀態就是判斷式
do            <==do 是迴圈的開始!
	程式段落
done          <==done 是迴圈的結束

while 的中文是『當....時』,所以,這種方式說的是『當 condition 條件成立時,就進行迴圈,直到 condition 的條件不成立才停止』的意思。還有另外一種不定迴圈的方式:
until [ condition ]
do
	程式段落
done

這種方式恰恰與 while 相反,它說的是『當 condition 條件成立時,就終止迴圈, 否則就持續進行迴圈的程式段。』是否剛好相反啊~我們以 while 來做個簡單的練習好了。 假設我要讓使用者輸入 yes 或者是 YES 才結束程式的執行,否則就一直進行告知使用者輸入字串。
[dmtsai@study bin]$ vim yes_to_s.sh
#!/bin/bash
# Program:
#	Repeat question until user input correct answer.
# History:
# 2015/07/17	VBird	First release
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH

while [ "${yn}" != "yes" -a "${yn}" != "YES" ]
do
	read -p "Please input yes/YES to s this program: " yn
done
echo "OK! you input the correct answer."

上面這個例題的說明是『當 ${yn} 這個變數不是 "yes" 且 ${yn} 也不是 "YES" 時,才進行迴圈內的程式。』 而如果 ${yn} 是 "yes" 或 "YES" 時,就會離開迴圈囉~那如果使用 until 呢?呵呵有趣囉~ 他的條件會變成這樣:
[dmtsai@study bin]$ vim yes_to_s-2.sh
#!/bin/bash
# Program:
#	Repeat question until user input correct answer.
# History:
# 2015/07/17	VBird	First release
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH

until [ "${yn}" == "yes" -o "${yn}" == "YES" ]
do
	read -p "Please input yes/YES to s this program: " yn
done
echo "OK! you input the correct answer."

仔細比對一下這兩個東西有啥不同喔! ^_^再來,如果我想要計算 1+2+3+....+100 這個數據呢? 利用迴圈啊~他是這樣的:
[dmtsai@study bin]$ vim cal_1_100.sh
#!/bin/bash
# Program:
#	Use loop to calculate "1+2+3+...+100" result.
# History:
# 2015/07/17	VBird	First release
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH

s=0  # 這是加總的數值變數
i=0  # 這是累計的數值,亦即是 1, 2, 3....
while [ "${i}" != "100" ]
do
	i=$(($i+1))   # 每次 i 都會增加 1
	s=$(($s+$i))  # 每次都會加總一次!
done
echo "The result of '1+2+3+...+100' is ==> $s"

嘿嘿!當你執行了『 sh cal_1_100.sh 』之後,就可以得到 5050 這個數據才對啊!這樣瞭呼~ 那麼讓你自行做一下,如果想要讓使用者自行輸入一個數字,讓程式由 1+2+... 直到你輸入的數字為止, 該如何撰寫呢?應該很簡單吧?答案可以參考一下習題練習裡面的一題喔!



12.5.2 for...do...done (固定迴圈)

相對於 while, until 的迴圈方式是必須要『符合某個條件』的狀態, for 這種語法,則是『 已經知道要進行幾次迴圈』的狀態!他的語法是:
for var in con1 con2 con3 ...
do
	程式段
done

以上面的例子來說,這個 $var 的變數內容在迴圈工作時:

第一次迴圈時, $var 的內容為 con1 ;
第二次迴圈時, $var 的內容為 con2 ;
第三次迴圈時, $var 的內容為 con3 ;
....

我們可以做個簡單的練習。假設我有三種動物,分別是 dog, cat, elephant 三種, 我想每一行都輸出這樣:『There are dogs...』之類的字樣,則可以:
[dmtsai@study bin]$ vim show_animal.sh
#!/bin/bash
# Program:
# 	Using for .... loop to print 3 animals
# History:
# 2015/07/17	VBird	First release
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH

for animal in dog cat elephant
do
	echo "There are ${animal}s.... "
done

等你執行之後就能夠發現這個程式運作的情況啦!讓我們想像另外一種狀況,由於系統上面的各種帳號都是寫在 /etc/passwd 內的第一個欄位,你能不能透過管線命令的 cut 捉出單純的帳號名稱後,以 id 分別檢查使用者的識別碼與特殊參數呢?由於不同的 Linux 系統上面的帳號都不一樣!此時實際去捉 /etc/passwd 並使用迴圈處理,就是一個可行的方案了!程式可以如下:
[dmtsai@study bin]$ vim userid.sh
#!/bin/bash
# Program
#       Use id, finger command to check system account's information.
# History
# 2015/07/17    VBird   first release
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
users=$(cut -d ':' -f1 /etc/passwd)    # 擷取帳號名稱
for username in ${users}               # 開始迴圈進行!
do
        id ${username}
done

執行上面的腳本後,你的系統帳號就會被捉出來檢查啦!這個動作還可以用在每個帳號的刪除、重整上面呢! 換個角度來看,如果我現在需要一連串的數字來進行迴圈呢?舉例來說,我想要利用 ping 這個可以判斷網路狀態的指令, 來進行網路狀態的實際偵測時,我想要偵測的網域是本機所在的 192.168.1.1~192.168.1.100,由於有 100 台主機, 總不會要我在 for 後面輸入 1 到 100 吧?此時你可以這樣做喔!
[dmtsai@study bin]$ vim pingip.sh
#!/bin/bash
# Program
#       Use ping command to check the network's PC state.
# History
# 2015/07/17    VBird   first release
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
network="192.168.1"              # 先定義一個網域的前面部分!
for sitenu in $(seq 1 100)       # seq 為 sequence(連續) 的縮寫之意
do
	# 底下的程式在取得 ping 的回傳值是正確的還是失敗的!
        ping -c 1 -w 1 ${network}.${sitenu} &> /dev/null && result=0 || result=1
	# 開始顯示結果是正確的啟動 (UP) 還是錯誤的沒有連通 (DOWN)
        if [ "${result}" == 0 ]; then
                echo "Server ${network}.${sitenu} is UP."
        else
                echo "Server ${network}.${sitenu} is DOWN."
        fi
done

上面這一串指令執行之後就可以顯示出 192.168.1.1~192.168.1.100 共 100 部主機目前是否能與你的機器連通! 如果你的網域與鳥哥所在的位置不同,則直接修改上頭那個 network 的變數內容即可!其實這個範例的重點在 $(seq ..) 那個位置!那個 seq 是連續 (sequence) 的縮寫之意!代表後面接的兩個數值是一直連續的! 如此一來,就能夠輕鬆的將連續數字帶入程式中囉!

除了使用 $(seq 1 100) 之外,你也可以直接使用 bash 的內建機制來處理喔!可以使用 {1..100} 來取代 $(seq 1 100) ! 那個大括號內的前面/後面用兩個字元,中間以兩個小數點來代表連續出現的意思!例如要持續輸出 a, b, c...g 的話, 就可以使用『 echo {a..g} 』這樣的表示方式!

最後,讓我們來玩判斷式加上迴圈的功能!我想要讓使用者輸入某個目錄檔名, 然後我找出某目錄內的檔名的權限,該如何是好?呵呵!可以這樣做啦~
[dmtsai@study bin]$ vim dir_perm.sh
#!/bin/bash
# Program:
#	User input dir name, I find the permission of files.
# History:
# 2015/07/17	VBird	First release
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH

# 1. 先看看這個目錄是否存在啊?
read -p "Please input a directory: " dir
if [ "${dir}" == "" -o ! -d "${dir}" ]; then
	echo "The ${dir} is NOT exist in your system."
	exit 1
fi

# 2. 開始測試檔案囉~
filelist=$(ls ${dir})        # 列出所有在該目錄下的檔案名稱
for filename in ${filelist}
do
	perm=""
	test -r "${dir}/${filename}" && perm="${perm} readable"
	test -w "${dir}/${filename}" && perm="${perm} writable"
	test -x "${dir}/${filename}" && perm="${perm} executable"
	echo "The file ${dir}/${filename}'s permission is ${perm} "
done

呵呵!很有趣的例子吧~利用這種方式,你可以很輕易的來處理一些檔案的特性呢。接下來,讓我們來玩玩另一種 for 迴圈的功能吧!主要用在數值方面的處理喔!



12.5.3 for...do...done 的數值處理

除了上述的方法之外,for 迴圈還有另外一種寫法!語法如下:
for (( 初始值; 限制值; 執行步階 ))
do
	程式段
done

這種語法適合於數值方式的運算當中,在 for 後面的括號內的三串內容意義為:

初始值:某個變數在迴圈當中的起始值,直接以類似 i=1 設定好;
限制值:當變數的值在這個限制值的範圍內,就繼續進行迴圈。例如 i<=100;
執行步階:每作一次迴圈時,變數的變化量。例如 i=i+1。

值得注意的是,在『執行步階』的設定上,如果每次增加 1 ,則可以使用類似『i++』的方式,亦即是 i 每次迴圈都會增加一的意思。好,我們以這種方式來進行 1 累加到使用者輸入的迴圈吧!
[dmtsai@study bin]$ vim cal_1_100-2.sh
#!/bin/bash
# Program:
# 	Try do calculate 1+2+....+${your_input}
# History:
# 2015/07/17	VBird	First release
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH

read -p "Please input a number, I will count for 1+2+...+your_input: " nu

s=0
for (( i=1; i<=${nu}; i=i+1 ))
do
	s=$((${s}+${i}))
done
echo "The result of '1+2+3+...+${nu}' is ==> ${s}"

一樣也是很簡單吧!利用這個 for 則可以直接限制迴圈要進行幾次呢!



12.5.4 搭配亂數與陣列的實驗

現在你大概已經能夠掌握 shell script 了!好了!讓我們來做個小實驗!假設你們公司的團隊中,經常為了今天中午要吃啥搞到頭很昏! 每次都用猜拳的~好煩喔~有沒有辦法寫支腳本,用腳本搭配亂數來告訴我們,今天中午吃啥好?呵呵!執行這隻腳本後, 直接跟你說要吃啥~那比猜拳好多了吧?哈哈!

要達成這個任務,首先你得要將全部的店家輸入到一組陣列當中,再透過亂數的處理,去取得可能的數值,再將搭配到該數值的店家秀出來即可! 其實也很簡單!讓我們來實驗看看:
[dmtsai@study bin]$ vim what_to_eat.sh
#!/bin/bash
# Program:
# 	Try do tell you what you may eat.
# History:
# 2015/07/17	VBird	First release
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH

eat[1]="賣噹噹漢堡"       # 寫下你所收集到的店家!
eat[2]="肯爺爺炸雞"
eat[3]="彩虹日式便當"
eat[4]="越油越好吃大雅"
eat[5]="想不出吃啥學餐"
eat[6]="太師父便當"
eat[7]="池上便當"
eat[8]="懷念火車便當"
eat[9]="一起吃泡麵"
eatnum=9                  # 需要輸入有幾個可用的餐廳數!

check=$(( ${RANDOM} * ${eatnum} / 32767 + 1 ))
echo "your may eat ${eat[${check}]}"

立刻執行看看,你就知道該吃啥了!非常有趣吧!不過,這個例子中只選擇一個樣本,不夠看!如果想要每次都秀出 3 個店家呢? 而且這個店家不能重複喔!重複當然就沒啥意義了!所以,你可以這樣作!
[dmtsai@study bin]$ vim what_to_eat-2.sh
#!/bin/bash
# Program:
# 	Try do tell you what you may eat.
# History:
# 2015/07/17	VBird	First release
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH

eat[1]="賣噹噹漢堡"
eat[2]="肯爺爺炸雞"
eat[3]="彩虹日式便當"
eat[4]="越油越好吃大雅"
eat[5]="想不出吃啥學餐"
eat[6]="太師父便當"
eat[7]="池上便當"
eat[8]="懷念火車便當"
eat[9]="一起吃泡麵"
eatnum=9

eated=0
while [ "${eated}" -lt 3 ]; do
        check=$(( ${RANDOM} * ${eatnum} / 32767 + 1 ))
        mycheck=0
        if [ "${eated}" -ge 1 ]; then
                for i in $(seq 1 ${eated} )
                do
                        if [ ${eatedcon[$i]} == $check ]; then
                                mycheck=1
                        fi
                done
        fi
        if [ ${mycheck} == 0 ]; then
                echo "your may eat ${eat[${check}]}"
                eated=$(( ${eated} + 1 ))
                eatedcon[${eated}]=${check}
        fi
done

透過亂數、陣列、迴圈與條件判斷,你可以做出很多很特別的東西!還不用寫傳統程式語言~試看看~挺有趣的呦!

原文出處:鳥哥的 Linux 私房菜 -- 第十二章、學習 Shell Scripts
前一個主題 | 下一個主題 | 頁首 | | |



Powered by XOOPS 2.0 © 2001-2008 The XOOPS Project|