Pract09 -------- ตอนที่ 1 1. ใช้คำสั่ง help เพื่อดูรายละเอียดของคำสั่ง alias และ unalias ของ bash -- คำสั่งทั้งสองใช้ทำอะไร? -- คำอธิบายที่ได้จาก help เพียงพอต่อการทำความเข้าใจหรือไม่? หากไม่เข้าใจควรจะต้องทำอย่างไร? 2. จาก Lect09.txt มีรายละเอียดของคำสั่ง set ของ bash อยู่เล็กน้อย จงใช้คำสั่ง help เพื่อดูรายละเอียดของคำสั่ง set $ help set ทดลองใช้คำสั่ง set $ set ผลลัพธ์ที่ได้เป็นอย่างไร ประกอบด้วยอะไรบ้าง และจงอธิบายการทำงานของคำสั่ง $ set | grep PS[[:digit:]] 3. จาก Lect09.txt มีทั้งตัวอย่างที่ทำการทดลองโดยตรงได้ และคำสั่งที่ไม่สามารถทดลองได้ เช่นเรื่องการแยกคำสั่งด้วย semicolon คือ $ x ; y ; z หากต้องการทำการทดลองจริงควรจะต้องเลือก Utility ใดมาใช้ทดลองจึงจะผลเห็นชัดเจนที่สุด 4. แฟ้ม test1.dat เป็น text file ที่มีเพียงบรรทัดเดียว ประกอบด้วยคำภาษาอังกฤษ 66 คำ แต่ละคำคั่นด้วย tab จงเขียน pipeline ที่ประกอบด้วยคำสั่ง tr และ sort เพื่อเรียงคำในแฟ้มตามพจนานุกรม และเขียนผลลัพธ์ลงในแฟ้ม test2.dat (รายละเอียดใน week07) ตอนที่ 2 ตัวแปร ---------------- จงพิมพ์และให้ script ต่อไปนี้ทำงาน เป็นการเตรียมการสำหรับการเรียนการสอนเรื่อง debugging และคุณลักษณะอีกหลายอย่างของตัวแปรในสัปดาห์ต่อไป บรรทัดที่ขึ้นต้นด้วย # เป็นหมายเหตุ ไม่จำเป็นต้องพิมพ์ หากต้องการพิมพ์ควรใช้เป็นภาษาอังกฤษ โดยดูจากโปรแกรม var1.sh และ var2.sh ที่ภาคพผนวกท้ายบทความนี้ และหากมีข้อสงสัยที่จุดหนึ่งจุดใดในในโปรแกรมขอให้สอบถามจากผู้สอน 1. โปรแกรม var1.sh $ cat -n var1.sh 1 #!/bin/bash 2 # การใช้ชื่อตัวแปรที่ไม่ต้องนำด้วย $ (Naked variables) 3 4 echo 5 6 # การใช้ชื่อตัวแปรที่ไม่ต้องนำด้วย $ จะใช้ได้ในกรณี 7 # ที่มีการกำหนดค่า, ไม่ใช้การอ้างถึงค่าในตัวแปรนั้น 8 9 # การกำหนดค่า สังเกตการใช้งาน \" เมื่อต้องการใช้ " เป็นอักขระธรรมดา 10 a=879 11 echo "The value of \"a\" is $a." 12 13 # การกำหนดค่าด้วยคำสั่ง 'let' เพื่อนำค่าของนิพจน์กำหนดให้กับตัวแปร 14 let a=16+5 15 echo "The value of \"a\" is now $a." 16 17 echo 18 19 # การใช้งานใน 'for' loop (ซึ่งโดยความจริงเป็นการกำหนดค่ารูปแบบหนึ่ง): 20 echo -n "Values of \"a\" in the loop are: " 21 for a in 7 8 9 11 22 do 23 echo -n "$a " 24 done 25 26 echo 27 echo 28 29 # การใช้งานคำสั่ง 'read' (ซึ่งเป็นหารกำหนดค่าอีกรูปแบบหนึ่ง): 30 read a 31 echo "The value of \"a\" is now $a." 32 33 echo 34 35 exit 0 ผลลัพธ์ที่ได้จากการทำงาน ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... คำอธิบายการทำงานบางส่วนของโปรแกรม บรรทัดที่ 11: echo "The value of \"a\" is $a." เป็นตัวอย่างการกำกับอาร์กิวเมนต์ของ echo ด้วยเครื่องหมายคำพูด ("...") เพื่ออ้างอิงถึงค่าในตัวแปร a ในขณะเดียวกันก็ต้องการใช้เครื่องหมายคำพูดในสายอักขระด้วย จึงต้องกำกับเครื่องหมายคำพูดแต่ละตัวด้วย \ บรรทัดที่ 14: let a=16+5 กำหนดให้คำนวณค่านิพจน์ "16+5" เพื่อนำมากำหนดไห้ตัวแปร a ทำใตัวแปร a มีค่าเป็น 21 บรรทัดที่ 21-24: การใช้งานตัวแปร a ใน for loop ซึ่งเป็นการกำหนดค่ารูปแบบหนึ่ง โดยจะกำหนดให้ a มีค่าตามที่กำหนดไว้ใน list ทีละค่า จึงไม่ต้องนำด้วย $ ส่วนคำสั่ง echo ในบรรทัดที่ 23 เป็นการอ้างถึงค่าในตัวแปร a จึงต้องนำด้วย $ 21 for a in 7 8 9 11 22 do 23 echo -n "$a " 24 done บรรทัดที่ 21-24: read a คำสั่ง read ใช้สำหรับอ่านบรรทัดข้อความจาก standard input และแยกออกเก็บในตัวแปรที่กำหนด คำสั่ง read จึงเป็นการกำหนดค่าให้ตัวแปรแบบหนึ่ง จึงใช้ชื่อตัวแปรได้โดยตรงไม่ต้องนำด้วย $ เมื่อเข้าใจการทำงานของโปรแกรมแล้ว ให้โปรแกรมทำงานอีกครั้งหนึ่ง โดยให้แสดงการทำงานของแต่ละคำสั่ง หรือ traced mode (-x) ดังนี้ $ bash -x var1.sh ผลลัพธ์ที่ได้เป็นอย่างไร พออ่านความหมายได้หรือไม่? จะเห็นว่า เชลล์ทำการขยายอักขระพิเศษในบรรทัดคำสั่ง ก่อนทำงานตามคำสั่งนั้น เมื่อพอเข้าใจแล้ว จึงทดลองให้โปรแกรมทำงานอีกครั้งหนึ่ง โดยให้แสดงคำสั่งที่อ่านมาจากแฟ้มคำสั่งโดยตรง (ไม่แสดงการขยาย) หรือทำงานแบบ verbose mode (-v) ดังนี้ $ bash -v var1.sh ผลลัพธ์ที่ได้เป็นอย่างไร แตกต่างจากการทำงานใน traced mode อย่างไร? เมื่อได้ข้อสรุปแล้วจึงใช้ตัวเลือกทั้งสองผสมกัน ดังนี้ $ bash - xv var1.sh ผลลัพธ์ที่ได้เป็นอย่างไร? เข้าใจการขยายอักขระพิเศษในตัวแปร ชัดเจนขึ้นบ้างหรือไม่ อย่างไร? 2. โปรแกรม var2.sh ปฏิบัติการเช่นเดียวกับโปรแกรม var1.sh เพียงแต่ใช้โปรแกรม var2.sh ซึ่งมีรายละเอียดดังนี้ $ cat -n var2.sh 1 #!/bin/bash 2 3 a=23 # กรณีอย่างง่าย 4 echo $a 5 b=$a 6 echo $b 7 8 # เริ่มเป็นกรณีที่ซับซ้อนขึ้น ใช้การแทนคำสั่งด้วยผลลัพธ์ (command substitution). 9 10 a=$(echo Hello!) 11 echo $a 12 13 # ขอให้สังเกตว่ามีการใช้เครื่องหมายตกใจ, ! (exclamation mark) ในการกำหนดค่าให้ตัวแปรด้วย 14 #+ หากเป็นการสั่งที่ prompt จะไม่ทำงาน เนื่องจากเป็นการเข้าสู่ระบบการเรียกใช้คำสั่งที่เคยใช้งาน 15 #+ และเก็บไว้ใน history buffer และ history file (.bash_history) 16 # แต่เมื่อใช้งานใน script, ระบบจะปิดการทำงานของ history โดยปริยาย 17 18 a=$(ls -l) # นำผลลัพธ์ของคำสั่ง 'ls -l' กำหนดให้ตัวแปร 'a' 19 echo $a # เมื่อไม่กำกับด้วยเครื่องหมายคำพูด, echo จะแทนที่ tab และ newlines ด้วยวรรค 20 echo 21 echo "$a" # กำกับด้วยเครื่องหมายคำพูดจึงจะรักษา tab และ newlines ไว้ได้ 22 # (ลองทบทวนเรื่องการกำกับอักขระพิเศษ หรือ Quoting. 23 exit 0 ภาคผนวก โปรแกรม var1.sh และ var2.sh พร้อม comment ภาษาอังกฤษ $ cat -n var1.sh 1 #!/bin/bash 2 # Naked variables 3 4 echo 5 6 # When is a variable "naked", i.e., lacking the '$' in front? 7 # When it is being assigned, rather than referenced. 8 9 # Assignment 10 a=879 11 echo "The value of \"a\" is $a." 12 13 # Assignment using 'let' 14 let a=16+5 15 echo "The value of \"a\" is now $a." 16 17 echo 18 19 # In a 'for' loop (really, a type of disguised assignment): 20 echo -n "Values of \"a\" in the loop are: " 21 for a in 7 8 9 11 22 do 23 echo -n "$a " 24 done 25 26 echo 27 echo 28 29 # In a 'read' statement (also a type of assignment): 30 read a 31 echo "The value of \"a\" is now $a." 32 33 echo 34 35 exit 0 $ cat -n var2.sh 1 #!/bin/bash 2 3 a=23 # Simple case 4 echo $a 5 b=$a 6 echo $b 7 8 # Now, getting a little bit fancier (command substitution). 9 10 a=$(echo Hello!) 11 echo $a 12 13 # Note that including an exclamation mark (!) within a command 14 #+ substitution construct will not work from the command line, 15 #+ since this triggers the Bash "history mechanism." 16 # Inside a script, however, the history functions are disable by default. 17 18 a=$(ls -l) # Assign result of 'ls -l' command to 'a' 19 echo $a # Unquote, however, it removes tabs and newlines. 20 echo 21 echo "$a" # The quote variable preserves whitespaces. 22 # (See the chapter on "Quoting.") 23 exit 0