Подтвердить что ты не робот

Префиксные и постфиксные элементы массива bash

Я хочу предварительно и постфиксный массив в bash аналогично расширению скобки.

Скажем, у меня есть массив bash

ARRAY=( one two three )

Я хочу иметь возможность пред- и постфиксации, как и следующее расширение раскладки

echo prefix_{one,two,three}_suffix

Лучшее, что я смог найти, использует bash regex для добавления префикса или суффикса

echo ${ARRAY[@]/#/prefix_}
echo ${ARRAY[@]/%/_suffix}

но я не могу найти ничего о том, как сделать это одновременно. Потенциально я мог бы использовать регулярные выражения и делать что-то вроде

echo ${ARRAY[@]/.*/prefix_$1_suffix}

но похоже, что захваты поддерживаются в подстановке переменных bash regex. Я мог бы также хранить временную переменную массива, например

PRE=(${ARRAY[@]/#/prefix_})
echo ${PRE[@]/%/_suffix}

Это, наверное, лучшее, что я могу придумать, но все же кажется, что он подпадает. Конечной альтернативой является использование цикла for, близкого к

EXPANDED=""
for E in ${ARRAY[@]}; do
    EXPANDED="prefix_${E}_suffix $EXPANDED"
done
echo $EXPANDED

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

4b9b3361

Ответ 1

Ваша последняя петля может быть выполнена с помощью witespace-friendly:

EXPANDED=()
for E in "${ARRAY[@]}"; do
    EXPANDED+=("prefix_${E}_suffix")
done
echo "${EXPANDED[@]}"

Ответ 2

Bash Расширение скобки не использует регулярные выражения. Используемый шаблон - это всего лишь некоторый shell glob, который вы можете найти в bash manual 3.5.8.1 Соответствие шаблону.

Ваше двухэтапное решение классно, но ему нужны некоторые цитаты для безопасности в виде пробелов:

ARR_PRE=("${ARRAY[@]/#/prefix_}")
echo "${ARR_PRE[@]/%/_suffix}"

Вы также можете сделать это каким-то злым образом:

eval "something $(printf 'pre_%q_suf ' "${ARRAY[@]}")"

Ответ 3

Более приятный, но по существу тот же, что и решение циклы:

$ ARRAY=(A B C)
$ mapfile -t -d $'\0' EXPANDED < <(printf "prefix_%s_postfix\0" "${ARRAY[@]}")
$ echo "${EXPANDED[@]}"
prefix_A_postfix prefix_B_postfix prefix_C_postfix

mapfile считывает строки в элементы массива. С помощью -d $'\0' вместо этого он считывает нулевые -d строки, а -t исключает разделитель из результата. См. help mapfile.

Ответ 4

Для массивов:

ARRAY=( one two three )
(IFS=,; eval echo prefix_\{"${ARRAY[*]}"\}_suffix)

Для строк:

STRING="one two three"
eval echo prefix_\{${STRING// /,}\}_suffix

eval заставляет его аргументы оцениваться дважды, в обоих случаях первые результаты оценки в

echo prefix_{one,two,three}_suffix

и второй выполняет его. Для массива case subhell используется, чтобы избежать перезапуска IFS

Вы также можете сделать это в zsh:

echo ${${ARRAY[@]/#/prefix_}/%/_suffix}

Ответ 5

У меня точно такой же вопрос, и я придумал следующее решение, используя механизм совпадения слов sed:

myarray=( one two three )
newarray=( $(echo ${myarray[*]}|sed "s/\(\b[^ ]\+\)/pre-\1-post/g") )
echo ${newarray[@]}
> pre-one-post pre-two-post pre-three-post
echo ${#newarray[@]}
> 3

Ожидание более элегантных решений...