루프의 여러 파이프, 파이프 결과를 배열에 저장

루프의 여러 파이프, 파이프 결과를 배열에 저장

나는 다음을 수행하려고 합니다(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특히 배열 중 하나에 추가된 변수에 출력을 저장 하려고 한다고 가정합니다 .

먼저 명령의 출력을 캡처하려면 "$( 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)" )

(파이프라인을 올바르게 읽었다면 위의 내용을 테스트하지 않은 것입니다.)

관련 정보