配列の各メンバーの前に追加して追加する方法は?

配列の各メンバーの前に追加して追加する方法は?

配列があります。

CATEGORIES=(one two three four)

パラメーター拡張を使用して、各配列メンバーの前に以下を追加できます。

echo ${CATEGORIES[@]/#/foo }

同じ方法で各配列メンバーに追加できます。

echo ${CATEGORIES[@]/%/ bar}

どのように両方を持つことができますか?次のいずれも機能しません。

echo ${CATEGORIES[@]/(.*)/foo \1 bar}
echo ${CATEGORIES[@]/(.*)/foo $1 bar}
echo ${CATEGORIES[@]/(.*)/foo ${BASH_REMATCH[1]} bar}

答え1

最終目標に応じて、以下を使用できますprintf

$ a=(1 2 3)
$ printf "foo %s bar\n" "${a[@]}"
foo 1 bar
foo 2 bar
foo 3 bar

printf書式文字列はすべての引数が使用されるまで再利用されるため、文字列セットにいくつかの書式を適用する簡単な方法が提供されます。

答え2

レコードの場合、with配列要素に中括弧などの拡張を開く演算子がzshあります。${^array}だから:

$ a=(one two three)
$ b=('foo '${^a}' bar')
$ printf '<%s>\n' $b
<foo one bar>
<foo two bar>
<foo three bar>

検索と置換も機能しますzsh

$ printf '<%s>\n' ${a//(#m)*/foo $MATCH bar}
<foo one bar>
<foo two bar>
<foo three bar>

そしてprintf -v配列から:

$ b=(); printf -v b 'foo %s bar' "$a[@]"
$ printf '<%s>\n' $b
<foo one bar>
<foo two bar>
<foo three bar>

echo ${CATEGORIES[@]/(.*)/foo \1 bar}作成された場合ksh93:

$ printf '<%s>\n' "${CATEGORIES[@]/@(.*)/foo \1 bar}"
<foo one bar>
<foo two bar>
<foo three bar>

答え3

p='* "foo  '
s='  bar $USER' 
CATEGORIES=(one two three four)
CATEGORIES=("${CATEGORIES[@]/#/$p}")
CATEGORIES=("${CATEGORIES[@]/%/$s}")

paste <(printf '[%s]\n' "${!CATEGORIES[@]}") \
      <(printf '%s\n'    "${CATEGORIES[@]}")

出力:

[0] * "foo  one  bar $USER
[1] * "foo  two  bar $USER
[2] * "foo  three  bar $USER
[3] * "foo  four  bar $USER

答え4

これは特別な場合追加された(または前に追加された)文字列が次の場合に適した解決策は次のとおりです。単一文字、新しい配列の値は必要ありません。

array=( aa bb cc )
IFS="]"                        # or, IFS="["
echo "${array[*]/#/ [}$IFS"    # or, echo "$IFS${array[*]/%/] }

出力を生成します[aa] [bb] [cc]

  • 引用形式は、"${array[*]}"各ペアの間に区切り文字を追加します(制約が現れる場所の最初の文字)。]IFS
  • ${array[*]/#/ [} [各要素の前に追加(または/%/フォームを追加)
  • 最後に拡張された値に末尾](from)を追加します。IFS

この手順を 1 つずつ適用すると、次のような結果が得られます。

aa]bb]cc
 [aa] [bb] [cc
 [aa] [bb] [cc]

(データを新しいアレイに簡単に復元することもできます。もしこの値にはスペースは含まれません。 )

1行でさまざまなプレフィックス/サフィックス操作を実行できます。

for ii in "${array[@]/#/foo }"; do echo "${ii/%/ bar}"; done

printf以下は、新しいアレイにコピーするより強力なソリューションです。

mapfile -d '' newarray < <(printf "foo %s bar\0" "${array[@]}")

サブシェルを犠牲にしても(bash-4.4が必要mapfile -d

最後に、新しい配列にコピーし、必要に応じてスパース配列と関連配列を処理できるループバリアントがあります。

declare -a array newarray   # -a for indexed array, -A for associative
array=( one two three )
for ii in "${!array[@]}"; do
  printf -v "newarray[$ii]" "foo %s bar" "${array[$ii]}"
done

printf必須ではありませんが、直接割り当てることができますが、IMHOはより明確です。bash(まだ!)しかし、配列への印刷をサポートすることで、zshループレスコピーとシングルライン変換が可能です。上記のStéphaneの回答を参照してください。)


ここで役に立つのは、拡張の一致文字列のプレースホルダとしてbashジェネリックがサポートされている場合&(たとえば$MATCH)です。zshコードはそこにあります。(そして長い間使用してきましたが)残念ながらまだアクティブではありません(shouldexp_replacement()参照subst.c)。有効にすると(#if 02回変更して再コンパイル)、期待どおりに機能します。

array=( aa bb cc )
newarray=( "${array[@]/*/foo & bar}" )

そうですね。次のバージョンでは可能かもしれません...

compgenプレフィックス/サフィックス操作があります(サポートされていますが、&ここで使用できる方法ではありません)。私たちができる最善はMuluのprintfソリューションよりも悪いです。

compgen -P "foo " -S " bar" -W "${array[*]}"

(ただ-W1つのオプションしか必要ないので、配列が平坦化され、スペースなどの値に問題が発生することに注意してくださいIFS

関連情報