ขอบคุณ http://www.thaitux.info/book/export/html/366
bash: แตะ Shell Script
ขออนุญาตเขียนแบบกองโจรนะครับ โดยมือใหม่ เพื่อมือใหม่ครับ
เอามาจาก tldp: BASH Programming – Introduction HOW-TO
ศึกษาเพิ่มเติมได้จาก tldp: Bash Guide for Beginners
และในเชิงลึก จาก tldp: Advanced Bash-Scripting Guide1.เกริ่น
เชลล์สคริปต์ พูดง่าย ๆ ก็คือการนำคำสั่งในเชลล์ของลินุกซ์มาเรียงต่อกันให้ทำงานตามที่เราต้องการ โดยเพิ่มโครงสร้างการวนรอบ และฟังก์ชั่นต่าง ๆ เติมเข้ามา เพื่อให้การทำงานได้ตามที่เราต้องการ ซึ่งจะเหมาะมากกับงานแบบ batch หรืองานแบบ schedule
ฉะนั้นการที่จะเขียนโค๊ดให้ได้ดี จึงต้องศึกษาจดจำคำสั่งต่าง ๆ ของเชลล์ให้ได้เท่าที่เราต้องการใช้งาน (จำหมดคงไม่ไหว)
คำสั่งต่าง ๆ สามารถดูได้ที่ gnu.org: Bash Reference Manualสำหรับเดเบียน หากต้องการใช้งาน bash แบบเต็มรูป (ไม่อั้นความสามารถ) อาจต้องปรับแต่งเล็กน้อย
เปลี่ยนให้เชลล์ของเราเป็น bash แทน sh ใช้คำสั่ง$ chsh -s /bin/bashสำหรับเอดิเตอร์ ถ้าใช้ vi ควรติดตั้ง vim-full และอย่าลืมแก้ไขไฟล์ vimrc ให้แสดงสีด้วย เพื่อให้ดูโค๊ดได้ง่ายขึ้น
$ sudo aptitude install vim-full $ vi ~/.vimrcsyntax on:wq2.เริ่มเขียน
2.1 สคริปต์ Hello World
สมมุติตั้งชื่อสคริปต์ว่า hello.sh
$ vi hello.sh#!/bin/bash echo Hello World:wqอย่าลืมเปลี่ยนสถานะเพื่อให้สคริปต์สามารถรันได้
$ chmod 755 hello.shเริ่มรัน
$ ./hello.sh Hello Worldเรียบร้อยแล้ว
บรรทัดแรก เรียกว่า hash-bang เป็นการบอกให้เชลล์รู้ว่า โค๊ดที่เราเขียนนี้จะถูกประมวลผลด้วยโปรแกรมอะไร ในที่นี้คือ
/bin/bash
บรรทัดที่สอง เป็นการสั่งให้พิมพ์Hello World
ออกทางจอภาพ
2.2 สคริปต์สำหรับสำรองข้อมูล
จากตัวอย่างข้างบน ผมเขียนอธิบายโดยละเอียดโดยใช้เอดิเตอร์ vi แต่เพื่อให้กระชับเข้า จะขอละเลยการใช้เอดิเตอร์ โดยจะเขียนเฉพาะโค๊ดอย่างเดียวครับ
#!/bin/bash tar -cvzf /tmp/my-backup.tgz /home/USER/บรรทัดที่สองให้เปลี่ยนคำว่า USER เป็นชื่อเรา
เป็นการสั่งให้ใช้คำสั่ง tar ทำการสำรองข้อมูลพร้อมบีบอัดข้อมูลในไดเรคทอรี่ของบ้านเราไปสู่ไฟล์ชื่อ/tmp/my-backup.tgz
3. การเปลี่ยนทิศข้อมูล (Redirection)
ใช้สัญญลักษณ์
>
ใสการเปลี่ยนทิศ3.1 ข้อมูลมาตรฐาน
ข้อมูลมาตรฐานในเชลล์จะมีอยู่ 4 ชนิด คือข้อมูลเข้า(stdin), ข้อมูลแสดงผล(stdout), ข้อมูลข้อผิดพลาด(stderr), และแฟ้มข้อมูล(file)
ในทางปฏิบัติ เราสามารถเปลี่ยนทิศทางของข้อมูลเหล่านี้ไปมาได้ โดยมีมาตรฐานคือ 1 จะหมายถึงข้อมูลแสดงผล(stdout) และ 2 จะหมายถึงข้อมูลความผิดพลาด(stderr)เช่น
3.2 ตัวอย่างเปลี่ยน stdout ไปเป็น file
$ ls -l > ls-l.txtจะเปลี่ยนการแสดงผลของคำสั่ง
ls -l
ไปเก็บไว้ที่ไฟล์ชื่อ ls-l.txt ดังนั้นคำสั่งตามตัวอย่างนี้จะไม่แสดงอะไรออกมาทางจอภาพ แต่จะเก็บไว้ที่ไฟล์แทน หากเราต้องการดูผล สามารถใช้คำสั่งแสดงผลของไฟล์ได้คือ$ cat ls-l.txt
3.3 ตัวอย่างเปลี่ยน stderr ไปเป็น file
$ grep da * 2> grep-errors.txtตัวอย่างนี้เป็นการค้นหาข้อความ
da
ในทุกไฟล์ (*) และหากเกิดข้อผิดพลาดขึ้น จะนำข้อความผิดพลาดไปเก็บไว้ที่ไฟล์ชื่อ grep-errors.txt
3.4 ตัวอย่างเปลี่ยน stdout ไปเป็น stderr
$ grep da * 1>&2เป็นการค้นหาข้อความ
da
ในทุกไฟล์ (*) โดยนำการแสดงผลไปใส่ไว้ใน stderr แทนการแสดงผลปกติ แต่ในกรณีนี้เราป้อนคำสั่งทางแป้นพิมพ์ stdout และ stderr คือจอภาพเหมือนกัน จึงไม่เห็นความแตกต่าง แต่หากคำสั่งนี้ไปอยู่ในสคริปต์ที่เรากำหนดให้ stderr เป็นไฟล์ error-log การแสดงผลก็จะถูกเปลี่ยนทิศไปตามนั้น
3.5 ตัวอย่างเปลี่ยน stderr ไปเป็น stdout
$ grep da * 2>&1เป็นการค้นหาข้อความ
da
ในทุกไฟล์ (*) โดยหากเกิดข้อผิดพลาดขึ้น จะแสดงผลข้อผิดพลาดออกมาทาง stdout ซึ่งในที่นี้คือจอภาพเหมือนกัน
3.6 ตัวอย่างเปลี่ยน stderr และ stdout ไปยัง file
$ rm -f $(find /home/USER -name core) &> /dev/nullคำสั่งนี้เป็นการค้นหาไฟล์ในไดเรคทอรี่
/home/USER
ที่มีชื่อว่า core (find /home/USER -name core
)
เมื่อพบแล้วก็จัดการลบทิ้งโดยไม่เตือน (rm -f
)
โดยโยกการแสดงผลทั้งหมด (ทั้ง stderr และ stdout – ใช้สัญญลักษณ์&>
) ไปยังไฟล์ชื่อ/dev/null
ซึ่งเป็นไฟล์พิเศษ หมายความว่ายกเลิกการแสดงผลทั้งหมด
(คำสั่งนี้ค่อนข้างอันตราย เพราะลบโดยไม่เตือน โปรดทดลองด้วยความระมัดระวังครับ)4. การส่งต่อผลลัพธ์ หรือ ไปป์ (Pipes)
4.1 ความหมาย
ไปป์เป็นการส่งต่อผลลัพธ์จากคำสั่งหนึ่งไปเป็นค่านำเข้าของอีกคำสั่งหนึ่ง
4.2 ตัวอย่างไปป์
$ ls -l | sed -e "s/[aeio]/u/g"ตัวอย่างนี้จะนำเอาผลลัพธ์ที่ได้จากคำสั่ง
ls -l
ส่งต่อไปให้คำสั่งsed -e "s/[aeio]/u/g"
ซึ่งจะแปลงการแสดงผลจากอักขระ a หรือ e หรือ i หรือ o ไปเป็นอักขระ u ทั้งหมดเราอาจเขียนคำสั่งเทียบเท่าได้ดังนี้
$ ls -l > temp.txt $ sed -e "s/[aeio]/u/g" temp.txt $ rm temp.txtจะเห็นว่าการทำไปป์ ลดขั้นตอนไปมาก คงเหลือเพียงบรรทัดเดียว
4.3 ตัวอย่างไปป์ที่สอง
$ ls -l | grep "\.txt$"ตัวอย่างนี้จะส่งผลลัพธ์จากคำสั่ง
ls -l
ต่อไปให้คำสั่งgrep "\.txt$"
คือให้แสดงเฉพาะไฟล์ที่มีนามสกุลเป็น.txt
เท่านั้น
มีค่าเท่ากับคำสั่ง ls แบบใส่พารามิเตอร์กรอง$ ls -l *.txtหมายเหตุ
รูปแบบ"\.txt$"
เป็นรูปแบบของ Regular Expression ซึ่งใช้มากในเชลล์สคริปต์ มีความหมายว่า “ที่ต้องลงท้ายด้วย .txt”5. ตัวแปร (Variables)
ตัวแปรในเชลล์สคริปต์ ไม่มีชนิดข้อมูล คือเราสามารถใช้ตัวแปรแทนตัวเลขหรืออักขระใด ๆ ก็ได้
โดยในขั้นตอนกำหนดค่า ไม่ต้องใช้เครื่องหมายใด ๆ นำหน้า แต่ตอนอ้างถึง ต้องใช้เครื่องหมาย$
นำหน้าตัวแปร
5.1 ตัวอย่างสคริปต์ Hello World แบบใช้ตัวแปร
#!/bin/bash STR="Hello World!" echo $STRให้ผลลัพธ์เหมือนตัวอย่างที่ 2.1
ข้อควรระวังคือ
- การกำหนดค่าให้ตัวแปร อย่าเว้นวรรคระหว่างตัวแปรกับเครื่องหมาย
=
- หากลืมใส่เครื่องหมาย
$
จะหมายถึงการแสดงผลข้อความว่าSTR
เฉย ๆ
5.2 ตัวอย่างสคริปต์สำรองข้อมูลแบบใช้ตัวแปร
#!/bin/bash OF=/tmp/my-backup-$(date +%Y%m%d).tgz tar -cvzf $OF /home/USER/ให้ผลลัพธ์คล้ายตัวอย่าง 2.2 แต่เพิ่มการใช้ตัวแปรลอยในคำสั่ง
$(date +%Y%m%d)
ซึ่งมีผลทำให้ชื่อไฟล์ข้อมูลสำรองมีวันที่ต่อท้ายชื่อด้วย
5.3 ตัวแปรท้องถิ่น
ตัวแปรในเชลล์สคริปต์ทุกตัว จะเป็นตัวแปรรวม (Global) คือทุก ๆ ส่วนของโปรแกรมจะเห็นเหมือนกันหมด
แต่ในกรณีที่เราต้องการให้เห็นเฉพาะในฟังก์ชั่นที่เราต้องการ เราสามารถกำหนดให้ตัวแปรเป็นตัวแปรท้องถิ่นได้ด้วยคำสั่งlocal
เช่น#!/bin/bash HELLO=Hello function hello { local HELLO=World echo $HELLO }echo $HELLO
hello
echo $HELLOสคริปต์นี้ตัวแปร
HELLO
ในโปรแกรมหลัก กับในฟังก์ชั่นจะเป็นตัวแปรคนละตัวกัน6. ประโยคเงื่อนไข
6.1 รูปแบบ
มีรูปแบบคือ
if [EXPRESSION]; then CODE IF 'EXPRESSION' IS TRUE. [elif [EXPRESSION-ELIF]; then CODE IF 'EXPRESSION-ELIF' IS TRUE.] [else CODE IF NOTHING IS TRUE.] fi
6.2 ตัวอย่าง
if ... then
#!/bin/bash if [ "foo" = "foo" ]; then echo expression evaluated as true fiโค๊ดนี้จะเป็นจริงเสมอ ดังนั้นข้อความ “
expression evaluated as true
” จะถูกพิมพ์ออกมาเสมอ
6.3 ตัวอย่าง
if ... then ... else
#!/bin/bash if [ "foo" = "foo" ]; then echo expression evaluated as true else echo expression evaluated as false fiโค๊ดนี้จะเป็นจริงเสมอ ดังนั้นข้อความ “
expression evaluated as true
” จะถูกพิมพ์ออกมาเสมอ
6.4 ตัวอย่างแบบใช้ตัวแปร
#!/bin/bash T1="foo" T2="bar" if [ "$T1" = "$T2" ]; then echo expression evaluated as true else echo expression evaluated as false fiตัวอย่างนี้จะเป็นเท็จเสมอ
สังเกตุการใช้ตัวแปรในการเปรียบเทียบ ควรให้ตัวแปรอยู่ในเครื่องหมายคำพูดเสมอ เพื่อป้องการการผิดพลาดจากการแทนค่าที่ซับซ้อน หรือการที่มีช่องว่างในค่าตัวแปร7.การวนรอบ โดยใช้คำสั่ง for, while และ until
คำสั่ง
for
มีลักษณะคล้าย for ในภาษาไพธอน มีรูปแบบเป็นfor VAR in SCOPE; do COMMAND doneคำสั่ง
while
มีรูปแบบเป็นwhile [CONDITION]; do COMMAND doneถ้าเงื่อนไข CONDITION เป็นจริง ก็จะทำคำสั่ง COMMAND คำสั่ง
until
รูปแบบตรงกันข้ามกับ while โดยมีรูปแบบเป็นuntil [CONDITION]; do COMMAND doneคือจะทำคำสั่ง COMMAND จนกว่าเงื่อนไข CONDITION จะเป็นจริง
7.1 ตัวอย่าง
for
#!/bin/bash for i in $( ls ); do echo item: $i doneเป็นการนำคำสั่ง
ls
ไปเป็นตัวแปรชั่วคราวในการกำหนดขอบเขตให้กับตัวแปรi
ในคำสั่งfor
ในที่นี้จะทำการแสดงผลว่าitem: FILENAME ...
7.2 ตัวอย่าง
for
อีกแบบ#!/bin/bash for i in `seq 1 10`; do echo $i doneเป็นการนำผลจากคำสั่ง
seq 1 10
ไปกำหนดขอบเขตให้กับตัวแปรi
ในคำสั่งfor
อาจเขียนเลียนแบบตัวอย่าง 7.1 ได้เหมือนกันดังนี้#!/bin/bash for i in $( seq 1 10 ); do echo $i done7.3 ตัวอย่าง
while
#!/bin/bash COUNTER=0 while [ $COUNTER -lt 10 ]; do echo The counter is $COUNTER let COUNTER=COUNTER+1 doneเป็นการแสดงค่าตัวแปร
COUNTER
ที่เพิ่มขึ้นทีละ 1 จาก 0 ถึง 9 โปรดสังเกตุการใช้ตัวแปรเก็บค่าตัวเลข, การเปรียบเทียบตัวเลขโดยใช้ตัวเปรียบเทียบ-lt
(less than) และการกำหนดเพิ่มค่าให้กับตัวแปรแบบตัวเลขโดยใช้คำสั่งlet
7.4 ตัวอย่าง
until
#!/bin/bash COUNTER=20 until [ $COUNTER -lt 10 ]; do echo COUNTER $COUNTER let COUNTER-=1 doneจะแสดงตัวเลขตั้งแต่ 20 ลดลงทีละ 1 จนถึง 10
8.ฟังก์ชั่น (functions)
ในการใช้งานเชลล์สคริปต์แบบจริงจัง เราจำเป็นต้องเขียนฟังก์ชั่นเพื่อประโยชน์ในการเรียกใช้งานแบบซ้ำ ๆ เพื่อให้ประหยัดการเขียนโค๊ด และให้โค๊ดดูง่าย
มีรูปแบบเป็นfunction FUNCTION_NAME { COMMAND }หรือ
FUNCTION_NAME () { COMMAND }โปรแกรมจะเว้นไม่ถูกเรียกทำงานในช่วงตั้งแต่ชื่อฟังก์ชั่นจนกระทั่งจบบล๊อก
{ COMMAND }
เรานิยมวางฟังก์ชั่นไว้ที่ต้นโปรแกรม เพื่อให้สามารถถูกเรียกจากโค๊ดหลักได้
8.1 ตัวอย่างฟังก์ชั่น
#!/bin/bash function quit { exit } function hello { echo Hello! } hello quit echo fooตัวอย่างนี้ บรรทัดที่ 10 คือคำสั่ง
echo foo
จะไม่ถูกเรียกใช้ เนื่องจากโปรแกรมจะหลุดสู่เชลล์ในบรรทัดที่ 9 คือคำสั่งquit
8.2 ตัวอย่างฟังก์ชั่นที่มีการส่งผ่านค่าตัวแปร
#!/bin/bash function quit { exit } function ex { echo $1 } ex Hello ex World quit echo fooจากตัวอย่าง จะเห็นการส่งผ่านข้อความเข้าไปในฟังก์ชั่น
ex
ด้วยตัวแปร$1
ในทำนองเดียวกัน ถ้ามีการส่งผ่านตัวแปรหลายตัว ก็จะใช้รูปแบบเป็น$2, $3, ...
โดยเรียกใช้งานด้วยรูปแบบex VAR1 VAR2 VAR3 ...
ตามลำดับ9.การติดต่อผู้ใช้ (User Interfaces)
9.1 ใช้คำสั่ง
select
ในการสร้างหัวข้อให้เลือก#!/bin/bash OPTIONS="Hello Quit" select opt in $OPTIONS; do if [ "$opt" = "Quit" ]; then echo done exit elif [ "$opt" = "Hello" ]; then echo Hello World else clear echo bad option fi doneตัวอย่างนี้จะสร้างหัวข้อ 1) และ 2) จากตัวแปร
OPTIONS
เพื่อมาให้เลือก โดยจะวนรอบถามไปเรื่อย ๆ จนกว่าจะพบคำสั่งexit
ให้ออกจากการวนรอบ
9.2 ใช้การตรวจสอบว่ามีการใส่ค่าพารามิเตอร์หรือไม่
#!/bin/bash if [ -z "$1" ]; then echo usage: $0 directory exit fi SRCD=$1 TGTD="/var/backups/" OF=home-$(date +%Y%m%d).tgz tar -cZf $TGTD$OF $SRCDบรรทัดที่ 2 จะตรวจว่ามีการใส่พารามิเตอร์ให้กับโปรแกรมหรือไม่ (
if [ -z "$1" ]
-z หมายถึงการตรวจสอบว่ามีค่าหรือไม่)
ถ้าไม่มีการใส่ค่าพารามิเตอร์ โปรแกรมจะทำคำสั่งในบรรทัดที่ 3 คือแสดงการใช้งาน ($0
คือชื่อโปรแกรมนี้) และบรรทัดที่ 4 คือออกจากโปรแกรม
แต่ถ้ามีการใส่ค่าพารามิเตอร์ถูกต้อง ก็จะทำบรรทัดที่ 6 ต่อไปจนจบ ซึ่งในที่นี้คือการบีบอัดทำสำเนาให้กับไดเรกทอรี่ที่เราให้เป็นพารามิเตอร์ ($1
) ในชื่อไฟล์ว่า/var/backups/home-YYYYMMDD
9.3 หยุดถามผู้ใช้ด้วยคำสัง
read
#!/bin/bash echo Please, enter your name read NAME echo "Hi $NAME!"สังเกตุการใช้คำสั่ง
read
กำหนดค่าให้ตัวแปรNAME
ไม่ต้องใช้เครื่องหมาย$
นำหน้าตัวแปรอาจรอรับค่าทีละหลายตัวแปรได้ด้วย โดยคั่นแต่ละตัวแปรด้วยช่องว่าง
#!/bin/bash echo Please, enter your firstname and lastname read FN LN echo "Hi! $LN, $FN !"10.เกร็ดอื่น ๆ
10.1 การสั่งรันสคริปต์และคำสั่งsource
การสั่งรันสคริปต์ในเชลล์ มีเกร็ดคือ
- ถ้าเราใส่ชื่อสคริปต์พร้อมพาธ เชลล์จะค้นหาสคริปต์จากชื่อเต็มที่เราใส่ เช่น
$ /bin/ls- ถ้าเราใส่ชื่อสคริปต์โดด ๆ เชลล์จะค้นหาสคริปต์จากตัวแปร
$PATH
โดยไม่สนใจไดเรคทอรี่ปัจจุบัน เช่น$ mycodeหากค้นไม่พบ จะแสดงข้อผิดพลาด
แต่หากต้องการสั่งรันสคริปต์ในไดเรคทอรี่ปัจจุบัน เราต้องใช้คำสั่งอ้างอิงคือ$ ./mycodeเมื่อสคริปต์ถูกรันจนจบแล้ว ค่าของตัวแปรต่าง ๆ ในสคริปต์จะถูกลบไปด้วย ยกเว้นถ้าเราใช้คำสั่ง
source
หรือคำสั่ง.
เชลล์จะรันคำสั่งนั้นโดยถือเสมือนเป็นสภาพแวดล้อมเดียวกัน ดังนั้นค่าตัวแปรต่าง ๆ ในสคริปต์จะยังคงค้างอยู่ในเชลล์
โดยเมื่อใช้คำสั่งนี้แล้ว การค้นหาสคริปต์ เชลล์จะค้นหาจากตัวแปร$PATH
ก่อน ตามด้วยไดเรคทอรี่ปัจจุบันด้วย
เช่น ถ้าสคริปต์ mycode มีเนื้อไฟล์เป็น#!/bin/bash ABC="This is new ABC"ทดลองรันได้ดังนี้
$ ABC="Old ABC" $ echo $ABC Old ABC $ ./mycode $ echo $ABC Old ABC $ . mycode $ echo $ABC This is new ABC
10.2 การแทนค่าตัวเลข
เราใช้
$((ARITHMATIC))
หรือ$[ARITHMATIC]
ในการแทนค่าตัวแปร
ดังนี้$ echo $(1+1) bash: 1+1: command not found$ echo 1+1
1+1
$ echo $((1+1))
2
$ echo $[1+1]
2
10.3 bash อยู่ที่ไหน
บรรทัดเริ่มต้นของสคริปต์ หลังเครื่องหมาย
#!
(hash-bang) เราต้องใส่พาธของโปรแกรม bash ให้เต็ม
สำหรับเดเบียน อยู่ที่/bin/bash
อยู่แล้ว แต่หากเป็นดิสโตรอื่น อาจค้นหาว่าโปรแกรม bash อยู่ที่ไหน โดยใช้คำสั่งเหล่านี้$ which bash $ whereis bash $ find / -name bash
10.4 ดูค่าที่โปรแกรมส่งออกมา
หลายโปรแกรมของเชลล์มีการส่งค่าออกมา (Return value) อาจเพื่อแจ้งสถานะการรันว่ารันสำเร็จหรือไม่อย่างไร หรืออาจส่งออกเป็นค่าที่จะนำไปประมวลผลต่อก็ตาม เราสามารถใช้ตัวแปรพิเศษ
$?
ในการดูผลลัพธ์ของโปรแกรมได้
เช่น#!/bin/bash cd /dada &> /dev/null echo rv: $? cd $(pwd) &> /dev/null echo rv: $?กรณีนี้ ไดเรคทอรี่
/dada
เป็นไดเรคทอรี่ที่เราแกล้งพิมพ์ผิดไว้ เพื่อดูว่าสคริปต์จะส่งออกค่าออกมาเป็นอย่างไร ซึ่งจะได้ผลออกมาเป็น 1 และ 0 ตามลำดับ คือ 1 หมายถึงมีข้อผิดพลาดในโปรแกรม และ 0 หมายถึงรันสำเร็จ ไม่มีข้อผิดพลาดใด ๆ
10.5 จับการแสดงผลใส่ตัวแปร
เราสามารถนำผลลัพธ์ของโปรแกรมมาใส่ในตัวแปร ด้วยการสั่งภายใต้เครื่องหมาย
`
(grave accent)
เช่น#!/bin/bash DBS=`mysql -u root -e "show databases"` for b in $DBS ; do mysql -u root -e "show tables from $b" doneเป็นการนำผลลัพธ์ของคำสั่งแรกคือ
mysql -u root -e "show databases"
มาใส่ในตัวแปรDBS
เพื่อทำเป็นขอบเขตให้กับตัวแปรb
ในคำสั่งfor
อีกครั้งหนึ่ง
ตามตัวอย่างจะแสดงผลทุกตารางในทุกฐานข้อมูลของ mysql11. ตัวดำเนินการ (operators) และคำสั่งน่าสนใจ
11.1 ตัวดำเนินการเปรียบเทียบตัวอักษร (String comparison operators)
[ "$s1" = "$s2" ]
หรือ[ "$s1" == "$s2" ]
เป็นจริง ถ้า s1 เท่ากับ s2[ "$s1" != "$s2" ]
เป็นจริง ถ้า s1 ไม่เท่ากับ s2[[ "$s1" < "$s2" ]]
หรือ[ "$s1" \< "$s2" ]
เป็นจริง ถ้า s1 น้อยกว่า s2[[ "$s1" > "$s2" ]]
หรือ[ "$s1" \> "$s2" ]
เป็นจริง ถ้า s1 มากกว่า s2[ -n "$s1" ]
เป็นจริง ถ้า s1 มีค่าใด ๆ[ -z "$s1" ]
เป็นจริง ถ้า s1 ไม่มีค่า
11.2 ตัวอย่างการเปรียบเทียบอักษร
#!/bin/bash S1='string' S2='String' if [ "$S1"="$S2" ]; then echo "S1('$S1') is not equal to S2('$S2')" fi if [ "$S1"="$S1" ]; then echo "S1('$S1') is equal to S1('$S1')" fi
11.3 ตัวดำเนินการทางคณิตศาลตร์ (Arithmetic operators)
+
การบวก-
การลบ*
การคูณ/
การหาร%
การหาเศษจากตัวหาร (remainder)
11.4 ตัวเปรียบเทียบทางคณิตศาตร์ (Arithmetic relational operators
-lt
น้อยกว่า (<)-gt
มากกว่า (>)-le
น้อยกว่าหรือเท่ากับ (<=)-ge
มากกว่าหรือเท่ากับ (>=)-eq
เท่ากับ (==)-ne
ไม่เท่ากับ (!=)
11.5 คำสั่งควรรู้
sed (stream editor)
sed
เป็นเอดิเตอร์แบบบรรทัดคำสั่ง มีการใช้งานที่พลิกแพลงหลากหลายมาก ตัวอย่าง$ sed 's/old/new/g' /tmp/dummyนำเอาเนื้อไฟล์
/tmp/dummy
มาแทนที่old
ด้วยnew
และแสดงออกทางจอภาพ$ sed 12,18d /tmp/dummyนำเอาเนื้อไฟล์
/tmp/dummy
มาแสดงทางจอภาพ โดยเว้นไม่แสดงบรรทัดที่ 12 ถึงบรรทัดที่ 18ดูรายละเอียดเพิ่มเติมได้ที่ gentoo: Sed by example
awk (manipulation of datafiles, text retrieval and processing)
awk
เป็นทั้งโปรแกรมและภาษาในการค้นหาข้อความในไฟล์จากรูปแบบที่เรากำหนดให้
สมมุติว่าไฟล์/tmp/dummy
มีเนื้อไฟล์คือtest123 test tteessttตัวอย่างการใช้งานคือ
$ awk '/test/ {print}' /tmp/dummy test123 testดูรายละเอียดเพิ่มเติมได้ที่ gentoo: Awk by example
grep (print lines matching a search pattern)
grep
เป็นโปรแกรมที่ใช้บ่อยในการค้นข้อความในไฟล์ และยังมีความสามารถในการสรุปผลการนับข้อความด้วย
ตัวอย่าง$ man grep | grep "standard" -c 8เป็นการค้นคำว่า standard ในการแสดงผลของคำสั่ง
man grep
ว่ามีอยู่กี่คำ คำตอบคือ 8ดูตัวอย่างเพิ่มเติมที่ tdlp: Examples using grep
wc (counts lines, words and bytes)
wc
ใช้ในการนับคำ, นับบรรทัด และนับจำนวนหน่วยความจำที่ถูกใช้ในไฟล์ เป็นไบต์
ตัวอย่าง$ wc --words --lines --bytes /tmp/dummy 3 3 22 /tmp/dummy
sort (sort lines of text files)
sort
ใช้จัดเรียงข้อมูล
สมมุติว่าไฟล์ /tmp/dummy มีเนื้อว่าb c aตัวอย่างคำสั่งคือ
$ sort /tmp/dummy a b cคือการนำเอาเนื้อไฟล์
/tmp/dummy
มาจัดเรียง และแสดงผลออกทางจอภาพ
bc (a calculator programming language)
bc
เป็นเครื่องคิดเลขแบบใช้บรรทัดคำสั่ง
ตัวอย่างเช่น$ echo 1+1 1+1 $ echo 1+1 | bc 2หรือใช้แบบโต้ตอบ
$ bc -q 1 == 5 00.05 == 0.05 1
5 != 5 0
2 ^ 8 256
sqrt(9) 3
while (i != 9) { i = i + 1; print i } 123456789
quit
tput (initialize a terminal or query terminfo database)
tput
ใช้ในการตั้งค่าหรือแสดงค่าต่าง ๆ ของเทอร์มินัล
เช่น$ tput cup 10 4เลื่อนเคอร์เซอร์ไปยังบรรทัดที่ 10 สดมภ์ที่ 4
$ tput resetล้างจอภาพ มีค่าเท่ากับคำสั่ง
clear
$ tput colsแสดงจำนวนสดมภ์ (ความกว้าง) ของจอเทอร์มินัล
12.ตัวอย่างสคริปต์
12.1 ตัวอย่างสคริปต์ดูรายชื่อไฟล์ในไดเรคทอรี่ย่อย
#!/bin/bash function listdir { local PAT="$1" local ROOT="$2" for i in *; do if [ -d "$i" ]; then local CUR="$ROOT/$i" pushd "$i" &>/dev/null listdir "$PAT" "$CUR" popd &>/dev/null fi done if [ ! -z "$( ls -d $PAT 2>/dev/null )" ]; then echo "Directory: $ROOT" ls -d $PAT 2>/dev/null echo fi }if [ -z “$1” ]; then
echo List file in PATTERN recursive into directories.
echo Usage: $0 “PATTERN”
exit
fi
PATTERN=”$1″
echo “List $PATTERN”
listdir “$PATTERN” “.”ให้ผลคล้ายคำสั่ง
$ find * -name PATTERN
12.2 ตัวอย่างสคริปต์บีบอัดสำรองข้อมูล
#!/bin/bash SRCD="/home/" TGTD="/var/backups/" OF=home-$(date +%Y%m%d).tgz tar -cZf $TGTD$OF $SRCD
12.3 เปลี่ยนชื่อไฟล์ทีละหลายไฟล์
#!/bin/sh # renna: rename multiple files according to several rules # written by felix hudson Jan - 2000#first check for the various ‘modes’ that this program has
#if the first ($1) condition matches then we execute that portion of the
#program and then exit# check for the prefix condition
if [ $1 = p ]; then#we now get rid of the mode ($1) variable and prefix ($2)
prefix=$2 ; shift ; shift# a quick check to see if any files were given
# if none then its better not to do anything than rename some non-existent
# files!!if [$1 = ]; then
echo “no files given”
exit 0
fi# this for loop iterates through all of the files that we gave the program
# it does one rename per file given
for file in $*
do
mv ${file} $prefix$file
done#we now exit the program
exit 0
fi# check for a suffix rename
# the rest of this part is virtually identical to the previous section
# please see those notes
if [ $1 = s ]; then
suffix=$2 ; shift ; shiftif [$1 = ]; then
echo “no files given”
exit 0
fifor file in $*
do
mv ${file} $file$suffix
doneexit 0
fi# check for the replacement rename
if [ $1 = r ]; thenshift
# i included this bit as to not damage any files if the user does not specify
# anything to be done
# just a safety measureif [ $# -lt 3 ] ; then
echo “usage: renna r [expression] [replacement] files… ”
exit 0
fi# remove other information
OLD=$1 ; NEW=$2 ; shift ; shift# this for loop iterates through all of the files that we give the program
# it does one rename per file given using the program ‘sed’
# this is a sinple command line program that parses standard input and
# replaces a set expression with a give string
# here we pass it the file name ( as standard input) and replace the nessesary
# textfor file in $*
do
new=`echo ${file} | sed s/${OLD}/${NEW}/g`
mv ${file} $new
done
exit 0
fi# if we have reached here then nothing proper was passed to the program
# so we tell the user how to use it
echo “usage;”
echo ” renna p [prefix] files..”
echo ” renna s [suffix] files..”
echo ” renna r [expression] [replacement] files..”
exit 0# done!
12.4 เปลี่ยนชื่อไฟล์แบบง่าย
#!/bin/bash # renames.sh # basic file renamercriteria=$1
re_match=$2
replace=$3for i in $( ls *$criteria* );
do
src=$i
tgt=$(echo $i | sed -e “s/$re_match/$replace/”)
mv $src $tgt
done13. การค้นหาที่ผิดในสคริปต์
เราใช้พารามิเตอร์
-x
ต่อท้ายคำสั่งในบรรทัดแรก#!/bin/bash -xจะมีผลว่าเชลล์จะแสดงทุกคำสั่งที่ถูกรันออกมาทางจอภาพ
จบแล้วจ้า