# การเขียนโปรแกรมเชลล์ (7)

เราสามารถทำการตรวจสอบเงื่อนไขในเชลล์ได้ โดยการใช้คำสั่ง "test" โดยที่ถ้าเงื่อนไขที่ทำการตรวจสอบนั้นเป็นเงื่อนไขที่ถูกต้องโปรแกรม test จะทำการให้ค่า return code เป็น 0 แต่ถ้าเป็นเงื่อนไขที่ไม่ถูกต้องจะให้ค่าที่ไม่เป็น 0 (โดยปกติจะเป็นค่า 1)

การตรวจสอบเงื่อนไขที่เกี่ยวกับไฟล์

-r pathname | : ถูกต้องถ้ามีไฟล์อยู่และอนุญาตให้สามารถอ่านไฟล์ได้ (readable)
-w pathname | : ถูกต้องถ้ามีไฟล์อยู่และอนุญาตให้สามารถเขียนไฟล์ได้ (writable)
-x pathname | : ถูกต้องถ้ามีไฟล์อยู่และอนุญาตให้สามารถทำงานได้ (executable)
-f pathname | : ถูกต้องถ้ามีไฟล์อยู่และไฟล์เป็นแบบไฟล์ธรรมดา (ordinary)
-d pathname | : ถูกต้องถ้ามีไฟล์อยู่และไฟล์เป็นแบบไดเรกทอรี
-c pathname | : ถูกต้องถ้ามีไฟล์อยู่และเป็นไฟล์แบบดีไวซ์ชนิด character
-b pathname | : ถูกต้องถ้ามีไฟล์อยู่และเป็นไฟล์แบบดีไวซ์ชนิด binary
-p pathname | : ถูกต้องถ้ามีไฟล์อยู่และเป็นไฟล์ชนิด pipe
-u pathname | : ถูกต้องถ้ามีไฟล์อยู่และ setuid bit ถูกเซ็ต
-g pathname | : ถูกต้องถ้ามีไฟล์อยู่และ getgid bit ถูกเซ็ต
-k pathname | : ถูกต้องถ้า sticky bit ถูกเซ็ต
-s pathname | : ถูกต้องถ้ามีไฟล์อยู่และเป็นไฟล์ที่มีข้อมูล
-t channelno | : ถูกต้องถ้าเป็นไฟล์ที่ติดต่อกับ terminal (tty)

การตรวจสอบเงื่อนไขที่เกี่ยวกับสตริง

-z string | : ถูกต้องถ้าสตริงมีความยาวเป็นศูนย์
-n string | : ถูกต้องถ้าสตริงมีความยาวไม่เป็นศูนย์
str1 = str2 | : ถูกต้องถ้าสตริงทั้งสองเหมือนกัน
str | : ถูกต้องถ้าสตริงมีข้อมูลอยู่ (ไม่เป็น null)

การตรวจสอบเงื่อนไขที่เกี่ยวกับตัวเลข

n1 -eq n2 | : ถูกต้องถ้า n1 เท่ากับ n2
n1 -ne n2 | : ถูกต้องถ้า n1 ไม่เท่ากับ n2
n1 -gt n2 | : ถูกต้องถ้า n1 มากกว่า n2
n1 -lt n2 | : ถูกต้องถ้า n1 น้อยกว่า n2
n1 -ge n2 | : ถูกต้องถ้า n1 มากกว่าหรือเท่ากับ n2
n1 -le n2 | : ถูกต้องถ้า n1 น้อยกว่าหรือเท่ากับ n2

การรวมเงื่อนไข

! | : เปลี่ยนผลลัพธ์เงื่อนไขเป็นตรงกันข้าม
-o | : เงื่อนไขแบบหรือ (OR)
-a | : เงื่อนไขแบบและ (AND)
(...) | : รวมคำสั่ง test

ตารางผลลัพธ์คณิตศาสตร์ลอจิกของ A กับ B

A | B | A and B | A or B
T | T | T | T
T | F | F | T
F | T | F | T
F | F | F | F

ในการใช้คำสั่ง test กับเงื่อนไข เมื่อคำสั่ง test ตรวจสอบเงื่อนไขนั้นว่าถูกต้องก็จะทำการคืนค่า exit code 0 ให้ จากหัวข้อที่แล้ว เราได้เรียนรู้ว่าหากต้องการจะตรวจสอบค่า exit code ของโปรแกรมหรือเชลล์เราสามารถตรวจสอบจากตัวแปร "$?" ได้ ซึ่งในที่นี้เราก็จะทำการพิมพ์ค่า exit code นั้นออกมาโดยการใช้คำสั่ง echo

