Tìm hiểu shell script - P2

3. Loop

Ký tự đại diện

Để sử dụng loop cần lướt qua 1 chút:

  • Sap chép file từ thư mục a sang thư mục b:
$ cp /tmp/a/* /tmp/b/
$ cp /tmp/a/*.txt /tmp/b/
$ cp /tmp/a/*.html /tmp/b/
  • Đổi tên file a sang b:
sudo mv a.txt b.txt

Ký tự cần được giải thích (escape)

$ echo Hello       World
Hello World
$ echo "Hello       World"
Hello     World
$ echo "Hello       "World
Hello     World
$  echo "Hello \"World\""
Hello "World"

=> 1 tab hoặc nhiều dấu cách sẽ bị hiểu nhầm nếu không đặt trong cặp dấu " ", các ký tự đặc biệt (như ") cần được giải thích bằng dấu xuyệt phải ngay phía trước. Hầu hết các ký tự đặc biệt (*, ', vân vân) không được giải thích bình thường, ví dụ * được coi là ký tự đại diện chứ không phải ký tự thường nếu không được đặt trong cặp " ", chẳng hạn:

$ echo *
case.shtml escape.shtml first.shtml 
functions.shtml hints.shtml index.shtml 
ip-primer.txt raid1+0.txt
$ echo *txt
ip-primer.txt raid1+0.txt
$ echo "*"
*
$ echo "*txt"
*txt

Trong ví dụ đầu tiên, * có nghĩa là tất cả các tệp trong thư mục hiện tại. Trong ví dụ thứ hai, *txt có nghĩa là tất cả các file kết thúc bằng txt. Trong ví dụ ba, tôi đặt dấu * trong dấu ngoặc kép và nó được hiểu theo nghĩa đen. Trong ví dụ thứ tư, áp dụng tương tự, nhưng tôi đã nối txt cho vào chuỗi.

Tuy nhiên, ", $,` và \ vẫn được giải thích bởi shell, ngay cả khi chúng nằm trong dấu ngoặc kép. Ký tự dấu gạch chéo ngược () được sử dụng để đánh dấu các ký tự đặc biệt này để chúng không được "giải thích" bởi trình shell, nhưng được truyền cho lệnh đang được chạy (ví dụ: echo). Vì vậy, để xuất 1 chuỗi gồm toàn những ký tự đặc biệt: (Giả sử giá trị của biến $X là 5):

A quote is ", backslash is \, backtick is `.
A few spaces are    and dollar is $. $X is 5.

Ta sẽ phải viết:

$ echo "A quote is \", backslash is \\, backtick is \`."
A quote is ", backslash is \, backtick is `.
$ echo "A few spaces are    and dollar is \$. \$X is ${X}."
A few spaces are    and dollar is $. $X is 5.

Chúng ta đã thấy vì sao " được sử dụng để xuất dấu cách, biến được sử dụng bởi dấu $, nên $X, ${X} đã được thay thế bởi giá trị của biến. Còn dấu xuyệt phải (\) là đặc biệt dùng để đánh dấu ký tự khác, vd:

$ echo "This is \\ a backslash"
This is \ a backslash
$ echo "This is \" a quote and this is \\ a backslash"
This is " a quote and this is \ a backslash

Vòng Lặp

Cách viết vòng lặp for trong shell chạy file for.sh

#!/bin/sh
for i in 1 2 3 4 5
do
  echo "Looping ... number $i"
done

kết quả:

Looping .... number 1
Looping .... number 2
Looping .... number 3
Looping .... number 4
Looping .... number 5

Chạy file for2.sh

#!/bin/sh
for i in hello 1 * 2 goodbye 
do
  echo "Looping ... i is set to $i"
done
Looping ... i is set to hello
Looping ... i is set to 1
Looping ... i is set to for2.sh
Looping ... i is set to for.sh
Looping ... i is set to 2
Looping ... i is set to goodbye

Cách viết vòng lặp while trong shell, file while.sh:

#!/bin/sh
INPUT_STRING=hello
while [ "$INPUT_STRING" != "bye" ]
do
  echo "Please type something in (bye to quit)"
  read INPUT_STRING
  echo "You typed: $INPUT_STRING"
done

=> gõ bye rồi enter từ bàn phím để kết thúc vòng lặp.


Một mẹo viết tắt vòng lặp đến từ Linux From Scratch! :

mkdir rc{0,1,2,3,4,5,6,S}.d

để thay thế cho

for runlevel in 0 1 2 3 4 5 6 S
do
  mkdir rc${runlevel}.d
done

Và vì thế có thể viết đệ quy để lấy danh sách các file/folder của nhiều path khác nhau:

$ cd /
$ ls -ld {,usr,usr/local}/{bin,sbin,lib}
drwxr-xr-x    2 root     root         4096 Oct 26 01:00 /bin
drwxr-xr-x    6 root     root         4096 Jan 16 17:09 /lib
drwxr-xr-x    2 root     root         4096 Oct 27 00:02 /sbin
drwxr-xr-x    2 root     root        40960 Jan 16 19:35 usr/bin
drwxr-xr-x   83 root     root        49152 Jan 16 17:23 usr/lib
drwxr-xr-x    2 root     root         4096 Jan 16 22:22 usr/local/bin
drwxr-xr-x    3 root     root         4096 Jan 16 19:17 usr/local/lib
drwxr-xr-x    2 root     root         4096 Dec 28 00:44 usr/local/sbin
drwxr-xr-x    2 root     root         8192 Dec 27 02:10 usr/sbin

4. Kiểm tra điều kiện

if [$foo = "bar" ]

Cú pháp:

if [ ... ]
then
  # if-code
else
  # else-code
fi

hoặc:

if  [ something ]; then
 echo "Something"
elif [ something_else ]; then
  echo "Something else"
else
  echo "None of the above"
fi

Để ý dấu ; có thể dùng làm phân định 2 dòng lệnh, cặp [ ] có thể sử dụng như 1 lệnh kiểm tra điều kiện:

#!/bin/sh
if  [ $X = 0 ]; then
 echo "Something"
elif [ $X -gt 1 ]; then
  echo "Something else"
else
  echo "None of the above"
fi

[ "$X" -le "0" ] && \
      echo "X is less than or equal to  zero"

Với X là biến (được export từ bên ngoài hoặc có thể khai báo bên trên cùng - xem phần 1 ).


5. Case

Cũng tương tự câu điều kiện if else, cú pháp case như sau:

#!/bin/sh

echo "Please talk to me ..."
while :
do
  read INPUT_STRING
  case $INPUT_STRING in
  hello)
    echo "Hello yourself!"
    ;;
  bye)
    echo "See you again!"
    break
    ;;
  *)
    echo "Sorry, I don't understand"
    ;;
  esac
done
echo
echo "That's all folks!"

Hãy chạy thử script trên và nhập và enter từ bàn phím hello, lkjasldkjasldkjas, và bye => bạn sẽ hiểu ngay về case.


Trong phần tới tôi sẽ nói tiếp về biến.

Trong phần cuối tôi sẽ mô tả cách khai báo Function , cũng như các gợi ý, lời khuyên, một số lệnh tham khảo để sử dụng trong shell (=, -gt. -le, ... bla bla) để có thể có kiến thức tương tác tốt với shell khi cần.


All Rights Reserved