Xử lý chuỗi trong linux
Trim leading and trailing white-space from stringFunction này hoạt động bằng cách tìm tất các các khoản trắng và xoá nó khỏi đầu và cuối chuỗi. Show Dấu “:” được sử dụng như 1 biến tạm thời. trim_string() { # Usage: trim_string " example string " : "${1#"${1%%[![:space:]]*}"}" : "${_%"${_##*[![:space:]]}"}" printf '%s\n' "$_" } Giải thích:
# đoạn này có tác dụng loại bỏ chuỗi dài nhất không phải khoản trống từ bên phải chuỗi # kết quả ta sẽ được khoản trắng ở đầu chuỗi cần cắt. "${1%%[![:space:]]*}" vd: string = " Hello, World " |________________| %% # tiếp theo ta thực hiện loại bỏ chuỗi vừa thu được ở trên # ra khỏi chuỗi cần cắt từ bên trái chuỗi. "${1#"${1%%[![:space:]]*}"}" vd: string = " Hello, World “ |___| # Kết quả ta được chuỗi “Hello, World ”
# đoạn này có tác dụng lấy phần khoản trắng phía sau của chuỗi "${_##*[![:space:]]}" vd: string = "Hello, World " |____________| ## # tiếp đến sẽ cắt đoạn string mới lấy được phía trên ra khỏi chuỗi được xét. "${_%"${_##*[![:space:]]}"}" vd: string = "Hello, World “ |__| % Kết quả ta sẽ được chuỗi “Hello, World”
Trim all white-space from string and truncate spaces# shellcheck disable=SC2086,SC2048 trim_all() { # Usage: trim_all " example string " set -f set -- $* printf '%s\n' "$*" set +f } Đầu tiên ta sẽ tìm hiểu về “set” , “set” được sử dụng để thiết lập và sửa đổi các biến nội bộ của shell. Trong trường hợp của hàm ở trên, “set” được sử dụng để thiết lâp gía trị cho các biến vị trí. Ví dụ: ta có file set.sh có nội dung: var="Welcome to thegeekstuff" set -- $var echo "\$1=" $1 echo "\$2=" $2 echo "\$3=" $3 khi thực hiện ./set.sh ta sẽ được kết quả in ra màn hình như sau: $1=Welcome $2=to $3=thegeekstuff Tương tự với hàm trim_all() trên, khi ta chạy: trim_all " Hello, World " sau khi thực hiện set — $* ta sẽ có được giá trị $1 = “Hello,”, $2 = ” World”, như ta biết biến $* sẽ chứa tất cả các tham số đầu vào của script, có nghĩa là biến $* sẽ bao gồm các biến $1, $2. Vì vậy khi ta thực hiện printf ‘%s\n’ “$*” bash sẽ thực hiện in ra màn hình giống như printf ‘%s\n’ “$1 $2”. Vì vậy ta được kết quả là “Hello, World”. Tương tự với: name=" John Black is my name. " trim_all "$name" ta sẽ có được $1=”John”, $2=”Black”, $3=”is”, $4=”my”, $5=”name.” cuối cùng ta sẽ có được kết quả là: “John Black is my name.” Ngoài ra trong hàm trên ta cũng thấy được set -f là set và option -f, option này có tác dụng là vô hiệu hóa các phần mở rộng filename. Use regex on a stringKết quả của việc so trùng bash’s regex có thể được sử dụng để thay thế “sed” trong phần lớn các trường hợp ứng dụng. Tuy nhiên, chức năng này của Bash là một trong số ít chức năng phụ thuộc vào nền tảng hệ điều hành. Bash sẽ sử dụng bất cứ trình xử lý regex (regex engine) nào được cài đặt trên hệ thống của người dùng. Ví dụ1: ta có 1 đoạn hội thoại string="hue, Hex, Rgb, Hsl. 0, #ff0000, rgb(255, 0, 0), hsl(0, 100%, 50%). 15, #ff4000, rgb(255, 64, 0), hsl(15, 100%, 50%). 30, #ff8000, rgb(255, 128, 0), hsl(30, 100%, ..." # ta muốn lấy ra tất cả các mã màu theo dạng "#......" ta dùng hàm sau regex() { # Usage: regex "string" "regex" for word in $1 do [[ $word =~ $2 ]] if [[ ${BASH_REMATCH[1]} ]] then printf '%s\n' "${BASH_REMATCH[1]}" fi done } regex "$string" '(#([a-fA-F0-9]{6}|[a-fA-F0-9]{3}))' ta sẽ được kết quả: #ff0000 #ff4000 #ff8000 Ví dụ 2: ta có 1 chuỗi string, ta muốn kiểm tra nó có phải là 1 email hay không string="[email protected]" string2="[email protected]" regex() { # Usage: regex "string" "regex" [[ $1 =~ $2 ]] && printf '%s\n' "${BASH_REMATCH[1]}" } khi ta chạy lệnh: regex "$string" '^([A-Za-z0-9._%+-][email protected][A-Za-z0-9.-]+\.[A-Za-z]{2,4})$' ta sẽ được kết quả:
[email protected] regex "$string2" '^([A-Za-z0-9._%+-][email protected][A-Za-z0-9.-]+\.[A-Za-z]{2,4})$' ta sẽ được kết quả rỗng. Tích hợp vào script ta có hàm kiểm tra màu như sau: is_hex_color() { if [[ $1 =~ ^(#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3}))$ ]]; then printf '%s\n' "${BASH_REMATCH[1]}" else printf '%s\n' "error: $1 is an invalid color." return 1 fi } color="#444444" is_hex_color "$color" || color="#FFFFFF" # kết quả: #444444 color="#444444134235" is_hex_color "$color" || color="#FFFFFF" # kết quả: error: #444444134235 is an invalid color. //echo $color => #FFFFFF Split a string on a delimiterLưu ý: hàm dưới đây yêu cầu phiên bản bash từ 4. trở lên split() { # Usage: split "string" "delimiter" IFS=$'\n' read -d "" -ra arr <<< "${1//$2/$'\n'}" printf '%s\n' "${arr[@]}" } Trước khi thực thi hàm trên, ta hãy tìm hiểu 1 số khái niệm sau đây nhé:
Sau khi làm rõ được các khái niệm trên, bây giờ ta hãy cùng phân tích hàm ở trên: Đầu tiên, ta gán IFS bằng ký tự newline $’\n’ sau đó ta dùng hàm read với option -d để thay đổi ký tự kết thúc dòng là “” cùng với option -ra để ghi các giá trị tìm thấy vào một mảng. Ta dùng phép replace trên chuỗi để đổi chổ ký tự mà ta muốn dùng để phân tách bằng ký tự xuống dòng ${1//$2/$’\n’}.Đầu tiên, ta gán IFS bằng ký tự newline $’\n’ sau đó ta dùng hàm read với option -d để thay đổi ký tự kết thúc dòng là “” cùng với option -ra để ghi các giá trị tìm thấy vào một mảng. Ta dùng phép replace trên chuỗi để đổi chổ ký tự mà ta muốn dùng để phân tách bằng ký tự xuống dòng ${1//$2/$’\n’}. Ví dụ: khi ta thực hiện lệnh split "apples,oranges,pears,grapes" "," hàm split sẽ replace chuỗi “apples,oranges,pears,grapes” với ký tự “,” bằng ký tự $’\n’, ta sẽ có được chuỗi mới là: [[email protected] ~]# string="apples,oranges,pears,grapes" [[email protected] ~]# a="," [[email protected] ~]# echo "${string//$a/$'\n'}" apples oranges pears grapes [[email protected] ~]# Sau đó, hàm read với các option -d, -r, -a sẽ ghi mỗi từ trong chuỗi mới kết thúc bằng ký tự ‘\n’ vào mảng thứ tự, bắt đầu từ vị trí 0. Cuối cùng ta có được 1 mảng chứa các giá trị đã cắt bằng ký tự phân cách là “,” Ví dụ 2: Như trên, ta thực hiện hàm split với các chuỗi sau: split "1, 2, 3, 4, 5" ", " split "hello---world---my---name---is---john" "—" ta sẽ được các kết quả cho lệnh đầu tiên: 1 2 3 4 5 và chuỗi tiếp sau là: hello world my name is john Trong bài này. mình đã giới thiệu cho các bạn 4 hàm xử lý chuỗi nâng cao, thật đơn giản phải không, các hàm này là tổ hợp của các cách xử lý chuỗi cơ bản mình đã giới thiệu ở các bài trước chứ không có nhiều kiến thức mới. Nếu nắm vững được cơ bản, các bạn sẽ dễ dàng đọc hiểu được cách hoạt động của các hàm trên. Ở bài sau, mình sẽ tiếp tục với các hàm xử lý chuỗi tiếp theo. |