以下のように連想配列を作成しました。いくつかの詳細を提供するために、キーは特定のファイルを参照します。これは大きなスクリプトのコンテキストでこの配列を使用するためです(ファイルを含むディレクトリはgetoptsパラメータになります)。
declare -A BAMREADS
echo "BAMREADS array is initialized"
BAMREADS[../data/file1.bam]=33285268
BAMREADS[../data/file2.bam]=28777698
BAMREADS[../data/file3.bam]=22388955
echo ${BAMREADS[@]} # Output: 22388955 33285268 28777698
echo ${!BAMREADS[@]} # Output: ../data/file1.bam ../data/file2.bam ../data/file3.bam
これまで、この配列は私が期待したように動作するようです。この配列に基づいて別の連想配列を作成したいと思います。具体的には、2番目の配列は最初の配列と同じキーを持ちますが、$ MINという変数で値を分割したいと思います。
次の戦略のどれが最善かわからないし、どちらも正しく機能しないようです。
戦略1:配列をコピーして配列を変更しますか?
MIN=33285268
declare -A BRAMFRACS
echo "BAMFRACS array is initialized"
BAMFRACS=("${BAMREADS[@]}")
echo ${BAMFRACS[@]} # Output: 22388955 33285268 28777698
echo ${!BAMFRACS[@]} # Output: 0 1 2
これは私が望む鍵ではありません。動作していても、すべての値について述べた作業を行う必要があります。
戦略2:最初の配列を繰り返しながら2番目の配列を設定します。
MIN=33285268
declare -A BRAMFRACS
echo "BAMFRACS array is initialized"
for i in $(ls $BAMFILES/*bam)
do
echo $i
echo ${BAMREADS[$i]}
BAMFRACS[$i] = ${BAMREADS[$i]}
done
echo ${BAMFRACS[@]}
echo ${!BAMFRACS[@]}
#When I run this, I get the following error which I am unsure how to solve:
../data/file1.bam
33285268
script.bash: line 108: BAMFRACS[../data/file1.bam]: No such file or directory
../data/file2.bam
28777698
script.bash: line 108: BAMFRACS[../data/file2.bam]: No such file or directory
../data/file3.bam
22388955
script.bash: line 108: BAMFRACS[../data/file3.bam]: No such file or directory
ありがとう
答え1
連想配列のコピーに関するより一般的な質問に答えます。
管理者が4.0で独自の連想配列を導入したとき、bash
zsh APIの代わりにksh93 APIをコピーするという不幸な決定を下しました。
ksh93
/bash
は連想配列の設定を完全にサポートしますが、次のものと一致しません。
hash=([k1]=v1 [k2]=v2)
通事論。時間が経つとzsh
そうです。
hash=(k1 v1 k2 v2)
(([k]=v...)
ksh93構文のサポートは後で互換性のために追加されました)。
しかし、これはksh93とbashを使用して任意のキーと値のリストからハッシュを生成するのが非常に難しいことを意味します。
zsh
構文を使用すると、リストをキーと値を交互に渡すだけです。たとえば、2 つの連想配列をコピーするには、次のようにします。
h2=("${(@kv)h1}")
または2つの列を持つCSVでは:
IFS=$'\n,'; h=($(<file.csv))
またはキーと値の配列から:
h=("${(@)keys:^values}")
ksh93
/構文を使用するbash
と、キーと値のリスト(たとえば、inなど)に拡張できる"${!h[@]}"
andがありますが、目的の構文の(in)キーと値に拡張できる演算子はありません。"${h[@]}"
"${(@k)h}"
"${(@v)h}"
zsh
[key]=value
h=(...)
"${(@kv)h}"
zsh
ループ内の要素をコピーするのではなく、連想配列をコピーするためにこれらのシェルで使用できる1つの方法はtypeset -p
。
たとえば、次のようにコピーと同じ操作をzsh
実行できます。h2=("${(@kv)h1}")
h1
h2
ksh93
bash
h1_definition=$(typeset -p h1) &&
eval "typeset -A h2=${h1_definition#*=}"
bash
次のように短縮できます。
h1_definition=$(typeset -p h1) &&
typeset -A h2="${h1_definition#*=}"
(ksh93のようにtypeset -A h=value
inの省略形ですが、開始して終了した場合、内容は(参照されているか、一部の拡張の結果であっても)渡されたかのように複合関連付け割り当てとして解釈されます。typeset -A h=([0]=value)
bash
value
(
)
eval
(
最後に、ループを使用するのも簡単です。
for k in "${!h1[@]}"; do h2[$k]=${h1[$k]}; done
答え2
古い配列から新しい配列を作成します。
MIN=33285268
declare -A BRAMFRACS
for key in "${!BAMREADS[@]}"; do
BRAMFRACS[$key]=$(( ${BAMREADS[$key]} / MIN ))
done
コードに関するコメント:
最初の提案コードがコピーされたため、機能しません。価値連想配列から新しい配列へ。これらの値は自動的にキー0、1、2を取得しますが、元のキーはコピーされません。上記のようにキーごとに配列をコピーする必要があります。これにより、正しいキーに必要な値を割り当てることができます。
=
2番目の提案コードには、割り当ての周りにスペースがあるため、構文エラーがあります。ここで見ているエラーが発生します。 「オペランドを使用して実行されるコマンドvariable = value
」と解釈されます。variable
=
value
一連のパス名を繰り返すには、次のようにします。使用しないでください
ls
。代わりにfor pathname in "$BAMFILES"/*bam; do
。変数拡張を引用してください。
可変データを出力する
printf
代わりに使用を検討してください。echo
関連:
答え3
次のbashは、連想配列AA2(設定されていない可能性があります)の値を他の連想配列AA1(ほとんど-Aと宣言する必要があります)に割り当てます。
LIST="$(declare -p AA2 2>/dev/null)"
[[ "$LIST" ]] && AA1+=${LIST#*=}
declare -p
変数値をdeclare
ステートメントにエコーすることは、単語分割の問題なしにインタプリタに直接渡すことができます。${LIST#*=}
等号とその前のすべてを削除します。- ゼロ以外の長さテスト(
2>/dev/null
)中にエラー()を非表示にすると、AA2設定を無効にできます。declare
[[ "$LIST" ]]
- AA1またはAA2が連想配列ではない場合、予期しない結果(エラーではない)が発生します。
答え4
これにより、トリックを実行できます(追加のキー値も追加できます)。
declare -A origDict=( [keya]=value_a [keyb]=value_b [keyc]=value_c )
declare -a newDict=( echo ${origDict[*]} [keynew]=new_value )