私は配列を持っています:
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}
最終的な目的が何であるかに応じて、printf
を使用できます。
$ a=(1 2 3)
$ printf "foo %s bar\n" "${a[@]}"
foo 1 bar
foo 2 bar
foo 3 bar
printf
は、すべての引数がすべて使用されるまでフォーマット文字列を再利用するため、文字列のセットにフォーマットを適用する簡単な方法を提供します。
レコードの場合、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>
_
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
特別な場合の解決策は次のとおりです。これは、追加された(または追加された)文字列が単一の文字、新しい配列の値は必要ありません。
_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
にスペースまたは何かがある値で問題が発生します)