ขออนุญาตเขียนแบบกองโจรนะครับ โดยมือใหม่ เพื่อมือใหม่ครับ
เอามาจาก tldp: BASH Programming - Introduction HOW-TO
ศึกษาเพิ่มเติมได้จาก tldp: Bash Guide for Beginners
และในเชิงลึก จาก tldp: Advanced Bash-Scripting Guide
เชลล์สคริปต์ พูดง่าย ๆ ก็คือการนำคำสั่งในเชลล์ของลินุกซ์มาเรียงต่อกันให้ทำงานตามที่เราต้องการ โดยเพิ่มโครงสร้างการวนรอบ และฟังก์ชั่นต่าง ๆ เติมเข้ามา เพื่อให้การทำงานได้ตามที่เราต้องการ ซึ่งจะเหมาะมากกับงานแบบ batch หรืองานแบบ schedule
ฉะนั้นการที่จะเขียนโค๊ดให้ได้ดี จึงต้องศึกษาจดจำคำสั่งต่าง ๆ ของเชลล์ให้ได้เท่าที่เราต้องการใช้งาน (จำหมดคงไม่ไหว)
คำสั่งต่าง ๆ สามารถดูได้ที่ gnu.org: Bash Reference Manual
สำหรับเดเบียน หากต้องการใช้งาน bash แบบเต็มรูป (ไม่อั้นความสามารถ) อาจต้องปรับแต่งเล็กน้อย
เปลี่ยนให้เชลล์ของเราเป็น bash แทน sh ใช้คำสั่ง
$ chsh -s /bin/bash
สำหรับเอดิเตอร์ ถ้าใช้ vi ควรติดตั้ง vim-full และอย่าลืมแก้ไขไฟล์ vimrc ให้แสดงสีด้วย เพื่อให้ดูโค๊ดได้ง่ายขึ้น
$ sudo aptitude install vim-full $ vi ~/.vimrc
syntax on
:wq
สมมุติตั้งชื่อสคริปต์ว่า 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
ออกทางจอภาพ
จากตัวอย่างข้างบน ผมเขียนอธิบายโดยละเอียดโดยใช้เอดิเตอร์ vi แต่เพื่อให้กระชับเข้า จะขอละเลยการใช้เอดิเตอร์ โดยจะเขียนเฉพาะโค๊ดอย่างเดียวครับ
#!/bin/bash tar -cvzf /tmp/my-backup.tgz /home/USER/
บรรทัดที่สองให้เปลี่ยนคำว่า USER เป็นชื่อเรา
เป็นการสั่งให้ใช้คำสั่ง tar ทำการสำรองข้อมูลพร้อมบีบอัดข้อมูลในไดเรคทอรี่ของบ้านเราไปสู่ไฟล์ชื่อ /tmp/my-backup.tgz
ใช้สัญญลักษณ์ >
ใสการเปลี่ยนทิศ
ข้อมูลมาตรฐานในเชลล์จะมีอยู่ 4 ชนิด คือข้อมูลเข้า(stdin), ข้อมูลแสดงผล(stdout), ข้อมูลข้อผิดพลาด(stderr), และแฟ้มข้อมูล(file)
ในทางปฏิบัติ เราสามารถเปลี่ยนทิศทางของข้อมูลเหล่านี้ไปมาได้ โดยมีมาตรฐานคือ 1 จะหมายถึงข้อมูลแสดงผล(stdout) และ 2 จะหมายถึงข้อมูลความผิดพลาด(stderr)
เช่น
$ ls -l > ls-l.txt
จะเปลี่ยนการแสดงผลของคำสั่ง ls -l
ไปเก็บไว้ที่ไฟล์ชื่อ ls-l.txt ดังนั้นคำสั่งตามตัวอย่างนี้จะไม่แสดงอะไรออกมาทางจอภาพ แต่จะเก็บไว้ที่ไฟล์แทน หากเราต้องการดูผล สามารถใช้คำสั่งแสดงผลของไฟล์ได้คือ
$ cat ls-l.txt
$ grep da * 2> grep-errors.txt
ตัวอย่างนี้เป็นการค้นหาข้อความ da
ในทุกไฟล์ (*) และหากเกิดข้อผิดพลาดขึ้น จะนำข้อความผิดพลาดไปเก็บไว้ที่ไฟล์ชื่อ grep-errors.txt
$ grep da * 1>&2
เป็นการค้นหาข้อความ da
ในทุกไฟล์ (*) โดยนำการแสดงผลไปใส่ไว้ใน stderr แทนการแสดงผลปกติ แต่ในกรณีนี้เราป้อนคำสั่งทางแป้นพิมพ์ stdout และ stderr คือจอภาพเหมือนกัน จึงไม่เห็นความแตกต่าง แต่หากคำสั่งนี้ไปอยู่ในสคริปต์ที่เรากำหนดให้ stderr เป็นไฟล์ error-log การแสดงผลก็จะถูกเปลี่ยนทิศไปตามนั้น
$ grep da * 2>&1
เป็นการค้นหาข้อความ da
ในทุกไฟล์ (*) โดยหากเกิดข้อผิดพลาดขึ้น จะแสดงผลข้อผิดพลาดออกมาทาง stdout ซึ่งในที่นี้คือจอภาพเหมือนกัน
$ rm -f $(find /home/USER -name core) &> /dev/null
คำสั่งนี้เป็นการค้นหาไฟล์ในไดเรคทอรี่ /home/USER
ที่มีชื่อว่า core (find /home/USER -name core
)
เมื่อพบแล้วก็จัดการลบทิ้งโดยไม่เตือน (rm -f
)
โดยโยกการแสดงผลทั้งหมด (ทั้ง stderr และ stdout - ใช้สัญญลักษณ์ &>
) ไปยังไฟล์ชื่อ /dev/null
ซึ่งเป็นไฟล์พิเศษ หมายความว่ายกเลิกการแสดงผลทั้งหมด
(คำสั่งนี้ค่อนข้างอันตราย เพราะลบโดยไม่เตือน โปรดทดลองด้วยความระมัดระวังครับ)
ไปป์เป็นการส่งต่อผลลัพธ์จากคำสั่งหนึ่งไปเป็นค่านำเข้าของอีกคำสั่งหนึ่ง
$ 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
จะเห็นว่าการทำไปป์ ลดขั้นตอนไปมาก คงเหลือเพียงบรรทัดเดียว
$ ls -l | grep "\.txt$"
ตัวอย่างนี้จะส่งผลลัพธ์จากคำสั่ง ls -l
ต่อไปให้คำสั่ง grep "\.txt$"
คือให้แสดงเฉพาะไฟล์ที่มีนามสกุลเป็น .txt
เท่านั้น
มีค่าเท่ากับคำสั่ง ls แบบใส่พารามิเตอร์กรอง
$ ls -l *.txt
หมายเหตุ
รูปแบบ "\.txt$"
เป็นรูปแบบของ Regular Expression ซึ่งใช้มากในเชลล์สคริปต์ มีความหมายว่า "ที่ต้องลงท้ายด้วย .txt"
ตัวแปรในเชลล์สคริปต์ ไม่มีชนิดข้อมูล คือเราสามารถใช้ตัวแปรแทนตัวเลขหรืออักขระใด ๆ ก็ได้
โดยในขั้นตอนกำหนดค่า ไม่ต้องใช้เครื่องหมายใด ๆ นำหน้า แต่ตอนอ้างถึง ต้องใช้เครื่องหมาย $
นำหน้าตัวแปร
#!/bin/bash STR="Hello World!" echo $STR
ให้ผลลัพธ์เหมือนตัวอย่างที่ 2.1
ข้อควรระวังคือ
=
$
จะหมายถึงการแสดงผลข้อความว่า STR
เฉย ๆ#!/bin/bash OF=/tmp/my-backup-$(date +%Y%m%d).tgz tar -cvzf $OF /home/USER/
ให้ผลลัพธ์คล้ายตัวอย่าง 2.2 แต่เพิ่มการใช้ตัวแปรลอยในคำสั่ง $(date +%Y%m%d)
ซึ่งมีผลทำให้ชื่อไฟล์ข้อมูลสำรองมีวันที่ต่อท้ายชื่อด้วย
ตัวแปรในเชลล์สคริปต์ทุกตัว จะเป็นตัวแปรรวม (Global) คือทุก ๆ ส่วนของโปรแกรมจะเห็นเหมือนกันหมด
แต่ในกรณีที่เราต้องการให้เห็นเฉพาะในฟังก์ชั่นที่เราต้องการ เราสามารถกำหนดให้ตัวแปรเป็นตัวแปรท้องถิ่นได้ด้วยคำสั่ง local
เช่น
#!/bin/bash HELLO=Hello function hello { local HELLO=World echo $HELLO } echo $HELLO hello echo $HELLO
สคริปต์นี้ตัวแปร HELLO
ในโปรแกรมหลัก กับในฟังก์ชั่นจะเป็นตัวแปรคนละตัวกัน
มีรูปแบบคือ
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
if ... then
#!/bin/bash if [ "foo" = "foo" ]; then echo expression evaluated as true fi
โค๊ดนี้จะเป็นจริงเสมอ ดังนั้นข้อความ "expression evaluated as true
" จะถูกพิมพ์ออกมาเสมอ
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
" จะถูกพิมพ์ออกมาเสมอ
#!/bin/bash T1="foo" T2="bar" if [ "$T1" = "$T2" ]; then echo expression evaluated as true else echo expression evaluated as false fi
ตัวอย่างนี้จะเป็นเท็จเสมอ
สังเกตุการใช้ตัวแปรในการเปรียบเทียบ ควรให้ตัวแปรอยู่ในเครื่องหมายคำพูดเสมอ เพื่อป้องการการผิดพลาดจากการแทนค่าที่ซับซ้อน หรือการที่มีช่องว่างในค่าตัวแปร
คำสั่ง 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 จะเป็นจริง
for
#!/bin/bash for i in $( ls ); do echo item: $i done
เป็นการนำคำสั่ง ls
ไปเป็นตัวแปรชั่วคราวในการกำหนดขอบเขตให้กับตัวแปร i
ในคำสั่ง for
ในที่นี้จะทำการแสดงผลว่า item: FILENAME ...
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 done
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
until
#!/bin/bash COUNTER=20 until [ $COUNTER -lt 10 ]; do echo COUNTER $COUNTER let COUNTER-=1 done
จะแสดงตัวเลขตั้งแต่ 20 ลดลงทีละ 1 จนถึง 10
ในการใช้งานเชลล์สคริปต์แบบจริงจัง เราจำเป็นต้องเขียนฟังก์ชั่นเพื่อประโยชน์ในการเรียกใช้งานแบบซ้ำ ๆ เพื่อให้ประหยัดการเขียนโค๊ด และให้โค๊ดดูง่าย
มีรูปแบบเป็น
function FUNCTION_NAME { COMMAND }
หรือ
FUNCTION_NAME () { COMMAND }
โปรแกรมจะเว้นไม่ถูกเรียกทำงานในช่วงตั้งแต่ชื่อฟังก์ชั่นจนกระทั่งจบบล๊อก { COMMAND }
เรานิยมวางฟังก์ชั่นไว้ที่ต้นโปรแกรม เพื่อให้สามารถถูกเรียกจากโค๊ดหลักได้
#!/bin/bash function quit { exit } function hello { echo Hello! } hello quit echo foo
ตัวอย่างนี้ บรรทัดที่ 10 คือคำสั่ง echo foo
จะไม่ถูกเรียกใช้ เนื่องจากโปรแกรมจะหลุดสู่เชลล์ในบรรทัดที่ 9 คือคำสั่ง quit
#!/bin/bash function quit { exit } function ex { echo $1 } ex Hello ex World quit echo foo
จากตัวอย่าง จะเห็นการส่งผ่านข้อความเข้าไปในฟังก์ชั่น ex
ด้วยตัวแปร $1
ในทำนองเดียวกัน ถ้ามีการส่งผ่านตัวแปรหลายตัว ก็จะใช้รูปแบบเป็น $2, $3, ...
โดยเรียกใช้งานด้วยรูปแบบ ex VAR1 VAR2 VAR3 ...
ตามลำดับ
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
ให้ออกจากการวนรอบ
#!/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
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.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
เราใช้ $((ARITHMATIC))
หรือ $[ARITHMATIC]
ในการแทนค่าตัวแปร
ดังนี้
$ echo $(1+1) bash: 1+1: command not found $ echo 1+1 1+1 $ echo $((1+1)) 2 $ echo $[1+1] 2
บรรทัดเริ่มต้นของสคริปต์ หลังเครื่องหมาย #!
(hash-bang) เราต้องใส่พาธของโปรแกรม bash ให้เต็ม
สำหรับเดเบียน อยู่ที่ /bin/bash
อยู่แล้ว แต่หากเป็นดิสโตรอื่น อาจค้นหาว่าโปรแกรม bash อยู่ที่ไหน โดยใช้คำสั่งเหล่านี้
$ which bash $ whereis bash $ find / -name bash
หลายโปรแกรมของเชลล์มีการส่งค่าออกมา (Return value) อาจเพื่อแจ้งสถานะการรันว่ารันสำเร็จหรือไม่อย่างไร หรืออาจส่งออกเป็นค่าที่จะนำไปประมวลผลต่อก็ตาม เราสามารถใช้ตัวแปรพิเศษ $?
ในการดูผลลัพธ์ของโปรแกรมได้
เช่น
#!/bin/bash cd /dada &> /dev/null echo rv: $? cd $(pwd) &> /dev/null echo rv: $?
กรณีนี้ ไดเรคทอรี่ /dada
เป็นไดเรคทอรี่ที่เราแกล้งพิมพ์ผิดไว้ เพื่อดูว่าสคริปต์จะส่งออกค่าออกมาเป็นอย่างไร ซึ่งจะได้ผลออกมาเป็น 1 และ 0 ตามลำดับ คือ 1 หมายถึงมีข้อผิดพลาดในโปรแกรม และ 0 หมายถึงรันสำเร็จ ไม่มีข้อผิดพลาดใด ๆ
เราสามารถนำผลลัพธ์ของโปรแกรมมาใส่ในตัวแปร ด้วยการสั่งภายใต้เครื่องหมาย `
(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
อีกครั้งหนึ่ง
ตามตัวอย่างจะแสดงผลทุกตารางในทุกฐานข้อมูลของ mysql
[ "$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 ไม่มีค่า#!/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
+
การบวก-
การลบ*
การคูณ/
การหาร%
การหาเศษจากตัวหาร (remainder)-lt
น้อยกว่า (<)-gt
มากกว่า (>)-le
น้อยกว่าหรือเท่ากับ (<=)-ge
มากกว่าหรือเท่ากับ (>=)-eq
เท่ากับ (==)-ne
ไม่เท่ากับ (!=) 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
เป็นทั้งโปรแกรมและภาษาในการค้นหาข้อความในไฟล์จากรูปแบบที่เรากำหนดให้/tmp/dummy
มีเนื้อไฟล์คือ
test123 test tteesstt
ตัวอย่างการใช้งานคือ
$ awk '/test/ {print}' /tmp/dummy test123 test
ดูรายละเอียดเพิ่มเติมได้ที่ gentoo: Awk by example
grep
เป็นโปรแกรมที่ใช้บ่อยในการค้นข้อความในไฟล์ และยังมีความสามารถในการสรุปผลการนับข้อความด้วย$ man grep | grep "standard" -c 8
เป็นการค้นคำว่า standard ในการแสดงผลของคำสั่ง man grep
ว่ามีอยู่กี่คำ คำตอบคือ 8
ดูตัวอย่างเพิ่มเติมที่ tdlp: Examples using grep
wc
ใช้ในการนับคำ, นับบรรทัด และนับจำนวนหน่วยความจำที่ถูกใช้ในไฟล์ เป็นไบต์$ wc --words --lines --bytes /tmp/dummy 3 3 22 /tmp/dummy
sort
ใช้จัดเรียงข้อมูลb c a
ตัวอย่างคำสั่งคือ
$ sort /tmp/dummy a b c
คือการนำเอาเนื้อไฟล์ /tmp/dummy
มาจัดเรียง และแสดงผลออกทางจอภาพ
bc
เป็นเครื่องคิดเลขแบบใช้บรรทัดคำสั่ง$ echo 1+1 1+1 $ echo 1+1 | bc 2
หรือใช้แบบโต้ตอบ
$ bc -q 1 == 5 0 0.05 == 0.05 1 5 != 5 0 2 ^ 8 256 sqrt(9) 3 while (i != 9) { i = i + 1; print i } 123456789 quit
tput
ใช้ในการตั้งค่าหรือแสดงค่าต่าง ๆ ของเทอร์มินัล$ tput cup 10 4
เลื่อนเคอร์เซอร์ไปยังบรรทัดที่ 10 สดมภ์ที่ 4
$ tput reset
ล้างจอภาพ มีค่าเท่ากับคำสั่ง clear
$ tput cols
แสดงจำนวนสดมภ์ (ความกว้าง) ของจอเทอร์มินัล
#!/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
#!/bin/bash SRCD="/home/" TGTD="/var/backups/" OF=home-$(date +%Y%m%d).tgz tar -cZf $TGTD$OF $SRCD
#!/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 ; shift if [$1 = ]; then echo "no files given" exit 0 fi for file in $* do mv ${file} $file$suffix done exit 0 fi # check for the replacement rename if [ $1 = r ]; then shift # i included this bit as to not damage any files if the user does not specify # anything to be done # just a safety measure if [ $# -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 # text for 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!
#!/bin/bash # renames.sh # basic file renamer criteria=$1 re_match=$2 replace=$3 for i in $( ls *$criteria* ); do src=$i tgt=$(echo $i | sed -e "s/$re_match/$replace/") mv $src $tgt done
เราใช้พารามิเตอร์ -x
ต่อท้ายคำสั่งในบรรทัดแรก
#!/bin/bash -x
จะมีผลว่าเชลล์จะแสดงทุกคำสั่งที่ถูกรันออกมาทางจอภาพ
จบแล้วจ้า