web-dev-qa-db-ja.com

配列の各メンバーにどのように付加して追加できますか?

私は配列を持っています:

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}
7
Big McLargeHuge

最終的な目的が何であるかに応じて、printfを使用できます。

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

printfは、すべての引数がすべて使用されるまでフォーマット文字列を再利用するため、文字列のセットにフォーマットを適用する簡単な方法を提供します。

7
muru

レコードの場合、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>
_
7
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
5
Peter.O

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

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

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

  • 引用符付きの形式_"${array[*]}"_は、各ペアの間にセパレータ_]_を追加します(IFSの最初の文字、これは制約が発生する場所です)
  • _${array[*]/#/ [}_は各要素の前に_[_を追加します(または__/%/_フォームを追加します)
  • 最後に、末尾の_]_(IFSから)を展開された値に追加します

これらの手順を1つずつ適用すると、次のようになります。

_aa]bb]cc
 [aa] [bb] [cc
 [aa] [bb] [cc]
_

(データを新しい配列として簡単に復元することもできますif値に空白が含まれていません。)

ワンライナーで異なる前置/後置演算を行うことができます:

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

これは、新しい配列にコピーするより堅牢なprintfソリューションです。

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

サブシェルを犠牲にしても(_mapfile -d_にはbash-4.4が必要)

最後に、新しい配列にコピーし、必要に応じて疎および連想配列も処理するループバリエーション。

_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はサポートしています。ループのないコピーを作成し、ワンライナーを変換します。上記のステファンの回答を参照してください。)


ここで役立つのは、bashが展開で一致する文字列のプレースホルダーとして共通の_&_(zshの_$MATCH_など)をサポートしている場合です。 コードはそこにあります(そして長い間使用されてきました)が、残念ながらまだ有効になっていません(shouldexp_replacement()を参照してください- _subst.c_ )。これを有効にすると(2つの_#if 0_の変更と再コンパイル)、期待どおりに動作します。

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

とにかく、多分次のバージョンで利用できる...

compgenには接頭辞/接尾辞演算があります(_&_をサポートしていますが、ここでは使用できません)。私たちがそれでできる最善のことは、muruのprintfソリューションほど良くありません。

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

(_-W_は単一のオプションのみを取るため、配列はフラット化されることに注意してください。これにより、IFSにスペースまたは何かがある値で問題が発生します)

1
mr.spuratic