Оболочки типа Bourne / POSIX имеют оператор split + glob, и он вызывается каждый раз, когда вы оставляете в кавычках раскрытие параметров ( $var
, $-
...), команду substitution ( $(...)
) или арифметическое расширение ( $((...))
) без кавычек.
На самом деле, вы вызвали это по ошибке, когда вы сделали for name in ${array[@]}
вместо for name in "${array[@]}"
. (На самом деле, вы должны помнить, что такой ошибочный вызов оператора является источником многих ошибок и уязвимостей в безопасности ).
Этот оператор настроен со $IFS
специальным параметром (чтобы указать, на какие символы разбивать (хотя имейте в виду, что пробел, табуляция и новая строка там получают специальную обработку)) и -f
возможностью отключить ( set -f
) или включить ( set +f
) glob
часть.
Также обратите внимание, что в то время как S
in $IFS
изначально был (в оболочке Bourne, откуда $IFS
происходит) для Separator, в оболочках POSIX символы in $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
оболочка не вызывает этот оператор split + glob неявным образом, если только в sh
или ksh
эмуляция. Там вы должны вызывать это явно. $=string
для части split, $~string
для части glob ( $=~string
для обеих), а также есть оператор split, где вы можете указать разделитель:
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
.
Как историческое примечание, оболочка Bourne (предок или современные оболочки 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}"