Bash

循環中的多個管道,將管道結果保存到數組

  • July 25, 2018

我正在嘗試執行以下操作(使用 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]}

我假設您希望將輸出echo ... | awk儲存在一個變數中,特別是附加到其中一個數組中。

首先,要擷取命令的輸出,請使用"$( 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}')" )

(請注意,命令替換中的引號與其外部的引號不同。前面的引號$1不會停止在外部開始的引用$(),這與 SE 上的語法高亮似乎暗示的不同。)

您可以通過將管道放入函式中來使其更易於閱讀:

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)" )

(如果我正確閱讀了您的管道,也就是說,我沒有測試上述內容。)

引用自:https://unix.stackexchange.com/questions/458307