Это очень легко использовать split()
в JavaScript, чтобы разбить строку на массив.
А как насчет сценария оболочки?
Скажи, что я хочу сделать это:
$ script.sh var1_var2_var3
Когда пользователь передает такую строку var1_var2_var3
в script.sh, внутри скрипта он преобразует строку в массив, подобный
array=( var1 var2 var3 )
for name in ${array[@]}; do
# some code
done
shell
shell-script
string
AGamePlayer
источник
источник
shell
вы используете, с чемbash
вы можете сделатьIFS='_' read -a array <<< "${string}"
perl
может сделать это тоже. Это не «чистая» оболочка, но она довольно распространенная.Ответы:
Оболочки типа 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
лучше рассматривать как разделители или терминаторы (см. Пример ниже).Итак, разделить на
_
:Чтобы увидеть различие между разделителем и разделителем , попробуйте:
Это разделит его на
var1
иvar2
только (без дополнительного пустого элемента).Итак, чтобы сделать его похожим на JavaScript
split()
, вам понадобится дополнительный шаг:(обратите внимание, что он разделит пустой элемент
$string
на 1 (не 0 ), как в JavaScriptsplit()
).Чтобы увидеть вкладку специальных процедур, пробел и перевод новой строки, сравните:
(где вы получаете
var1
иvar2
) сгде вы получите:
''
,var1
,''
,var2
,''
.Обратите внимание, что
zsh
оболочка не вызывает этот оператор split + glob неявным образом, если только вsh
илиksh
эмуляция. Там вы должны вызывать это явно.$=string
для части split,$~string
для части glob ($=~string
для обеих), а также есть оператор split, где вы можете указать разделитель:или сохранить пустые элементы:
Обратите внимание, что есть
s
для разделения , а не разграничения (также с$IFS
известным несоответствием POSIXzsh
). Он отличается от 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).В
zsh
оболочку встроена поддержка регулярных выражений, совместимых с Perl (в ееzsh/pcre
модуле), но использование ее для разделения строки, хотя и возможно, является относительно громоздким.источник
$PATH
на:
), наоборот, вы обычно хотите сохранить пустые элементы. Обратите внимание, что в оболочке Bourne все персонажи получали специальную обработку,ksh
изменив ее так, чтобы обрабатывались только пустые (только пробел, табуляция и новая строка).zsh
обработки строкой содержит 2 или более символов в${(s:string:)var}
? Если добавлено, я могу удалить свой ответ :)S
обозначает разделитель , а не разделитель . По крайней мере, так написано в руководстве по моему bash.$IFS
происходит из оболочки Bourne, где он был разделителем , ksh изменил поведение без изменения имени. Я упомянул это, чтобы подчеркнуть, чтоsplit+glob
(за исключением zsh или pdksh) просто больше не разделяется.Да, используйте
IFS
и установите его_
. Затем используйтеread -a
для сохранения в массив (-r
отключает расширение с обратной косой чертой). Обратите внимание, что это относится к bash; ksh и zsh имеют сходные возможности с немного отличающимся синтаксисом, а обычный sh вообще не имеет переменных массива.От
man bash
:Обратите внимание, что
read
останавливается на первой новой строке. Перейдите-d ''
к,read
чтобы избежать этого, но в этом случае в конце будет добавлен новый перевод строки из-за<<<
оператора. Вы можете удалить его вручную:источник
$r
что не содержит символов новой строки или обратной косой черты. Также обратите внимание, что он будет работать только в последних версияхbash
оболочки.bash
,read -a
был введен в Bash 4, верно?<<<
был добавлен только недавно,bash
но кажется, что он был там с 2.05b (2002).read -a
даже старше этого.<<<
приходитzsh
и поддерживаетсяksh93
(и mksh и yash), ноread -a
зависит от bash (это-A
ksh93, yash и zsh).