Never ask how to use, just wonder how to make...

Dec 12, 2008

Làm chủ Linux Bash shell: Xử lý string trong Bash shell

Một trong những shell được sử dụng thường xuyên trong Linux là bash shell. Khi viết các shell script, công việc mà người sử dụng hay gặp phải nhất có lẽ là xử lý string (tìm file, xử lý tên file, xử lý log, xử lý chuỗi nhập vào,...). Sau đây tôi xin trình bày một số điểm mấu chốt thú vị trong xử lý string với bash shell.

Hai lệnh đầu tiên, đơn giản nhưng tương đối hữu ích, đó là dirnamebasename. Cho một biến có chứa 1 string dạng đường dẫn đến 1 thư mục D hoặc 1 file X, lệnh basename sẽ trả về đúng tên thư mục D hoặc tên file X, còn lệnh dirname trả về phàn đường dẫn đến thư mục mẹ của D hoặc X. Ví dụ:
$ basename /home/thangphamduy/workspace/foo.txt
foo.txt
$ dirname /home/thangphamduy/workspace/foo.txt
/home/thangphamduy/workspace
$ basename /home/thangphamduy/workspace
workspace
$ dirname /home/thangphamduy/workspace

/home/thangphamduy

$ ALPHA="/home/thangphamduy/temp/bar.txt"
$ BETA=`dirname $ALPHA`
$ echo $BETA
/home/thangphamduy/temp

Đó chỉ là xử lý xâu đơn giản, tiếp đây, chúng ta thử xử lý xâu một cách "pro" hơn với bash shell. Trong 1 biểu thức, ta thường bắt gặp một biến được đặt trong cặp dấu ngoặc nhọn kiểu như ${MYVAR}. Và bash cũng cho phép chúng ta xử lý biến đó ngay trong cặp ngoặc nhọn. Chúng ta có thể dễ dàng cắt bỏ hay lấy ra một phần của string chứa trong biến một cách rất dễ dàng. Để dễ hình dung, các bạn có thể xem ví dụ sau:

$ MYVAR=foodforthought.jpg
$ echo ${MYVAR##*fo}
rthought.jpg
$ echo ${MYVAR#*fo}
odforthought.jpg

Trong lệnh thứ nhất, ở phía trong dấu ${}, đầu tiên chúng ta viết tên biến, sau đó là hai dấu #, rồi đến 1 chuỗi ký tự đại diện (*fo). Vậy lệnh này có nghĩa là gì và nó được bash shell thực hiện như thế nào? Lệnh này (echo ${MYVAR##*fo}) sẽ khiến cho bash thực hiện việc cắt bỏ chuối dài nhất, tính từ ký tự đầu tiên, khớp với chuỗi ký tự đại diện (còn gọi là wildcard), sau đó in phần còn lại ra stdout. Khi gặp lệnh này, bash shell sẽ thực hiện việc tìm kiếm tất cả các xâu con khớp với chuỗi ký tự đại diện *fo trong xâu được chứa bởi $MYVAR(tức là tìm tất cả các xâu kết thúc với 2 ký tự fo):
f
fo MATCHES *fo
foo
food
foodf
foodfo MATCHES *fo
foodfor
foodfort
foodforth
foodfortho
foodforthou
foodforthoug
foodforthought
foodforthought.j
foodforthought.jp
foodforthought.jpg

Sau khi kết thúc tìm kiếm (trong VD trên bash tìm được 2 kết quả), bash sẽ lấy xâu kết quả dài nhất (foodfo), rồi loại bỏ nó ra khỏi xâu gốc (phần còn lại: rthought.jpg), rồi in kết quả ra màn hình.

Trong câu lệnh thứ hai (echo ${MYVAR#*fo}), công việc cũng tương tự như trên, nhưng thay vì lấy kết quả dài nhất, bash shell lại lấy kết quả ngắn nhất (fo) rồi loại bỏ khỏi xâu gốc và in kết quả ra màn hình. Thực ra khi chỉ sử dụng 1 dấu # ở phần tùy biến, ngay khi tìm được kết quả đầu tiên, bash shell sẽ lập tức dừng việc tìm kiếm lại.

Để tìm kiếm từ cuối xâu thay vì tìm kiếm từ đầu xâu, chúng ta thay các tùy biến # và ## bằng các tùy biến % và %%, cách sử dụng hoàn toàn tương tự. Ví dụ:
$ MYVAR=thangphamduy/workspace/bar.foo.txt
$ echo ${MYVAR%.*}
thangphamduy/workspace/bar.foo
$ echo ${MYVAR%%.*}
thangphamduy/workspace/bar

Và một cách xử lý string nữa, ít được dùng tới hơn, nhưng nhiều lúc rất có ích, đó là cắt xâu theo vị trí:
$ MYVAR=http://thangphamduy.blogspot.com
$ echo ${MYVAR:0:13}
http://fotech
$ echo ${MYVAR:8:17}
fotech.org

Phần xử lý string xin được dừng lại tại đây, cảm ơn quý vị và các bạn đã quan tâm theo dõi >:).
(Tham khảo từ
Bash by example - IBM)