Các shell giống như Bourne / POSIX có toán tử chia + toàn cầu và nó được gọi mỗi khi bạn để mở rộng tham số ( $var
, $-
...), thay thế lệnh ( $(...)
) hoặc mở rộng số học ( $((...))
) không được trích dẫn trong ngữ cảnh danh sách.
Trên thực tế, bạn đã gọi nó do nhầm lẫn khi bạn đã làm for name in ${array[@]}
thay vì for name in "${array[@]}"
. (Trên thực tế, bạn nên cẩn thận khi gọi toán tử đó như thế là do nhiều lỗi và lỗ hổng bảo mật ).
Toán tử đó được cấu hình với $IFS
tham số đặc biệt (để cho biết các ký tự được phân chia trên (mặc dù hãy cẩn thận rằng khoảng trắng, tab và dòng mới nhận được xử lý đặc biệt ở đó)) và -f
tùy chọn tắt ( set -f
) hoặc enable ( set +f
) glob
phần.
Cũng lưu ý rằng trong khi S
ở $IFS
ban đầu (trong vỏ Bourne nơi $IFS
xuất phát từ) cho Separator, trong vỏ POSIX, các nhân vật trong $IFS
nên thay vì được xem như delimiters hoặc Terminators (xem dưới đây để biết một ví dụ).
Vì vậy, để phân chia trên _
:
string='var1_var2_var3'
IFS=_ # delimit on _
set -f # disable the glob part
array=($string) # invoke the split+glob operator
for i in "${array[@]}"; do # loop over the array elements.
Để xem sự khác biệt giữa dấu phân cách và dấu phân cách , hãy thử:
string='var1_var2_'
Điều đó sẽ phân chia nó thành var1
và var2
chỉ (không có phần tử trống thêm).
Vì vậy, để làm cho nó tương tự như JavaScript split()
, bạn cần thêm một bước:
string='var1_var2_var3'
IFS=_ # delimit on _
set -f # disable the glob part
temp=${string}_ # add an extra delimiter
array=($temp) # invoke the split+glob operator
(lưu ý rằng nó sẽ chia một phần tử trống $string
thành 1 (không phải 0 ), như của JavaScript split()
).
Để xem tab điều trị đặc biệt, không gian và dòng mới nhận được, hãy so sánh:
IFS=' '; string=' var1 var2 '
(nơi bạn nhận được var1
và var2
) với
IFS='_'; string='_var1__var2__'
nơi bạn nhận được: ''
, var1
, ''
, var2
, ''
.
Lưu ý rằng zsh
shell không gọi toán tử split + global như thế trừ khi trong sh
hoặc ksh
mô phỏng. Ở đó, bạn phải gọi nó một cách rõ ràng. $=string
cho phần tách, $~string
cho phần toàn cầu ( $=~string
cho cả hai) và phần này cũng có toán tử phân tách trong đó bạn có thể chỉ định dấu phân cách:
array=(${(s:_:)string})
hoặc để bảo tồn các phần tử trống:
array=("${(@s:_:)string}")
Lưu ý rằng có s
để phân tách , không phân định (cũng với $IFS
, không tuân thủ POSIX đã biết zsh
). Nó khác với JavaScript split()
ở chỗ một chuỗi trống được chia thành phần tử 0 (không phải 1).
Một sự khác biệt đáng chú ý với $IFS
-splitting là ${(s:abc:)string}
chia rẽ trên abc
chuỗi, trong khi với IFS=abc
, mà sẽ chia trên a
, b
hoặc c
.
Với zsh
và ksh93
, điều trị đặc biệt mà không gian, tab hoặc dòng mới nhận được có thể được loại bỏ bằng cách nhân đôi chúng vào $IFS
.
Như một ghi chú lịch sử, vỏ Bourne (vỏ POSIX tổ tiên hoặc hiện đại) luôn tước bỏ các yếu tố trống rỗng. Nó cũng có một số lỗi liên quan đến việc chia tách và mở rộng $ @ với các giá trị không mặc định là $IFS
. Ví dụ IFS=_; set -f; set -- $@
sẽ không tương đương với IFS=_; set -f; set -- $1 $2 $3...
.
Tách trên regexps
Bây giờ đối với một cái gì đó gần gũi hơn với JavaScript split()
có thể phân tách trên các biểu thức thông thường, bạn cần phải dựa vào các tiện ích bên ngoài.
Trong rương công cụ POSIX, awk
có một split
toán tử có thể phân chia trên các biểu thức chính quy mở rộng (những phần tử này ít nhiều là một tập hợp con của các biểu thức chính quy giống như Perl được JavaScript hỗ trợ).
split() {
awk -v q="'" '
function quote(s) {
gsub(q, q "\\" q q, s)
return q s q
}
BEGIN {
n = split(ARGV[1], a, ARGV[2])
for (i = 1; i <= n; i++) printf " %s", quote(a[i])
exit
}' "$@"
}
string=a__b_+c
eval "array=($(split "$string" '[_+]+'))"
Các zsh
vỏ có được xây dựng trong hỗ trợ cho các biểu thức Perl-tương thích thường xuyên (trong nó zsh/pcre
mô-đun), nhưng sử dụng nó để chia một chuỗi, mặc dù có thể là tương đối cồng kềnh.
shell
bạn đang sử dụng cái gì , vớibash
bạn có thể làm gìIFS='_' read -a array <<< "${string}"