Looping Statements ใช้บังคับให้ Program Execute Statement ซ้ำๆ Executed Statement เรียกว่า Loop Body
Loops Execute จนกว่า Controlling Expression จะเป็น 0 Controlling Expression อาจเป็น Scalar Data Type ใดๆ
Shell Language ก็มี Iteration/Looping Statements หลายแบบ ในบทความนี้ มาทบทวน Looping Statements ที่ Bash ให้มา พร้อมตัวอย่าง
Bash รองรับ Looping Statements 3 ประเภท:
- For Loop
- While Loop
- Until Loop
บทความนี้เป็นส่วนหนึ่งของชุด Bash Tutorial Series ต่อเนื่อง
Loops สามารถ Nested ได้ เหมือนภาษาโปรแกรมอื่น Bash ก็มี Break Statement ออกจาก Loop ปัจจุบัน และ Continue Statement Resume Iteration ถัดไปของ Loop Statement
Bash For Loop – วิธีแรก
For Loops ใช้เมื่อจำนวน Iterations รู้จักก่อนเข้ Loop Bash รองรับ For Loop 2 แบบ รูปแบบแรกของ Bash For Loop:
for varname in list do commands ## Body of the loop done
ใน Syntax ข้างต้น:
- for, in, do และ done เป็น Keywords
- List คือ List ใดๆ ที่มี List of Items
- varname คือ Bash Variable Name ใดๆ
ในรูปแบบนี้ For Statement Execute Commands ใน Body หนึ่งครั้งต่อ Item ใน List Item ปัจจุบันจาก List จะเก็บใน Variable "varname" ทุกครั้งผ่าน Loop varname นี้สามารถ Process ใน Body ของ Loopได้ List นี้อาจเป็น Variable ที่มีหลาย Words คั่นด้วย Spaces ถ้า List หายไปใน For Statement จะใช้ Positional Parameters ที่ส่งเข้า Shell
Bash For Loop Example 1. Unzip ไฟล์ Zip ทั้งหมด
ตัวอย่างต่อไปนี้หา List of Files ที่ Match "*.zip*" ใน Root Directory สร้าง Directory ใหม่ที่ Location เดียวกับ Zip File และ Unzip เนื้อหา
# cat zip_unzip.sh
#! /bin/bash
# Find files which has .zip
for file in `find /root -name "*.zip*" -type f`
do
# Skip the extension .zip
dirname=`echo ${file} | awk -F'.' '{print $1}'`
# Create the directory
mkdir $dirname
# Copy the zip file
cp ${file} ${dirname}
cd $dirname
# Unzip the zip file from newly created directory
unzip ${dirname}/$(echo ${file##/*/})
done
- ในตัวอย่าง Find Command คืนค่า List of Files แต่ละ File จะ Process ผ่าน Loop
- ต่อ Item สร้าง Directory ชื่อ Zip File Copy Zip File ไป Directory ใหม่ และ Unzip จากที่นั่น
- Echo Statement
echo ${file##/*/}ให้แค่ File Name ไม่ใช่ Path
# ./zip_unzip.sh Archive: /root/test2/test2.zip extracting: t1/p extracting: t1/q extracting: t1/r extracting: t1/s extracting: t1/t extracting: t1/u extracting: t1/v Archive: /root/test1/test1.zip extracting: t/a extracting: t/b extracting: t/c extracting: t/d extracting: t/e
คล้าย Bash Loop, Awk ก็มี For Loop และ While Loop ตามที่พูดใน Awk While and For Loop Article
Bash For Loop – วิธีที่สอง
รูปแบบที่สองของ For Loop คล้าย For Loop ใน 'C' Programming Language ซึ่งมี 3 Expressions (Initialization, Condition และ Updation)
for (( expr1; expr2; expr3 )) do commands done
- ใน Syntax Bash For Command ข้างต้น ก่อน Iteration แรก expr1 จะ Evaluated ใช้ Initialize Variables สำหรับ Loop ปกติ
- Statements ระหว่าง do และ done Execute ซ้ำจนกว่า expr2 จะเป็น TRUE
- หลัง Iteration แต่ละรอบ expr3 จะ Evaluated ใช้ Increment Loop Counter ปกติ
ตัวอย่างต่อไปนี้ Generate N Random Numbers
Bash For Example 2. Generate N Random Numbers
$ cat random.sh #! /bin/bash echo -e "How many random numbers you want to generate" read max for (( start = 1; start <= $max; start++ )) do echo -e $RANDOM done $ ./random.sh How many random numbers you want to generate 5 6119 27200 1998 12097 9181
ใน Code Snippet ข้างต้น For Loop Generate Random Number Max ครั้ง RANDOM เป็น Internal Bash Function คืนค่า Random Integer ทุกครั้งที่ Invoke
Bash While Loop
Iteration Statement อีกแบบจาก Shell Programming Language คือ While Statement
Syntax: while expression do commands done
ใน While Loop Syntax ข้างต้น:
- while, do, done เป็น Keywords
- Expression คือ Expression ใดๆ ที่คืนค่า Scalar Value
- While Statement ทำให้ Block of Code Execute ขณะที่ Conditional Expression เป็น True
Bash While Example 3. เขียนเนื้อหาลง File
ตัวอย่างต่อไปนี้อ่าน Data จาก Stdout และเขียนลง File
$ cat writefile.sh #! /bin/bash echo -e "Enter absolute path of the file name you want to create" read file while read line do echo $line >> $file done $ sh writefile.sh Enter absolute path of the file name you want to create /tmp/a while for until $ cat /tmp/a while for until
ตัวอย่างข้างต้นอ่าน Filename จาก User และอ่านบรรทัดจาก Stdin Append แต่ละบรรทัดไป Filename ที่กำหนด เมื่อ EOF Enter Read จะ Fail ดังนั้น Loop จบที่นั่น
ถ้าเขียน Bash Scripts เยอะ สามารถใช้ Vim Editor เป็น Bash IDE ด้วย Vim bash-support Plugin ตามที่พูดไปก่อนหน้า
Bash While Example 4. อ่านเนื้อหา File
ในตัวอย่างก่อนหน้า อ่าน Data จาก Stdout เขียนลง File ตัวอย่างนี้อ่าน File Content และเขียนลง Stdout
$ cat read.sh #! /bin/bash echo -e "Enter absolute path of the file name you want to read" read file exec <$file # Redirects stdin to a file while read line do echo $line done $ ./read.sh Enter absolute path of the file name you want to read /tmp/a while for until
ในตัวอย่างนี้ ได้ Filename มาอ่าน และด้วย Exec Redirect Stdin ไป File ตั้งแต่จุดนั้น Stdin ทั้งหมดมาจาก File แทน Keyboard Read Command อ่านบรรทัดจาก Stdin ดังนั้น While Loop อ่าน Stdin จนกว่า EOF
Bash Until Loop
Until Statement คล้าย While Statement มากทั้ง Syntax และ Function ความต่างจริงคือ Until Execute Code Block ขณะที่ Conditional Expression เป็น False ในขณะที่ While Execute ขณะที่เป็น True
syntax: until expression do commands # body of the loop done
ใน Bash Until Syntax ข้างต้น: where until, do, done เป็น Keywords Expression ใดๆ ที่เป็น Conditional Expression
Bash Until Example 5. Monitor Logfile
ตัวอย่างนี้ Monitor ขนาด Logfile เมื่อ Logfile Size ถึง 2000 Bytes จะ Copy Logfile นั้น
$ cat monitor.sh
file=/tmp/logfile
until [ $(ls -l $file | awk '{print $5}') -gt 2000 ]
do
echo "Sleeping for next 5 seconds"
sleep 5
done
date=`date +%s`
cp $file "$file-"$date.bak
$ ./monitor.sh
Sleeping for next 5 seconds
Sleeping for next 5 seconds
$ ls -l /tmp/logfile*
-rw-r--r-- 1 sss sss 2010 Jun 24 12:29 logfile
-rw-r--r-- 1 sss sss 2005 Jun 24 16:09 logfile-1277474574.bak
Until Statement Execute Body ของ Loop ต่อจนกว่า Condition จะเป็น True ในตัวอย่าง Condition คือ File Size มากกว่า 2000 Bytes ดังนั้น Copy File เมื่อถึง 2000 Bytes
อ่านเพิ่มเติม Bash Array Examples ก่อนหน้า
Bash Until Example 6. รอ Machine พร้อม
ตัวอย่างนี้ใช้ Wait จน Machine พร้อมก่อน SSH ไปเครื่องนั้น Until Loop Statement จบก็ต่อเมื่อ Ping ตอบสนอง
$ cat mac_wait.sh #! /bin/bash read -p "Enter IP Address:" ipadd echo $ipadd until ping -c 1 $ipadd do sleep 60; done ssh $ipadd $./mac_wait.sh Enter IP Address:192.143.2.10 PING 192.143.2.10 (192.143.2.10) 56(84) bytes of data. --- 192.143.2.10 ping statistics --- 1 packets transmitted, 0 received, 100% packet loss, time 0ms PING 192.143.2.10 (192.143.2.10) 56(84) bytes of data. 64 bytes from 192.143.2.10: icmp_seq=1 ttl=64 time=0.059 ms --- 192.143.2.10 ping statistics --- 1 packets transmitted, 1 received, 0% packet loss, time 0ms rtt min/avg/max/mdev = 0.059/0.059/0.059/0.000 ms The authenticity of host '192.143.2.10 (192.143.2.10)' can't be established. Are you sure you want to continue connecting (yes/no)? yes
Until Loop มีประโยชน์มากที่ Command Line เป็นวิธีรอ Certain Events เกิดขึ้น