ตัวอย่าง

ตัวอย่างนี้จะทดสอบว่า "/bin" เป็นไดเรกทอรีหรือไม่ ซึ่งก็จะได้ exit code จากคำสั่ง test เป็น 0 ซึ่งก็คือ "/bin" เป็นไดเรกทอรีจริง ส่วนตัวอย่างถัดไปจะทำการตรวจสอบว่า "/bin" เป็นไฟล์หรือไม่ ซึ่งผลลัพธ์ที่ได้ก็จะเป็นเท็จ

    $ test -d /bin; echo $?
    0
    $ test -f /bin; echo $?
    1

ตัวอย่างถัดมาจะใช้เครื่องหมายก้ามปู "[...]" ทำการครอบเงื่อนไขที่ต้องการจะทดสอบซึ่งก็จะให้ผลลัพธ์แบบเดียวกับการใช้คำสั่ง test แต่การใช้เครื่องหมายก้ามปูจะทำให้บรรทัดคำสั่งดูเป็นระเบียบและเข้าใจง่ายกว่า สำหรับในคอร์นเชลล์จะใช้เครื่องหมายก้ามปูซ้อน "[[...]]" การใช้เครื่องหมายแบบนี้ในการทดสอบเงื่อนไขจะมีรูปแบบพิเศษที่เพิ่มเติมขึ้นมาจากการใช้คำสั่ง test หรือการใช้เครื่องหมายก้ามปูธรรมดา

    $ [ ! -f /bin ]; echo $?
    0

ตัวอย่างนี้จะใช้นิพจน์ทางตรรกะเข้ามาร่วมตรวจสอบเงื่อนไขด้วย คือเป็นการทดสอบว่าค่าตัวเลข 1 มากกว่า 2 และ ค่าตัวเลข 2 มากกว่า 3 หรือไม่ พิจารณาจากตารางทางตรรกะศาสตร์แล้ว ก็จะเห็นว่าผลลัพธ์ของ "จริง" และ "เท็จ" (T AND F) ก็จะได้ออกมาเป็นเท็จ ซึ่งก็จะตรงกับผลลัพธ์ที่เชลล์พิมพ์ออกมาให้

    $ [ 1 -gt 2 -a 3 -gt 2 ]; echo $?
    1

### การใช้คำสั่งควบคุมทิศทางการทำงาน Flow control command

ผลลัพธ์ที่ได้จากการใช้คำสั่ง test ทำการทดสอบเงื่อนไขนี้ เราสามารถนำมาใช้เป็นเงื่อนไขของการควบคุมทิศทางการทำงานของโปรแกรมได้ ซึ่งก็จะขึ้นอยู่กับรูปแบบของคำสั่งที่ควบคุมทิศทางต่างๆว่าจะจัดการกับเงื่อนไขที่เป็นจริงอย่างไร และจะจัดการกับเงื่อนไขที่เป็นเท็จอย่างไร

การควบคุมทิศทางการทำงานของโปรแกรมโดยใช้ชุดคำสั่งแบบ ถ้า...แล้ว (if...then) รูปแบบของคำสั่ง

1.     if
       then
       	command list
       else
       	command list
       fi

สำหรับคำสั่งควบคุมทิศทางแบบ ถ้า...แล้ว นี้หากเงื่อนไขที่ทดสอบคืนค่า exit code ที่เป็นจริง (0) มาให้ก็จะทำคำสั่งหลัง "then" แต่ถ้าเป็นเท็จ (ไม่ 0) ก็จะทำชุดคำสั่งที่อยู่หลัง "else" คำสั่งควบคุมทิศทางแบบ ถ้า...แล้ว จะต้องทำการปิดชุดคำสั่งด้วยคำสำคัญ "fi" (เป็นตัวกลับหน้า-หลังกับ if)

ตัวอย่าง

    if [ -d $1 ]
    then
        echo $1 is a directory
    else
        echo $1 is not a directory
    fi

