Lấy xâu con trong shell script
Hôm trước nhân lúc nhàn rỗi mình có giúp một “đồng nghiệp” viết một script nhỏ bằng ZShell phục vụ cho việc testing. Do công việc hàng ngày chỉ là viết các script đơn giản nên mình đã khá lúng túng trước yêu cầu phải lấy ra được một xâu con (substring) từ một xâu khác. Lên Google search thì thấy cũng có khá nhiều người gặp khó khăn trước vấn đề này và hóa ra xử lí xâu trong shell cũng là một vấn đề khá thú vị. Bài viết này tổng kết những phương pháp để lấy substring trong shell mà tác giả lượm lặt trên mạng. Chú ý rằng những phương pháp này có thể không áp dụng được với một số loại shell nhất định.
Những kĩ thuật dưới đây được áp dụng để giải quyết bài toán cụ thể là lấy ra xâu “substring” từ xâu “this is a substring test”. Bài toán này có ý nghĩa trong trường hợp substring là một biến có thể nhận nhiều giá trị khác nhau.
1- Sử dụng cú pháp substring=${string:starting_position:length}
string=”this is a substring test”
substring=${string:10:9}
echo $substring
substring
Chú ý rằng vị trí đầu tiên trong một xâu là 0. Nhược điểm của cách này là chỉ áp dụng khi xâu con cần lấy ra có độ dài cố định. Hơn nữa cách này không áp dụng được cho zshell, một loại shell được dùng phổ biến trên các hệ thống UNIX.
2- Sử dụng lệnh cut
Lệnh cut dùng để lấy ra một số kí tự trong một xâu. Dùng man cut để xem chi tiết về lệnh này. Trong bài toán cụ thể của chúng ta, trong xâu string thì xâu con “substring” bắt đầu từ vị trí 11 và kết thúc ở vị trí thứ 19. Bởi vậy có thể dùng lệnh sau đây để cắt ra “substring”
string=”this is a substring test” echo $string | cut –c11-19
substring
Nhược điểm của cách làm này là chỉ áp dụng với xâu con có độ dài cố định. Chúng ta có thể sử dụng lệnh cut với các tham số sau đây đề khắc phục nhược điểm đó
string=”this is a substring test” echo $string | cut –d’ ‘ –f4
substring
Lệnh trên lấy ra trường thứ 4 (f = field) của xâu string, mỗi trường cách nhau bởi kí tự space (d=delimeter).
3- Sử dụng các toán tử #, ##, % và %%
Toán tử # nghĩa là xóa bắt đầu từ bên trái xâu đầu tiên thỏa mãn mẫu (pattern) theo sau dấu #
string=”this is a substring test”
# mẫu “* “ sau dấu #, xóa từ bên trái xâu đầu tiên có dạng một xâu hay một kí tự bất kì
#theo sau bởi kí tự space, tức là xâu “this “
#(chú ý “*” đại diện cho một xâu hay kí tự bất kí)
substring=${string#* }
echo $substring
is a substring test
Toán tử ## nghĩa là xóa bắt đầu từ bên trái xâu cuối cùng thỏa mãn mẫu (pattern) theo sau dấu ##
string=”this is a substring test”
# mẫu “* “ sau dấu ##, xóa từ bên trái xâu cuối cùng có dạng một xâu hay kí tự bất kì
#theo sau bởi kí tự space, tức là xâu “this is a substring “
substring=${string##* }
echo $substring
test
Toán tử % nghĩa là xóa từ bên phải xâu đầu tiên thỏa mãn mẫu (pattern) theo sau dấu %.
string=”this is a substring test”
# mẫu “ *” sau dấu %, xóa từ bên phải xâu đầu tiên có dạng kí tự space
#theo sau bởi một xâu hay kí tự bất kí, tức là xâu “ test”.
substring=${string% *}
echo $substring
this is a substring
Toán tử %% nghĩa là xóa từ bên phải xâu đầu tiên thỏa mãn mấu (pattern) theo sau dấu %%.
string=”this is a substring test”
#mẫu “ *” sau dấu %%, xóa từ bên phải xâu cuối cùng có dạng kí tự space
#theo sau bởi một xâu hay kí tự bất kì, tức là xâu “ is a substring test”
substring=${string%% *}
echo $substring
this
Trở lại bài toán ban đầu, để lấy ra xâu “substring” chúng ta cần xóa đi hai xâu “this is a “ và “ test”. Việc xóa đi xâu “ test” đã được nói đến ở trên:
substring=${string% *}
Có nhiều cách để xóa nốt xâu “this is a “. Xâu này có đặc điểm là xâu đầu tiên có dạng một xâu bất kì theo sau bởi kí tự ‘a’ theo sau bởi kí tự space. Bởi vậy có thể viết
substring=${substring#*a }
echo $substring
substring
Đơn giản hơn, đó chính là xâu có dạng “this is a “!!!. Bởi vậy chúng ta có cách thứ hai sau đây
substring=${substring#this is a }
echo $substring
substring
Ngoài những cách nói trên thì sed và awk cũng là những công cụ rất mạnh để xử lí xâu. awk có hẳn một hàm substr để lấy ra các xâu con từ một xâu. Tác giả đã có một bài viết về sed và hi vọng sẽ sớm có một bài giới thiệu awk trong tương lai gần.
Một trang web thú vị tổng hợp các cú pháp của lập trình bash shell là: http://www.arachnoid.com/linux/shell_programming.html
Cái thú vị nhất ở trang này là lời khẳng định sau đây: “I want to say at the outset that shell programming is an art, not a science. That means there is always some other way to do the same thing.“
Trong zshell chúng ta có thể sử dụng cú pháp $string[ start_position, end_position ] để lấy ra xâu con bắt đầu từ vị trí start_position và kết thúc ở end_position. Ví dụ:
string=”this is a substring test”
echo $string[ 11, 19 ]
substring