ループ内の複数のパイプ、パイプの結果を配列に保存する

ループ内の複数のパイプ、パイプの結果を配列に保存する

私は次のことをしようとしています(bashを使用)。常に同じ名前のファイルを検索し、そのファイルからデータを抽出します。抽出されたデータを新しい配列に保存したいのですが、ほとんど来たようです。以下のコードをご覧ください。

私が検索しているファイルはすべて次の形式を持っています。

 #!/bin/bash
  echo "the concentration of NDPH is 2 mM, which corresponds to 2 molecules in a box of size 12 nm (12 x 12 x 12 nm^3)" > README_test

#find all the README* files and save the paths into an array called files
  files=()
  data1=()
  data2=()
  data3=()

  while IFS=  read -r -d $'\0'; do
files+=("$REPLY")
  #open all the files and extract data from them
  while read -r line
  do
name="$line"
echo "$name" | tr ' ' '\n'|  awk 'f{print;f=0;exit} /of/{f=1}' 
echo "$name" 
echo "$name" | tr ' ' '\n'|  awk 'f{print;f=0;exit} /of/{f=1}'
data1+=( "$echo "$name" | tr ' ' '\n'|  awk 'f{print;f=0;exit} /of/{f=1}' )" )    

# variables are not preserved...
# data2+= echo "$name"  | tr ' ' '\n'|  awk 'f{print;f=0;exit} /is/{f=1}'
echo "$name"  | tr ' ' '\n'|  awk 'f{print;f=0;exit} /size/{f=1}'
# variables are not preserved... 
# data3+= echo "$name"  | tr ' ' '\n'|  awk 'f{print;f=0;exit} /size/{f=1}'
  done < "$REPLY"
  done < <(find . -name "README*" -print0)
  echo ${data1[0]}

問題は、私が望むファイルの正確な出力を提供するパイプがループ内で「動作しない」ということです(変数を保存しません)。パイプ出力(data1、data2、data3)で埋められた配列を取得するためにプロセス置換を使用できるかどうかわかりません。

更新:だから私は配列にものを正しく割り当てていません。 (data1を参照してください。今は正しく割り当てられています。)しかし、なぜですか?

echo ${data1[0]}

そして

echo "$name" | tr ' ' '\n'|  awk 'f{print;f=0;exit} /of/{f=1}'

いいえ、同じですか?

ソリューション(ilkkachuの回答に基づいています):

  #!/bin/bash
  echo "the concentration of NDPH is 2 mM, which corresponds to 2 molecules in a box of size 12 nm (12 x 12 x 12 nm^3)" > README_test
  files=()
  data1=()
  data2=()
  data3=()

  get_some_field() {    
 echo "$1" | tr ' ' '\n'|  awk -vkey="$2" 'f{print;f=0;exit} $0 ~ key {f=1}' 
  }

  #find all the README* files and save the paths into an array called files
  while IFS=  read -r -d $'\0'; do
files+=("$REPLY")
  #open all the files and extract data from them
  while read -r line
  do
name="$line"
echo "$name" 
echo "$name" | tr ' ' '\n'|  awk 'f{print;f=0;exit} /of/{f=1}'
data1+=( "$(get_some_field "$name" of)" )
data2+=( "$(get_some_field "$name" is)" )
data3+=( "$(get_some_field "$name" size)" )

  done < "$REPLY"
 done < <(find . -name "README*" -print0)

  echo ${data1[0]}
  echo ${data2[0]}
  echo ${data3[0]}

ベストアンサー1

echo ... | awk特に、配列の1つに追加された変数に出力を保存したいとします。

まず、コマンドの出力をキャプチャするには"$( cmd... )"(コマンドの置き換え)を使用します。簡単な例として、ホスト名が印刷されます。

var=$(uname -n)
echo $var

次に、配列に追加するには、右側に括弧付きの配列割り当て構文を使用する必要があります。これにより、var配列に値が追加されます。

array+=( $var )

第三に、拡張$varとコマンドの置換は$(...)単語セパレーターの影響を受けるため、単語区切り文字を括弧で囲む必要があります。もう一度簡単な例を挙げると、次のようなuname -a完全な出力が提供されます。一つ配列の要素:

array+=( "$(uname -a)" )

またはあなたの場合は、以下が完了します。

data1+=( "$(echo "$1" | tr ' ' '\n'|  awk 'f{print;f=0;exit} /of/{f=1}')" )

(コマンド置換の引用符は、コマンド置換の引用符と同じではありません。外部それ。前の参照は、SEで強調表示された構文が示唆するのとは異なり、$1externalで始まる参照を停止しません。$())

パイプを関数に入れると、読みやすくなります。

get_data1() {
    echo "$name" | tr ' ' '\n'|  awk 'f{print;f=0;exit} /of/{f=1}'
}
...
data1+=( "$(get_data1)" )

または、パイプラインが似ているように見えるので、この関数を使用してコードの重複を避けます。

get_some_field() {
    echo "$1" | tr ' ' '\n'|  awk -vkey="$2" 'f{print;f=0;exit} $0 ~ key {f=1}'
}

それから

data1+=( "$(get_some_field "$name" of)" )
data2+=( "$(get_some_field "$name" is)" )
data3+=( "$(get_some_field "$name" size)" )

(パイプラインを正しく読んだ場合は、上記の内容をテストしていません。)

おすすめ記事