ให้บันทึกชื่อไฟล์เป็น "ex3" แล้วทำการเปลี่ยนโหมดเป็นโหมดที่สามารถสั่งให้ทำงานได้จากนั้นสั่งทำงานโปรแกรมดังต่อไปนี้

    $ ex3 /bin
    /bin is a directory

2.     if
       then
       	command list
       elif
       then
       	command list
       else
       	command list
       fi

สำหรับคำสั่งควบคุมทิศทางแบบ ถ้า...แล้ว รูปแบบที่สองนี้จะคล้ายกับแบบแรก เพียงแต่มีการเพิ่มเติมการตรวจเงื่อนไขเพิ่มขึ้นมาอีกเงื่อนไขหนึ่ง ซึ่งเงื่อนไขนี้จะอยู่ตามหลังคำบังคับ "elif" หากเงื่อนไขตรงนี้เป็นจริง ก็จะทำงานตามชุดคำสั่งหลังคำบังคับ "then" ที่ตามมาทันที สำหรับเงื่อนไขของชุดคำสั่งแบบนี้ สามารถจะเพิ่มเติมเข้ามาได้ไม่จำกัดจำนวน ในกรณีที่เงื่อนไขเกิดถูกต้องมากกว่าหนึ่งเงื่อนไข ก็จะเข้าไปทำงานชุดคำสั่งแรกตามเงื่อนไขแรกสุดที่พบว่าตรงกัน และจะไม่สนใจเงื่อนไขอื่นๆที่ตรงกันอีก หากเงื่อนไขทั้งหมดของ "if" และ "elif" ไม่มีเงื่อนไขใดที่เป็นจริงเลย ก็จะไปทำชุดคำสั่งหลังคำบังคับ "else" แทน

ตัวอย่าง

    if [ "$1" = "JOHN" ]
    then
        echo "Hello $1"
    elif [ "$1" = "MARY" ]
    then
        echo "Hello $1"
    else
        echo "I don't know $1"
    fi

ให้บันทึกสคริปต์เป็นชื่อ ex4 แล้วทดลองใช้งานโปรแกรมดังต่อไปนี้

    $ ex4 JOHN
    Hello JOHN
    $ ex4 MARY
    Hello MARY
    $ ex4 PETER
    I don't know PETER

### การใช้คำสั่งทั่วไปบนลีนุกซ์มาเป็นเงื่อนไข

นอกจากเงื่อนไขที่ใช้กับคำสั่ง "test" แล้วเราสามารถนำเอาคำสั่งอื่นๆ หรือแม้แต่เชลล์สคริปต์ที่เราสร้างขึ้นมาเอง มาเป็นเงื่อนไขของคำสั่งควบคุมทิศทางแบบ "ถ้า...แล้ว" ก็ได้ ซึ่งก็จะทำการตรวจจาก exit code ของคำสั่งหรือเชลล์สคริปต์นั้นๆ หาก exit code เป็น 0 ก็จะถือว่าเงื่อนไขเป็นจริง แต่ถ้าไม่เป็น 0 ก็จะถือว่าเงื่อนไขเป็นเท็จ เราอาจนำเอาหลายๆคำสั่งเข้ามาเป็นเงื่อนไขร่วมกันก็ได้ แต่วิธีการรวมก็จะแตกต่างกันไป กล่าวคือหากรวมเงื่อนไขแบบ "และ" ก็จะใช้เครื่องหมาย "&&" แต่หากรวมเงื่อนไขแบบ "หรือ" ก็จะใช้เครื่องหมาย "||"

1. if statement1 || statement2
ตัวอย่าง

    filename=$1
    word1=$2
    word2=$3

    if grep $word1 $filename > /dev/null || grep $word2 $filename > /dev/null
    then
        echo "$word1 or $word2 is in $filename."
    fi

ให้ทำการบันทึกเชลล์สคริปต์นี้เป็นไฟล์ชื่อ ex5 และทำการสั่งงานโปรแกรมดังต่อไปนี้

    $ ex5 ex5 if case
    if or case is in ex5

