В Bash, пуленепробиваемый способ, который будет работать, даже если ваша переменная содержит символы новой строки:
IFS=';' read -d '' -ra array < <(printf '%s;\0' "$in")
Посмотрите:
$ in=$'one;two three;*;there is\na newline\nin this field'
$ IFS=';' read -d '' -ra array < <(printf '%s;\0' "$in")
$ declare -p array
declare -a array='([0]="one" [1]="two three" [2]="*" [3]="there is
a newline
in this field")'
Хитрость для этого в том, чтобы использовать параметр -d
read
(разделитель) с пустым разделителем, так что read
вынужден читать все, что ему подается. И мы передаем read
точно с содержимым переменной in
, без завершающей строки, благодаря printf
. Обратите внимание, что мы также помещаем разделитель в printf
, чтобы строка, переданная в read
, имела конечный разделитель. Без него read
обрезает потенциальные конечные пустые поля:
$ in='one;two;three;' # there's an empty field
$ IFS=';' read -d '' -ra array < <(printf '%s;\0' "$in")
$ declare -p array
declare -a array='([0]="one" [1]="two" [2]="three" [3]="")'
конечное пустое поле сохраняется.
Обновление для Bash≥4,4
Начиная с Bash 4.4, встроенный mapfile
(он же readarray
) поддерживает опцию -d
для указания разделителя. Отсюда и другой канонический путь:
mapfile -d ';' -t array < <(printf '%s;' "$in")