Как я могу объединить элементы массива в Bash? - PullRequest
356 голосов
/ 06 октября 2009

Если у меня есть такой массив в Bash:

FOO=( a b c )

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

Ответы [ 28 ]

7 голосов
/ 29 октября 2018

Это не слишком отличается от существующих решений, но позволяет избежать использования отдельной функции, не изменяет IFS в родительской оболочке и находится в одной строке:

arr=(a b c)
printf '%s\n' "$(IFS=,; printf '%s' "${arr[*]}")"

в результате

a,b,c

Ограничение: разделитель не может быть длиннее одного символа.

4 голосов
/ 11 февраля 2016

Укороченная версия топ-ответа:

joinStrings() { local a=("${@:3}"); printf "%s" "$2${a[@]/#/$1}"; }

Использование:

joinStrings "$myDelimiter" "${myArray[@]}"
4 голосов
/ 20 ноября 2017

Объедините лучшее из всех миров до сих пор со следующей идеей.

# join with separator
join_ws()  { local IFS=; local s="${*/#/$1}"; echo "${s#"$1$1$1"}"; }

Этот маленький шедевр

  • 100% чистый bash (расширение параметра с IFS временно не установлено, без внешних вызовов, без printf ...)
  • компактный, полный и безупречный (работает с одно- и многосимвольными ограничителями, работает с ограничителями, содержащими пробелы, разрывы строк и другие специальные символы оболочки, работает с пустым разделителем)
  • эффективный (без вложенной оболочки, без копирования массива)
  • простой и глупый и, в некоторой степени, красивый и поучительный, а также

Примеры:

$ join_ws , a b c
a,b,c
$ join_ws '' a b c
abc
$ join_ws $'\n' a b c
a
b
c
$ join_ws ' \/ ' A B C
A \/ B \/ C
4 голосов
/ 29 июня 2012
$ set a 'b c' d

$ history -p "$@" | paste -sd,
a,b c,d
4 голосов
/ 05 июня 2013

printf решение, которое принимает разделители любой длины (на основе @ не имеет значения, ответ)

#/!bin/bash
foo=('foo bar' 'foo baz' 'bar baz')

sep=',' # can be of any length
bar=$(printf "${sep}%s" "${foo[@]}")
bar=${bar:${#sep}}

echo $bar
1 голос
/ 19 июня 2014

Используйте perl для разделителей с несколькими символами:

function join {
   perl -e '$s = shift @ARGV; print join($s, @ARGV);' "$@"; 
}

join ', ' a b c # a, b, c

или в одну строку:

perl -le 'print join(shift, @ARGV);' ', ' 1 2 3
1, 2, 3
1 голос
/ 06 октября 2009

Прямо сейчас я использую:

TO_IGNORE=(
    E201 # Whitespace after '('
    E301 # Expected N blank lines, found M
    E303 # Too many blank lines (pep8 gets confused by comments)
)
ARGS="--ignore `echo ${TO_IGNORE[@]} | tr ' ' ','`"

Что работает, но (в общем случае) ужасно сломается, если в элементах массива будет пробел.

(Для тех, кто заинтересован, это скрипт-оболочка для pep8.py )

1 голос
/ 11 апреля 2013

Если элементы, к которым вы хотите присоединиться, - это не массив, а строка, разделенная пробелами, вы можете сделать что-то вроде этого:

foo="aa bb cc dd"
bar=`for i in $foo; do printf ",'%s'" $i; done`
bar=${bar:1}
echo $bar
    'aa','bb','cc','dd'

Например, мой вариант использования заключается в том, что в моем сценарии оболочки передаются некоторые строки, и мне нужно использовать это для запуска SQL-запроса:

./my_script "aa bb cc dd"

В my_script мне нужно сделать "SELECT * FROM table WHERE name IN (" aa "," bb "," cc "," dd "). Тогда приведенная выше команда будет полезна.

1 голос
/ 15 мая 2014

Моя попытка.

$ array=(one two "three four" five)
$ echo "${array[0]}$(printf " SEP %s" "${array[@]:1}")"
one SEP two SEP three four SEP five
1 голос
/ 14 декабря 2018

Вот что поддерживает большинство POSIX-совместимых оболочек:

join_by() {
    # Usage:  join_by "||" a b c d
    local arg arr=() sep="$1"
    shift
    for arg in "$@"; do
        if [ 0 -lt "${#arr[@]}" ]; then
            arr+=("${sep}")
        fi
        arr+=("${arg}") || break
    done
    printf "%s" "${arr[@]}"
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...