จากตัวอย่างจะเป็นการตรวจหาคำสองคำในไฟล์ หากหาเจอคำใดคำหนึ่งหรือทั้งคู่ ก็จะทำการแจ้งให้ทราบว่าหาเจอคำที่หนึ่ง "หรือ" คำที่สอง จากตัวอย่างก็จะเป็นการตรวจหาคำว่า "if" กับคำว่า "case" ในไฟล์ ex5 ซึ่งเป็นตัวเชลล์สคริปต์เอง เราจะเห็นว่ามีคำว่า "if" อยู่ใน ex5 แต่ไม่มีคำว่า "case" ซึ่งก็จะตรงกับเงื่อนไขที่ว่าพบคำใดคำหนึ่งอยู่ในไฟล์ อนึ่งสำหรับคำสั่ง "grep" ซึ่งเป็นคำสั่งที่ใช้ตรวจหาคำที่ต้องการค้นหาจากไฟล์นั้นจะทำการคืนค่า exit code ที่เป็น 0 มาให้ในกรณีที่หาคำนั้นๆพบ แต่หากหาไม่พบก็จะคืนค่าที่ไม่เป็น 0 ออกมาให้
2. if statement1 && statement2
ตัวอย่าง

    filename=$1
    word1=$2
    word2=$3

    if grep $word1 $filename > /dev/null && grep $word2 $filename > /dev/null
    then
        echo "$word1 and $word2 are both in $filename."
    fi

ให้ทำการบันทึกเชลล์สคริปต์นี้เป็นไฟล์ชื่อ ex6 และทำการสั่งงานโปรแกรมดังต่อไปนี้

    $ ex6 ex6 if then
    if and then are both in ex5

สำหรับตัวอย่างนี้จะต้องตรวจคำเจอทั้งสองคำ (คือ "if" กับ "then") โปรแกรมจึงจะแจ้งให้ทราบว่าพบคำทั้งสองอยู่ในไฟล์ที่ต้องการค้นหานั้น

### คำสั่งควบคุมทิศทางแบบ case

รูปโฟลว์ชาร์ตของ if...then และมีลักษณะโครงสร้างแบบเดียวกับโครงสร้างของ case ด้วย
โครงสร้างของ case จะมีลักษณะดังต่อไปนี้

    case STRING in
        pattern-1)  command-list1 ;;
        pattern-2)  command-list2 ;;
        pattern-3)  command-list3 ;;
                *)  cammand-list-else ;;
    esac

หากมีเงื่อนไขแบบ "ถ้า...แล้ว" หรือ if-elif จำนวนมาก เราจะมีวิธีที่ดีกว่าในการจัดการกับเงื่อนไขเหล่านั้น นั่นก็คือใช้ case เข้ามาแทนที่ สำหรับโครงสร้างของ case ตามปกติจะใช้จับคู่ (matching) กับสตริงที่มีรูปแบบลักษณะ (pattern) เหมือนกันและจะไม่สามารถใช้ได้กับรูปแบบของนิพจน์ทางคณิตศาสตร์ สำหรับรูปแบบต่างๆจะต้องมีเครื่องหมายวงเล็บปิด ")" ตามท้าย และหลังจากนั้นก็จะเป็นชุดคำสั่งที่จะให้ทำงานจะต้องปิดท้ายชุดคำสั่งด้วยเครื่องหมาย colon คู่ ";;" เราสามารถใส่รูปแบบได้มากกว่าหนึ่งรูปแบบได้ สำหรับรูปแบบที่ไม่สามารถจับคู่ได้เลย จะใช้คำบังคับ "*" การปิดท้ายคำสั่งควบคุม case จะใช้คำบังคับ "esac" (เป็นคำกลับหน้า-หลังของ "case") ตัวอย่าง

    echo -n "entry (j/J/n/N/y/Y)"; read INPUT
    case "$INPUT" in
        [yYjJ]) echo "entry is permitted" ;;
          [nN]) echo "entry is also permitted" ;;
             *) echo "entry is false"
    	    echo "the valid entry are (j/J/n/N/y/Y)" ;;
    esac

ให้บันทึกเชลล์สคริปต์ข้างบนในชื่อ ex7 แล้วทำการเรียกโปรแกรมดังต่อไปนี้

    $ ex7
    entry (j/J/n/N/y/Y)j
    entry is permitted
    $ ex7
    entry (j/J/n/N/y/Y)e
    entry is false
    the valid entry are (j/J/n/N/y/Y)

