9

Как разделить строку на массив в Bash?

9

Вопрос: Как разделить строку на части и сохранить их в массиве в Bash-скрипте?

В Bash-скрипте мне нужно разделить строку на отдельные элементы и сохранить их в массиве.

Например, у меня есть следующая строка:

Paris, France, Europe

Я хотел бы получить массив, который будет выглядеть так:

array[0] = Paris
array[1] = France
array[2] = Europe

Предпочтительна простая реализация, скорость не имеет значения. Как я могу это сделать?

5 ответ(ов)

15

Чтобы разделить строку на массив, можно использовать следующую команду в 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}"

Более крупные отрицательные смещения позволяют выбрать элементы, находящиеся дальше от конца массива. Обратите внимание на пробел перед знаком минус в старой форме — он необходим.

1

Код, который вы предоставили, создает массив из строк, разделенных запятыми, затем выводит третий элемент массива. Давайте разберем его по шагам:

  1. Переменная t инициализируется строкой "one,two,three".
  2. С помощью команды echo и утилиты tr, запятые в строке заменяются на переносы строк ('\n'), таким образом каждая часть строки будет на новой строке.
  3. Результат этой команды помещается в массив a с использованием конструкции ($( ... )), которая выполняет команду в подстановке и создает массив из полученных строк.
  4. Наконец, команда echo "${a[2]}" выводит третий элемент массива (индексация начинается с 0), который в данном случае равен "three".

Таким образом, код выводит слово three.

Пример кода:

t="one,two,three"
a=($(echo "$t" | tr ',' '\n'))
echo "${a[2]}"  # вывод: three

Если вас интересует вывод элемента с индексом 2, это правильное решение.

0

Если ваш переменная содержит несколько строк, то метод из принятого ответа будет работать не совсем так. Для обработки многострочной переменной, например:

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.

0

Иногда у меня возникали проблемы с тем, что метод, описанный в принятом ответе, не работал, особенно если разделителем являлся символ перевода строки.

В таких случаях я решил задачу следующим образом:

string='первая строка
вторая строка
третья строка'

oldIFS="$IFS"
IFS='
'
IFS=${IFS:0:1} # это полезно для форматирования кода с табуляцией
lines=( $string )
IFS="$oldIFS"

for line in "${lines[@]}"
do
    echo "--> $line"
done

В этом примере я использую временное изменение IFS (внутренний разделитель полей) для корректного разделения строк. Сначала я сохраняю текущее значение IFS, затем устанавливаю его на символ перевода строки, чтобы правильно разбить данные на строки. После обработки я возвращаю IFS к его начальному значению. Таким образом, строки корректно обрабатываются и выводятся на экран.

0

Если вы используете macOS и не можете воспользоваться командой readarray, вы можете сделать следующее:

MY_STRING="string1 string2 string3"
array=($MY_STRING)

Чтобы перебрать элементы массива, используйте следующий код:

for element in "${array[@]}"
do
    echo $element
done

Таким образом, вы успешно создадите массив из строки и сможете итерироваться по его элементам.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь