Cách dễ nhất và an toàn nhất trong BASH 3 trở lên là:
var="string to split"
read -ra arr <<<"$var"
(trong đó arr
mảng lấy các phần bị tách của chuỗi) hoặc, nếu có thể có dòng mới trong đầu vào và bạn muốn nhiều hơn chỉ dòng đầu tiên:
var="string to split"
read -ra arr -d '' <<<"$var"
(xin lưu ý không gian trong -d ''
, không thể bỏ đi), nhưng điều này có thể cung cấp cho bạn một dòng mới bất ngờ từ <<<"$var"
(vì điều này hoàn toàn bổ sung một LF ở cuối).
Thí dụ:
touch NOPE
var="* a *"
read -ra arr <<<"$var"
for a in "${arr[@]}"; do echo "[$a]"; done
Đầu ra dự kiến
[*]
[a]
[*]
vì giải pháp này (trái ngược với tất cả các giải pháp trước đây ở đây) không dễ bị bất ngờ và thường không kiểm soát được vỏ.
Ngoài ra, điều này cung cấp cho bạn toàn bộ sức mạnh của IFS như bạn có thể muốn:
Thí dụ:
IFS=: read -ra arr < <(grep "^$USER:" /etc/passwd)
for a in "${arr[@]}"; do echo "[$a]"; done
Xuất ra một cái gì đó như:
[tino]
[x]
[1000]
[1000]
[Valentin Hilbig]
[/home/tino]
[/bin/bash]
Như bạn có thể thấy, không gian cũng có thể được bảo tồn theo cách này:
IFS=: read -ra arr <<<' split : this '
for a in "${arr[@]}"; do echo "[$a]"; done
đầu ra
[ split ]
[ this ]
Xin lưu ý rằng việc xử lý IFS
trong BASH là một chủ đề của riêng nó, do đó, hãy thực hiện các bài kiểm tra của bạn, một số chủ đề thú vị về điều này:
unset IFS
: Bỏ qua các lần chạy SPC, TAB, NL và trên dòng bắt đầu và kết thúc
IFS=''
: Không tách trường, chỉ đọc mọi thứ
IFS=' '
: Chạy SPC (và chỉ SPC)
Một số ví dụ cuối cùng
var=$'\n\nthis is\n\n\na test\n\n'
IFS=$'\n' read -ra arr -d '' <<<"$var"
i=0; for a in "${arr[@]}"; do let i++; echo "$i [$a]"; done
đầu ra
1 [this is]
2 [a test]
trong khi
unset IFS
var=$'\n\nthis is\n\n\na test\n\n'
read -ra arr -d '' <<<"$var"
i=0; for a in "${arr[@]}"; do let i++; echo "$i [$a]"; done
đầu ra
1 [this]
2 [is]
3 [a]
4 [test]
BTW:
Nếu bạn không quen $'ANSI-ESCAPED-STRING'
làm quen với nó, đó là một trình tiết kiệm thời gian.
Nếu bạn không bao gồm -r
(như trong read -a arr <<<"$var"
) thì đọc sẽ thoát dấu gạch chéo ngược. Điều này được để lại như là bài tập cho người đọc.
Đối với câu hỏi thứ hai:
Để kiểm tra một cái gì đó trong chuỗi tôi thường dính vào case
, vì điều này có thể kiểm tra nhiều trường hợp cùng một lúc (lưu ý: trường hợp chỉ thực hiện trận đấu đầu tiên, nếu bạn cần sử dụng các case
câu lệnh nhân), và nhu cầu này khá thường xuyên (chơi chữ dự định):
case "$var" in
'') empty_var;; # variable is empty
*' '*) have_space "$var";; # have SPC
*[[:space:]]*) have_whitespace "$var";; # have whitespaces like TAB
*[^-+.,A-Za-z0-9]*) have_nonalnum "$var";; # non-alphanum-chars found
*[-+.,]*) have_punctuation "$var";; # some punctuation chars found
*) default_case "$var";; # if all above does not match
esac
Vì vậy, bạn có thể đặt giá trị trả về để kiểm tra SPC như thế này:
case "$var" in (*' '*) true;; (*) false;; esac
Tại sao case
? Bởi vì nó thường dễ đọc hơn một chút so với chuỗi regex, và nhờ các siêu ký tự Shell, nó xử lý 99% tất cả các nhu cầu rất tốt.