สำหรับตัวอย่างการใช้ case ข้างบนจะเป็นการแสดงถึงการจับคู่ของตัวอักษร ซึ่งเราจะอ่านเข้ามาเก็บไว้ในตัวแปรเชลล์ชื่อ INPUT และจะนำเอาค่าในตัวแปร INPUT ไปเปรียบเทียบแบบสตริงกับรูปแบบต่างๆ การใช้คำสั่ง echo -n จะเป็นการพิมพ์ข้อความที่ตามหลัง echo แบบไม่ขึ้นบรรทัดใหม่ ดังนั้นเมื่อใช้คำสั่ง read ตามมาก็จะเป็นการรอรับการใส่ข้อมูลต่อท้ายจากข้อความที่พิมพ์ออกมาทันที (ไม่ขึ้นบรรทัดใหม่)

จากตัวอย่างเราจะเห็นว่ารูปแบบของสตริงแต่ละบรรทัดสามารถกำหนดให้จับคู่กันได้มากกว่าหนึ่งแบบ ตัวอย่างเช่น "[yYjJ]" ก็จะเป็นการเลือกได้ว่าจะจับคู่กับตัวอักษร "y", "Y", "j" หรือ "J" เนื่องจากอยู่ในเครื่องหมายก้ามปู ซึ่งมีความหมายว่าสามารถเลือกเอาได้หนึ่งอย่างจากที่อยู่ในเครื่องหมายก้ามปูนั้น

ส่วนบรรทัดสุดท้ายเป็นการจับคู่กับสตริงที่ไม่เข้าคู่เลยนั้น จะเห็นว่าเราสามารถใส่ชุดคำสั่งเข้าไปมากกว่าหนึ่งบรรทัดได้ แต่ชุดคำสั่งสุดท้ายจะต้องปิดท้ายด้วยเครื่องหมาย colon คู่ ";;"

### คำสั่งควบคุมทิศทางแบบวนรอบ (loop flow control)

คำสั่งควบคุมทิศทางแบบวนรอบหรือวนลูปจะมีอยู่สามแบบคือ for, while และ until

#### for loop

โครงสร้าง

    for VAR in Arg-list
    do
        command list
    done

คำสั่ง for นี้จะทำทำงานวนรอบจนกระทั่งสมาชิกใน "Arg-list" ถูกใช้หมด ชุดคำสั่งในลูป for จะต้องอยู่ภายใต้คำบังคับ "do" และ "done" การใช้ for ส่วนใหญ่จะใช้กับลูปที่รู้จำนวนของรอบที่ต้องทำและ "Arg-list" ที่แน่นอน

ตัวอย่าง

    SUM=0
    for i in 1 2 3 4 5 6 7 8 9
    do
        SUM=`expr $SUM + $i`
    done
    echo "Sum is $SUM"

ให้บันทึกเชลล์สคริปต์ข้างต้นเป็นไฟล์ชื่อ ex8 แล้วสั่งให้โปรแกรมทำงานดังนี้

    $ ex8
    Sum is 45

จากตัวอย่างจะเป็นการรวมตัวเลขจำนวนเต็มตั้งแต่ 1 ถึง 9 เสร็จแล้วพิมพ์ค่าที่ได้้ออกมา

#### while และ until

##### โครงสร้างของ while

    while (true condition)
    do
        command list
    done

คำสั่ง while จะใช้กับเงื่อนไขที่เป็นจริง
ตัวอย่าง

    SUM=0
    i=1
    while [ $i -lt 10 ]
    do
        SUM=`expr $SUM + $i`
        i=`expr $i + 1`
    done
    echo "Sum is $SUM"

โปรแกรมตัวอย่างข้างบนจะทำงานเหมือนกับ ex8 แต่ในที่นี้ใช้รูปแบบของ while loop โปรแกรมจะทำการบวกตัวเลข "i" ไปเรื่อยๆโดยเริ่มตั้งแต่ 1 และเพิ่มค่า i ขึ้นทีละหนึ่ง ลูปนี้จะทำงานไปเรื่อยๆตราบใดที่ค่า i ยังน้อยกว่า 10 เมื่อค่า i มากกว่า 10 แล้วก็จะออกจากลูปและพิมพ์ผลบวกที่ได้ทั้งหมด

##### โครงสร้างของ until

    until (false condition)
    do
        command list
    done

คำสั่ง until จะใช้กับเงื่อนไขที่เป็นเท็จ
ตัวอย่าง

    SUM=0
    i=1
    until [ $i -eq 10 ]
    do
        SUM=`expr $SUM + $i`
        i=`expr $i + 1`
    done
    echo "Sum is $SUM"

