Как разделить строку на массив в Bash?
Вопрос: Как разделить строку на части и сохранить их в массиве в Bash-скрипте?
В Bash-скрипте мне нужно разделить строку на отдельные элементы и сохранить их в массиве.
Например, у меня есть следующая строка:
Paris, France, Europe
Я хотел бы получить массив, который будет выглядеть так:
array[0] = Paris
array[1] = France
array[2] = Europe
Предпочтительна простая реализация, скорость не имеет значения. Как я могу это сделать?
5 ответ(ов)
Чтобы разделить строку на массив, можно использовать следующую команду в Bash:
IFS=', ' read -r -a array <<< "$string"
Обратите внимание, что символы, указанные в переменной $IFS
, обрабатываются индивидуально как разделители. В данном случае это означает, что поля могут разделяться либо запятой, либо пробелом, а не последовательностью из этих двух символов. Примечательно, что при наличии запятой и пробела подряд в исходных данных пустые поля не создаются, так как пробел обрабатывается особым образом.
Чтобы получить доступ к отдельному элементу массива, можно использовать следующую конструкцию:
echo "${array[0]}"
Для перебора всех элементов массива используйте следующий цикл:
for element in "${array[@]}"
do
echo "$element"
done
Если вам нужно получить как индекс, так и значение элемента, можно сделать это следующим образом:
for index in "${!array[@]}"
do
echo "$index ${array[index]}"
done
Этот последний пример полезен, поскольку массивы в Bash могут быть разреженными. Это означает, что вы можете удалить элемент или добавить новый, и при этом индексы не будут последовательными.
unset "array[1]"
array[42]=Earth
Чтобы получить количество элементов в массиве, используйте следующую команду:
echo "${#array[@]}"
Как уже упоминалось, массивы могут быть разреженными, поэтому не стоит использовать длину массива, чтобы получить последний элемент. Вот как это можно сделать для Bash 4.2 и новее:
echo "${array[-1]}"
Для любой версии Bash (начиная где-то с 2.05b) можно воспользоваться следующей конструкцией:
echo "${array[@]: -1:1}"
Более крупные отрицательные смещения позволяют выбрать элементы, находящиеся дальше от конца массива. Обратите внимание на пробел перед знаком минус в старой форме — он необходим.
Код, который вы предоставили, создает массив из строк, разделенных запятыми, затем выводит третий элемент массива. Давайте разберем его по шагам:
- Переменная
t
инициализируется строкой"one,two,three"
. - С помощью команды
echo
и утилитыtr
, запятые в строке заменяются на переносы строк ('\n'
), таким образом каждая часть строки будет на новой строке. - Результат этой команды помещается в массив
a
с использованием конструкции($( ... ))
, которая выполняет команду в подстановке и создает массив из полученных строк. - Наконец, команда
echo "${a[2]}"
выводит третий элемент массива (индексация начинается с 0), который в данном случае равен"three"
.
Таким образом, код выводит слово three
.
Пример кода:
t="one,two,three"
a=($(echo "$t" | tr ',' '\n'))
echo "${a[2]}" # вывод: three
Если вас интересует вывод элемента с индексом 2, это правильное решение.
Если ваш переменная содержит несколько строк, то метод из принятого ответа будет работать не совсем так. Для обработки многострочной переменной, например:
string='first line
second line
third line'
вам потребуется использовать другой подход для получения всех строк. Один из способов — воспользоваться циклом while
с командой read
:
while read -r line; do lines+=("$line"); done <<<"$string"
Однако в Bash есть более простой способ — использовать команду readarray
:
readarray -t lines <<<"$string"
Чтобы вывести все строки, можно воспользоваться возможностями printf
, что делается очень просто:
printf ">[%s]\n" "${lines[@]}"
Это приведёт к следующему выводу:
>[first line]
>[ second line]
>[ third line]
Таким образом, использование readarray
позволяет легко и удобно работать с многострочными строками в Bash.
Иногда у меня возникали проблемы с тем, что метод, описанный в принятом ответе, не работал, особенно если разделителем являлся символ перевода строки.
В таких случаях я решил задачу следующим образом:
string='первая строка
вторая строка
третья строка'
oldIFS="$IFS"
IFS='
'
IFS=${IFS:0:1} # это полезно для форматирования кода с табуляцией
lines=( $string )
IFS="$oldIFS"
for line in "${lines[@]}"
do
echo "--> $line"
done
В этом примере я использую временное изменение IFS
(внутренний разделитель полей) для корректного разделения строк. Сначала я сохраняю текущее значение IFS
, затем устанавливаю его на символ перевода строки, чтобы правильно разбить данные на строки. После обработки я возвращаю IFS
к его начальному значению. Таким образом, строки корректно обрабатываются и выводятся на экран.
Если вы используете macOS и не можете воспользоваться командой readarray
, вы можете сделать следующее:
MY_STRING="string1 string2 string3"
array=($MY_STRING)
Чтобы перебрать элементы массива, используйте следующий код:
for element in "${array[@]}"
do
echo $element
done
Таким образом, вы успешно создадите массив из строки и сможете итерироваться по его элементам.
Как пройтись по массиву строк в Bash?
Разделить массив на части
Добавить новый элемент в массив в Bash без указания индекса
Как изменить цвет вывода echo в Linux
Как перемешать (сделать случайным) массив в JavaScript?