เขียน Shell Script

By | 01/08/2013

ขอบคุณ 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 Guide

1.เกริ่น

เชลล์สคริปต์ พูดง่าย ๆ ก็คือการนำคำสั่งในเชลล์ของลินุกซ์มาเรียงต่อกันให้ทำงานตามที่เราต้องการ โดยเพิ่มโครงสร้างการวนรอบ และฟังก์ชั่นต่าง ๆ เติมเข้ามา เพื่อให้การทำงานได้ตามที่เราต้องการ ซึ่งจะเหมาะมากกับงานแบบ 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

2.เริ่มเขียน

 

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  done

7.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

อีกครั้งหนึ่ง
ตามตัวอย่างจะแสดงผลทุกตารางในทุกฐานข้อมูลของ mysql

11. ตัวดำเนินการ (operators) และคำสั่งน่าสนใจ

 

11.1 ตัวดำเนินการเปรียบเทียบตัวอักษร (String comparison operators)

  • <strong>[ "$s1" = "$s2" ]</strong>

    หรือ

    <strong>[ "$s1" == "$s2" ]</strong>

    เป็นจริง ถ้า s1 เท่ากับ s2

  • <strong>[ "$s1" != "$s2" ]</strong>

    เป็นจริง ถ้า s1 ไม่เท่ากับ s2

  • <strong>[[ "$s1" &lt; "$s2" ]]</strong>

    หรือ

    [ "$s1" \&lt; "$s2" ]

    เป็นจริง ถ้า s1 น้อยกว่า s2

  • <strong>[[ "$s1" &gt; "$s2" ]]</strong>

    หรือ

    [ "$s1" \&gt; "$s2" ]

    เป็นจริง ถ้า s1 มากกว่า s2

  • <strong>[ -n "$s1" ]</strong>

    เป็นจริง ถ้า s1 มีค่าใด ๆ

  • <strong>[ -z "$s1" ]</strong>

    เป็นจริง ถ้า 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)

  • <strong>+</strong>

    การบวก

  • <strong>-</strong>

    การลบ

  • <strong>*</strong>

    การคูณ

  • <strong>/</strong>

    การหาร

  • <strong>%</strong>

    การหาเศษจากตัวหาร (remainder)

 

11.4 ตัวเปรียบเทียบทางคณิตศาตร์ (Arithmetic relational operators

  • <strong>-lt</strong>

    น้อยกว่า (<)

  • <strong>-gt</strong>

    มากกว่า (>)

  • <strong>-le</strong>

    น้อยกว่าหรือเท่ากับ (<=)

  • <strong>-ge</strong>

    มากกว่าหรือเท่ากับ (>=)

  • <strong>-eq</strong>

    เท่ากับ (==)

  • <strong>-ne</strong>

    ไม่เท่ากับ (!=)

 

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  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 (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 ; 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!

 

12.4 เปลี่ยนชื่อไฟล์แบบง่าย

#!/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

13. การค้นหาที่ผิดในสคริปต์

เราใช้พารามิเตอร์

-x

ต่อท้ายคำสั่งในบรรทัดแรก

#!/bin/bash -x

จะมีผลว่าเชลล์จะแสดงทุกคำสั่งที่ถูกรันออกมาทางจอภาพ

จบแล้วจ้า

ใส่ความเห็น

อีเมลของคุณจะไม่แสดงให้คนอื่นเห็น ช่องที่ต้องการถูกทำเครื่องหมาย *