โปรแกรมตัวอย่างข้างบนก็เป็นโปรแกรมที่ให้ผลลัพธ์แบบเดียวกับโปรแกรมที่ใช้โครงสร้างของ for-loop และ while-loop เช่นเดียวกัน จะเห็นว่าโปรแกรมมีลักษณะที่คล้ายกับโปรแกรมที่ใช้โครงสร้างแบบ while-loop มาก เพียงแต่เงื่อนไขที่ใช้ตรวจสอบจะเป็นเงื่อนไขที่กลับกันเท่านั้น กล่าวคือเงื่อนไขนี้จะใช้ตรวจสอบว่าค่าของตัวแปร i เท่ากับ 10 หรือไม่ until-loop จะทำการวนลูปทำงานไปเรื่อยๆตราบใดที่เงื่อนไขที่ตามหลัง until มานั้นยังคงเป็นเท็จ

ในการเขียนโปรแกรมนั้นเราสามารถจะเลือกใช้เฉพาะ while-loop หรือ until-loop ตัวใดตัวหนึ่งเพียงอย่างเดียวก็ได้ เพราะเงื่อนไขของลูปทั้งสองแบบเราสามารถดัดแปลงให้ทดแทนกันได้ ดังที่ได้แสดงในโปรแกรมตัวอย่าง แต่หากคุณต้องการจะใช้งานลูปทั้งสองแบบก็ได้ ตรงนี้ก็จะขึ้นอยู่กับความถนัดของผู้เขียนโปรแกรมแต่ละคน

#### break และ continue

คำสั่ง break และ continue จะทำการหยุดการทำชุดคำสั่งที่ตามหลัง break กับ continue และสำหรับ break เมื่อหยุดแล้วก็จะกระโดดออกไปนอกลูป ตรงจุดที่อยู่ถัดจากคำบังคับ "done" ส่วน continue จะกลับไปทำงานในลูปต่อ ตรงจุดที่อยู่ถัดจากคำบังคับ "do"

    SUM=0
    while [ true ]
    do
        echo -n "Please enter number 1-9 , except 5 , (q-quit)"
        read INPUT

        if [ "$INPUT" = "q" ]
        then
            echo "Break loop now!"
            break
        elif [ $INPUT -eq 5 ]
        then
            echo "Please not input 5"
            continue
        elif [ $INPUT -lt 1 ]
        then
            echo "Please not input data < 1"
            continue
        elif [ $INPUT -gt 9 ]
        then
            echo "Please do not input data > 9"
            continue
        fi
        SUM=`expr $SUM + $INPUT`
    done
    echo "SUM is $SUM"

ในตัวอย่างนี้นอกจากแสดงถึงการใช้ break กับ continue แล้ว ยังแสดงให้เห็นถึงการใช้ while ที่เป็นที่นิยมใช้อีกแบบหนึ่ง นั่นก็คือการใช้กับเงื่อนไข "true" วิธีการใช้งานแบบนี้ จะทำให้โปรแกรมวนลูปแบบไม่รู้จบ ซึ่งมักจะใช้กับการวนทำงานที่มีการรับข้อมูลเข้าไปตามตัวอย่างข้างต้น จะมีเงื่อนไขของการรับข้อมูลบางรูปแบบที่จะใช้กระโดดออกจากลูปเพื่อจบการทำงาน ซึ่งในที่นี้ก็จะใช้คำสั่ง "break" เมื่อผู้ใช้มีการป้อนตัวอักษร "q" เข้ามา เราอาจจะใช้คำสั่ง "exit" แทนก็ได้ แต่โปรแกรมจะไม่ทำงานส่วนที่พิมพ์ผลลัพธ์ที่อยู่ท้ายโปรแกรม

สำหรับคำสั่ง "continue" จะใช้กับการป้อนข้อมูลที่เป็นตัวเลข 5 ซึ่งในที่นี้ก็จะเป็นการข้ามการบวกเลข 5 ไป ตัวเลขที่ใส่ได้และโปรแกรมจะทำการบวกเลขให้จะมีเฉพาะตัวเลข 1-4 และ 6-9 ส่วนตัวเลขที่น้อยกว่า 1 และมากกว่า 9 ก็จะถูกคำสั่ง "continue" ข้ามส่วนของโปรแกรมที่เป็นการคำนวณการบวกเลขไปเช่นเดียวกัน

