Оболонки, подібні до Bourne / POSIX, мають оператор split + glob, і він викликається кожен раз, коли ви залишаєте розширення параметра ( $var
, $-
...), підстановку команд ( $(...)
) або арифметичне розширення ( $((...))
), котируемого в контексті списку.
Насправді ви покликали це помилково, коли зробили for name in ${array[@]}
замість цього for name in "${array[@]}"
. (Насправді, ви повинні бути обережними, що виклик такого оператора помилково є джерелом багатьох помилок та вразливості безпеки ).
Цей оператор налаштований за допомогою $IFS
спеціального параметра (щоб вказати, на які символи потрібно розділити (хоча будьте обережні, що пробіл, вкладка та новий рядок отримують там спеціальну обробку)) та -f
можливість відключити ( set -f
) або включити ( set +f
) glob
частину.
Також зауважте, що в той час, як " S
in" $IFS
(в оболонці Bourne, звідки $IFS
походить) для Separator, в оболонках POSIX, символи в них $IFS
повинні розглядатися як роздільники або термінатори (див. Приклад нижче).
Отже, щоб розділити на _
:
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.
Щоб побачити відмінність між роздільником і роздільником , спробуйте:
string='var1_var2_'
Це розділить його на var1
і var2
тільки (без зайвих порожніх елементів).
Отже, щоб зробити його схожим на JavaScript split()
, вам знадобиться додатковий крок:
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
(зауважте, що він розділить порожній $string
на 1 (не 0 ) елемент, як JavaScript split()
).
Щоб переглянути вкладку спеціальних процедур, пробіл та нову лінію, порівняйте:
IFS=' '; string=' var1 var2 '
(Де ви отримаєте var1
і var2
) з
IFS='_'; string='_var1__var2__'
де ви отримаєте: ''
, var1
, ''
, var2
, ''
.
Зауважте, що zsh
оболонка не викликає оператора спліт-глобуля неявно подібного, якщо не є sh
або ksh
емуляція. Там вам потрібно чітко посилатися на це. $=string
для розділеної частини, $~string
для глобальної частини ( $=~string
для обох), а також він має роздільний оператор, де ви можете вказати роздільник:
array=(${(s:_:)string})
або зберегти порожні елементи:
array=("${(@s:_:)string}")
Зверніть увагу , що s
для розщеплення , а НЕ обмежує (також з $IFS
, відомим POSIX невідповідність zsh
). Від JavaScript відрізняється split()
тим, що порожній рядок розділений на 0 (а не 1) елемент.
Помітною відмінністю від $IFS
-splitting є те, що ${(s:abc:)string}
розбивається на abc
рядок, тоді як з IFS=abc
, що розділиться на a
, b
або c
.
З zsh
і ksh93
, спеціальне лікування, пробіл, табуляція або новий рядок отримати можуть бути вилучені шляхом подвоєння їх $IFS
.
Як історична примітка, оболонка Борна (предка або сучасні оболонки POSIX) завжди позбавляла порожніх елементів. Він також мав ряд помилок, пов’язаних з розщепленням та розширенням $ @ із значеннями, що не мають замовчування $IFS
. Наприклад IFS=_; set -f; set -- $@
, не було б рівнозначно IFS=_; set -f; set -- $1 $2 $3...
.
Розщеплення на регулярні виразки
Тепер для чогось ближчого до JavaScript, split()
який може розділитись на регулярні вирази, вам потрібно буде покластися на зовнішні утиліти.
У скрині інструментів POSIX awk
є split
оператор, який може розділити на розширені регулярні вирази (це більш-менш підмножина регулярних виразів Perl, що підтримуються JavaScript).
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" '[_+]+'))"
zsh
Оболонка має вбудовану підтримку для Perl-сумісних регулярних виразів (в його zsh/pcre
модулі), але використовувати його для розбиття рядка, хоча можливо щодо громіздкі.
shell
ти використовуєш,bash
можеш зробитиIFS='_' read -a array <<< "${string}"