Note06-2 ตอนที่ ๒ จากปฏิบัติการ การเขียน Unix pipeline เพื่อแสดงรายละเอียดของแฟ้มที่มีขนาดใหญ่ที่สุด 5 แฟ้มแรกใน /usr/bin (คำแนะนำ -- sort, head) ในความเป็นจริง คำสั่ง ls มีตัวเลือก -S สำหรับเรียงรายชื่อแฟ้มในไดเรกทอรีตามขนาดของแฟ้มจากมากไปน้อย สามารถนำมาใช้ใน pipeline ได้เลย เช่น ls -Sl /usr/bin | head -5 แต่แบบฝึกหัดนี้มีจุดประสงค์ให้ศึกษาคำสั่ง sort ซึ่งจะได้ใช้ต่อไปในการเขียน shell script โดยเฉพาะอย่างยิ่งการกำหนด sorted key ในบรรทัดคำสั่ง เพราะจากคู่มือของคำสั่งจะพบว่า หากไม่มีการกำหนดเป็นอย่างอื่น คำสั่ง sort จะถือเอาข้อมูลทั้งบรรทัดเป็น sorted key กล่าวอีกนัยหนึ่งคือ การจัดเรียงจะเกิดขึ้นจากอักขระตัวแรกของบรรทัดเป็นต้นไป และถือเป็นการจัดเรียงสายอักขระตามพจนานุกรม (lexicographical order) ตัวอักษรตัวใหญ่ในภาษาอังกฤษมาก่อนตัวอักษรตัวเล็ก โดยเรียงจากน้อยไปมาก (ascending order) สรุป: ค่าโดยปริยายของ sort sorted key: ข้อมูลทั้งบรรทัด ชนิดข้อมูล: สายอักขระ วิธีการจัดเรียง: เรียงตามพจนานุกรม, ตัวอักษรตัวใหญ่มาก่อนตัวเล็ก ลำดับข้อมูล: เรียงจากมากไปน้อย ผู้ใช้สามารถเปลี่ยนแปลงค่าโดยปริยายเหล่านี้ได้ โดยการกำหนดตัวเลือกที่หมาะสม ก. อักษรตัวใหญ่และตัวเล็ก จัดเรียงตัวอักษรภาษาอังกฤษตัวเล็กและตัวใหญ่ไปพร้อมกัน กำหนดด้วยตัวเลือก -f (fold lower case to upper case character) หมายถึงให้จัดเรียงเหมือนตัวอักษรทั้งหมดเป็นอักษรตัวใหญ่ ข. ชนิดข้อมูล ในกรณีที่ข้อมูลเป็นสายอักขระที่มีแต่ตัวเลข (string of digits) กำหนดให้เรียงตามค่าของตัวเลขได้ โดยใช้ตัวเลือก -n (numeric-sort) และหากข้อมูลเป็นชื่อย่อของเดือน เช่น Jan, Feb, ... กำหนดให้เรียงตามชื่อเดือนได้ โดยใช้ตัวเลือก -M (month-sort) ค. วิธีการจัดเรียง หากต้องการให้มีการเรียงจากมากไปน้อย (descending order) กำหนดด้วยตัวเลือก -r (reverse) ง. การกำหนด sorted key การกำหนด sorted key ทำได้โดยใช้ตัวเลือก -k ซึ่งมีคำอธิบายดังนี้ -k, --key=POS1[,POS2] start a key at POS1 (origin 1), end it at POS2 (default end of line) หรือ กำหนดให้ sorted key เริ่มต้นที่ POS1 (ค่าเดิมเป็น 1) และสิ้นสุดที่ POS2 (ค่าโดยปริยายเป็นท้ายสุดของบรรทัด) คำอธิบาย POS เป็นดังนี้ POS คือ F[.C][OPTS], เมื่อ F เป็นหมายเลขฟิลด์ และ C เป็นตำแหน่งเริ่มต้นของอักขระในฟิลด์นั้น ค่าเดิมของ F และ C คือ 1; หากไม่มีการกำหนดตัวเลือก -b หรือ -t อักขระตัวแรกในฟิลด์จะนับจากอักขระที่อยู่หลัง whitespace (วรรค, tab); OPTS เป็นอักขระกำหนดวิธีการการจัดเรียง ซึ่งแต่ละวิธีเป็นอักขระตัวเดียว และใช้ผสมกันได้ ตัวเลือก -b ใช้กำหนดให้ข้ามวรรคที่ต้นบรรทัด (ถ้ามี) ส่วนตัวเลือก -t ใช้กำหนดอักขระคั่นฟิลด์ ในกรณีที่ไม่ใช่ whitespace จะเห็นว่าแม้จะมีการแปลคู่มือเป็นภาษาไทยแล้ว ก็ยังอ่านและทำความเข้าใจได้ยาก จึงต้องการให้ได้ทดลองใช้จริง เพื่อสร้างความเข้าใจ และสรุปการใช้งานเป็นแบบของตนเองให้ได้ เมื่อทำได้กับคำสั่งหนึ่ง จะได้เป็นกำลังใจในการทำความเข้าใจคำสั่งอื่นๆ ต่อไป $ ls -l /usr/bin ... ... ... -rwxr-xr-x 1 root root 85168 Mar 19 2014 bc ... ... ... หมายเหตุ: ยังจำโปรแกรม bc (basic calculator) ที่เคยใช้ตอนเริ่มเรียนวิชานี้ได้ไหม? จะเห็นว่า "ขนาดของแฟ้ม" ที่จะใช้เป็น sorted key เป็นฟิลด์ที่ 5 และเป็นสายอักขระที่เป็นตัวเลข วิธีการจัดเรียงทำจากมากไปน้อย ชนิดข้อมูล: สายอักขระที่เป็นตัวเลข ใช้ numeric-sort, -n เรียงจากมากไปน้อย ใช้การ reverse ผลการเปรียบเทียบ, -r sorted key: ใช้ฟิลด์ที่่ 5 เพียงฟิลด์เดียว เริ่มจากอักขระตัวแรกในฟิลด์ (default), อักขระคั่นฟิลด์เป็นวรรค (default) การกำหนดเพียงฟิลด์เดียว เพื่อป้องการนำ เดือน, วัน, ปี, และชื่อแฟ้ม มาเป็น key รองในการจัดเรียงด้วย ฟิลด์เดียว - ฟิลด์เริ่มต้นฟิลด์สุดท้ายเป็นฟิลด์เดียวกัน คือฟิลด์ที่ 5 คำสังที่ต้องการคือ "sort -k5rn,5" นำมากับ ls และ head เป็น pipeline ได้ดังนี้ $ ls -l /usr/bin | sort -k5rn,5 | head -5 การแสดงผลยังอยู่ในรูปแบบของคำสั่ง ls -l หากต้องการแสดงผลในรูปชื่อแฟ้ม และ ขนาด เช่น php5 9114792 ... ... ... ... ต้องใช้ awk ช่วยในการตัดชื่อแฟ้ม (ฟิลด์ที่ 9) และขนาด (ฟิลด์ที่ 5) ดังนี้ $ ls -l /usr/bin | sort -k5rn,5 | awk '{print $9 " " $5}' | head -5 php5 9114792 gdb 5724352 aptitude-curses 4383088 mysql_client_test 3754328 ชื่อแฟ้มและขนาดจะอ่านได้ยาก อาจเพิ่มจำนวนวรรคระหว่างฟิลด์ให้มากขึ้น หรือเปลี่ยนอักขระคั่นเป็น tab เช่น $ ls -l /usr/bin | sort -k5rn,5 | awk '{print $9 "\t" $5}' | head -5 php5 9114792 gdb 5724352 aptitude-curses 4383088 mysql_client_test 3754328 ผลลัพธ์ถูกต้องแล้ว แต่ยังไม่ "สวย" หากต้องการควบคุมการพิมพ์ให้ดีกว่านี้ ต้องใช้คำสั่ง printf ร่วมกับ awk เช่น $ ls -l /usr/bin | sort -k5rn,5 | awk '{printf "%-20s %s\", $9, $5}' | head -5 php5 9114792 gdb 5724352 aptitude-curses 4383088 mysql_client_test 3754328 python3.4 3714088 การทำให้การแสดงผลดูเรียบร้อยสวยงาม เป็นกระบวนการที่กินเวลาและความพยายามมาก แต่ก็เป็นส่นที่จำเป็น เพื่อเพิ่มคุณค่าให้กับโปรแกรม แต่ต้องทำหลังจากที่โปรแกรมทำงานถูกต้องสมบูรณ์แล้ว ขอให้ระลึกไว้เสมอว่า "✔ โปรแกรมที่มีทำงานได้ถูกต้องแต่การแสดงผลไม่สวยงาม เป็นโปรแกรมที่ใช้ประโยชน์ได้" "✘ โปรแกรมที่มีการแสดงผลสวยงาม แต่ทำงานไม่ถูกต้อง เป็นโปรแกรมที่ไม่มีคุณค่าใดๆ เลย" สุภาษิต (ฝร่ง) สำหรับนักเขียนโปรแกรม "First make it work, then make it pretty." "Make it work, make it better, make it faster." คำถาม: ทำอย่างไรจึงจะรู้ว่า pipeline หรือ โปรแกรมที่เขียนขึ้น ทำงานได้ถูกต้อง? คำตอบ: testing อย่างไร? --------- (1). คำตอบที่ง่ายที่สุดคือ กลับไปทบทวน Testing ในรายวิชา Software Development ใหม่ (2). ถ้าเป็น pipeline ในแบบฝึกหัดชุดนี้ เทียบผลลัพธ์กับการใช้คำสั่ง ls -lS (3). ถ้าเป็นงานอื่นมี่เกี่ยวกับแฟ้ม ควรทดสอบในไดเรกทอรีที่มีจำนวนแฟ้มน้อยๆ ก่อน เมื่อทำงานได้ถูกต้องสมบูรณ์ ก็พอจะแน่ใจได้ว่าเมื่อนำไปใช้กับไดเรกทอรีที่มีแฟ้มมาก ควรให้ผลลัพธ์ที่ถูกต้องเช่นกัน (4). ก่อนเริ่มทำโปรแกรม (หรือ pipeline) ทุกครั้ง ควรได้นึกถึงและจัดเตรียมข้อมูลสำหรับทดสอบการทำงานของโปรแกรมไว้ก่อน ข้อมูลทดสอบต้องครอบคลุมการทำงานทั้งหมดของโปรแกรม เมื่อเขียนโปรแกรมเสร็จและให้ทำงานกับข้อมูลทดสอบ หากข้อมูลขุดใดให้ผลลัพธ์ไม่ถูกต้อง ผู้เขียนโปรแกรมจะรู้ได้ทันทีว่าโปรแกรมน่าจะผิดที่ส่วนใด ข้อมูลสำหรับทดสอบที่ดีที่สุดคือ ข้อมูลเข้าทั้งหมดที่เป็นไปได้ของโปรแกรม แต่ไม่สามารถทำได้เพราะเป็นข้อมูลจำนวนมหาศาล หรือเป็น Universal set (Universe - U) จึงต้องพิจารณา "เลือก" ข้อมูลที่น้อยที่สุด ให้ครอบคลุมการทำงานของโปรแกรมมากที่สุด เรียกว่า Test set (T) โดย T ⊂ U