คำสั่ง continue และ break นี้จะทำการกระโดดออกไปจากลูปที่โปรแกรมกำลังทำงานอยู่ แต่เราสามารถระบุให้ continue และ break ทำการกระโดดออกไปยังลูปที่ชั้นใดก็ได้ ในกรณีที่ลูปของเรามีการครอบอยู่หลายชั้น วิธีการใช้งานก็เพียงแต่เติมตัวเลขตามท้ายคำสั่ง break และ continue เท่านั้น ตัวอย่างเช่น "break 2" จะทำการกระโดดออกจากลูปไปสองชั้น (ไปอยู่หลัง done ของลูปที่สอง)

### workshop : โปรแกรมสำเนาไดเรกทอรี (copydir)

เราได้เรียนรู้วิธีการเขียนโปรแกรมเชลล์มาพอสมควรแล้ว ต่อไปนี้จะเป็นโครงงานสำหรับการเขียนโปรแกรมสำเนาไดเรกทอรี ในระบบลีนุกซ์ไม่มีคำสั่งที่ทำการสำเนาไดเรกทอรีโดยตรง แทนที่เราจะใช้วิธีสำเนาไฟล์ทีละไฟล์จากไดเรกทอรีหนึ่งไปยังอีกไดเรกทอรีหนึ่ง ควรจะเขียนโปรแกรมเชลล์ขึ้นมาเพื่อจะจัดการกับปัญหานี้โดยเฉพาะ

คำสั่งที่อาจเป็นประโยชน์กับการเขียนโปรแกรม

- dirname จะแสดงชื่อไดเรกทอรีของโปรแกรมออกมา (ในกรณีที่ใส่ชื่อแบบเต็ม)
- basename จะแสดงเฉพาะชื่อของโปรแกรมออกมา (ในกรณีที่ใส่ชื่อแบบเต็ม)

ตัวอย่างเช่น

    $ dirname /usr/bin/ls
    /usr/bin

    $ basename /usr/bin/ls
    ls

ปกติผู้ใช้ยูนิกซ์ในระดับผู้เชี่ยวชาญจะสามารถใช้คำสั่ง find ควบคู่ไปกับคำสั่ง cpio เพื่อช่วยในการสำเนาไดเรกทอรี โดยจะทำการสำเนาไฟล์ทั้งหมดและรวมทั้งไฟล์ใดไดเรกทอรีล่างๆด้วย ไปไว้ที่ไดเรกทอรีใหม่ โดยใช้คำสั่งดังนี้

    $ find [src directory name] -print | cpio -pd [dest directory name]
    เช่น
    $ find /home/user1 -print | cpio -pd /home/user2

แต่ในบางกรณีเราอาจไม่ต้องการจะสำเนาไดเรกทอรีไปไว้ที่ไดเรกทอรีใหม่ (จากตัวอย่างคือ /home/user2) เพราะในไดเรกทอรีใหม่อาจมีไฟล์อื่นๆอยู่ก่อนแล้ว หากนำไปไว้ที่ไดเรกทอรีใหม่เลยอาจเป็นการสับสนกับของเดิมได้ โปรแกรมเชลล์ของเราก็ควรจะมีความสามารถในการตรวจสอบไดเรกทอรีปลายทางได้ว่า มีไฟล์อยู่ก่อนแล้วหรือไม่ และถ้ามีจะให้จัดการได้อย่างไร

นอกจากนี้หากผู้ใช้ระบุชื่อไดเรกทอรีปลายทางผิด แทนที่จะเป็นชื่อไดเรกทอรีกลับเป็นชื่อไฟล์ไป โปรแกรมควรจะจัดการอย่างไร หรือหากชื่อไดเรกทอรีปลายทางไม่ปรากฏอยู่โปรแกรมควรจะจัดการอย่างไร

นอกจากปัญหาข้างต้นเหล่านี้ลองคิดถึงปัญหาที่อาจเกิดขึ้นอื่นๆ ลองออกแบบโปรแกรมที่ช่วยให้ผู้ใช้ที่ไม่เชี่ยวชาญลีนุกซ์/ยูนิกซ์ สามารถใช้งานโปรแกรมได้ง่ายเท่าที่จะเป็นไปได้

ดูรายละเอียดโปรแกรมจากเอกสารตอนถัดไป (SHELL (8))

HTML developed by Kaiwal Development Team (kaiwal@geocities.com)