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 $IFStham 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à -ftùy chọn tắt ( set -f) hoặc enable ( set +f) globphần.
Cũng lưu ý rằng trong khi Sở $IFSban đầu (trong vỏ Bourne nơi $IFSxuất phát từ) cho Separator, trong vỏ POSIX, các nhân vật trong $IFSnê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 var1và var2chỉ (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 $stringthà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 var1và var2) với
IFS='_'; string='_var1__var2__'
nơi bạn nhận được: '', var1, '', var2, ''.
Lưu ý rằng zshshell không gọi toán tử split + global như thế trừ khi trong shhoặc kshmô phỏng. Ở đó, bạn phải gọi nó một cách rõ ràng. $=stringcho phần tách, $~stringcho phần toàn cầu ( $=~stringcho 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 abcchuỗi, trong khi với IFS=abc, mà sẽ chia trên a, bhoặc c.
Với zshvà 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, awkcó một splittoá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 zshvỏ 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/pcremô-đ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.
shellbạn đang sử dụng cái gì , vớibashbạn có thể làm gìIFS='_' read -a array <<< "${string}"