6

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

14

У меня есть массив в Bash, который выглядит следующим образом:

FOO=( a b c )

Как мне объединить элементы массива через запятую? Например, чтобы получить строку a,b,c.

5 ответ(ов)

3

В вашем примере вы задаете массив foo, состоящий из элементов a, "b c" и d.

Вот шаги, которые происходят в вашем коде:

  1. Вы создаете массив foo, в котором первый элемент — a, второй элемент — строка b c (с пробелом), и третий элемент — d.

    foo=(a "b c" d)
    
  2. Затем вы используете переменную IFS (Internal Field Separator) для временной установки разделителя на запятую. После этого вы выводите все элементы массива в строку, где элементы массива будут разделены запятой.

    bar=$(IFS=, ; echo "${foo[*]}")
    
  3. При выполнении команды echo "$bar" вы выводите значение переменной bar, которое будет a,b c,d.

Таким образом, итоговый вывод будет:

a,b c,d

Таким образом, пробел в строке "b c" сохраняется, так как он является частью одного элемента массива, а запятые вставляются между элементами массива при их объединении в строку.

2

Еще одно решение:

#!/bin/bash
foo=('foo bar' 'foo baz' 'bar baz')
bar=$(printf ",%s" "${foo[@]}")
bar=${bar:1}

echo $bar

Редактировать: то же самое, но для разделителя переменной длины с несколькими символами:

#!/bin/bash
separator=")|(" # например, для построения регулярного выражения, надеемся, что это не будет содержать %s
foo=('foo bar' 'foo baz' 'bar baz')
regex="$( printf "${separator}%s" "${foo[@]}" )"
regex="${regex:${#separator}}" # удаляем ведущий разделитель
echo "${regex}"
# Вывод: foo bar)|(foo baz)|(bar baz

В этом решении мы используем printf для создания строки, в которой элементы массива foo разделены заданным разделителем. В первом примере используется запятая в качестве разделителя, а во втором – строка с несколькими символами. С помощью обрезки строки мы удаляем ведущий разделитель, чтобы получить желаемый результат.

0

Да, вы можете сделать что-то подобное. Например, вы можете временно изменить значение переменной IFS (Internal Field Separator), чтобы объединить элементы массива с использованием определенного разделителя. Вот пример кода на Bash:

SAVE_IFS="$IFS"  # Сохраняем текущее значение IFS
IFS=","          # Устанавливаем разделитель на запятую
FOOJOIN="${FOO[*]}"  # Объединяем элементы массива FOO в строку
IFS="$SAVE_IFS"  # Восстанавливаем оригинальное значение IFS

echo "$FOOJOIN"  # Выводим объединенную строку

В этом коде мы сначала сохраняем текущее значение IFS. Затем устанавливаем IFS на запятую, что позволяет разделять элементы массива FOO запятой при объединении. После этого мы восстанавливаем оригинальное значение IFS, чтобы избежать неожиданных последствий в дальнейшем коде. Наконец, выводим объединенную строку. Это позволяет безопасно настраивать IFS, не повредив другие части вашего скрипта.

0

Вы можете достичь желаемого результата, не используя внешние команды, с помощью параметрической подстановки в Bash. Ниже приведен пример кода, который сначала инициализирует массив, затем преобразует его в строку, разделяя элементы запятой:

FOO=( a b c )          # инициализация массива
BAR=${FOO[@]}          # создание строки, разделенной пробелами, из массива
BAZ=${BAR// /,}        # использование параметрической подстановки для замены пробелов на запятые
echo $BAZ              # вывод результата

Вывод будет следующим:

a,b,c

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

0

Вот функция на чистом Bash, которая решает задачу:

join() {
    # $1 - имя переменной для возврата
    # $2 - разделитель
    # $3... - элементы для соединения
    local retname=$1 sep=$2 ret=$3
    shift 3 || shift $(($#))
    printf -v "$retname" "%s" "$ret${@/#/$sep}"
}

Посмотрите на пример использования:

$ a=( one two "three three" four five )
$ join joineda " and " "${a[@]}"
$ echo "$joineda"
one and two and three three and four and five
$ join joinedb randomsep "only one element"
$ echo "$joinedb"
only one element
$ join joinedc randomsep
$ echo "$joinedc"

$ a=( $' stuff with\nnewlines\n' $'and trailing newlines\n\n' )
$ join joineda $'a sep with\nnewlines\n' "${a[@]}"
$ echo "$joineda"
 stuff with
newlines
a sep with
newlines
and trailing newlines

$

Эта функция сохраняет даже завершающие переводы строк и не требует подсчета для получения результата. Если вам не нравится использование printf -v (почему бы и нет?) и передача имени переменной, вы можете, конечно, использовать глобальную переменную для возвращаемой строки:

join() {
    # $1 - разделитель
    # $2... - элементы для соединения
    # результат в глобальной переменной join_ret
    local sep=$1 IFS=
    join_ret=$2
    shift 2 || shift $(($#))
    join_ret+="${*/#/$sep}"
}

Таким образом, вы можете использовать обе версии функции в зависимости от ваших предпочтений.

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