awk에서 찾은 각 항목을 배열에 저장

Aug 20 2020

내 이전 질문은 "중복"으로 표시되었고 나는 이것 과 이것 에 대해 지적 했습니다 . 해당 스레드에서 제공되는 솔루션은이 문제를 전혀 해결하지 못합니다.

file.txt의 내용 :

Some line of text 0
Some line of text 1
Some line of text 2
PATTERN1
Some line of text 3
Some line of text 4
Some line of text 5
PATTERN2
Some line of text 6
Some line of text 7
Some line of text 8
PATTERN1
Some line of text 9
Some line of text 10
Some line of text 11
PATTERN2
Some line of text 12
Some line of text 13
Some line of text 14

사이에 "PATTERN1"과 "PATTERN2"+ 줄을 추출해야합니다. 다음 명령은이 작업을 완벽하게 수행합니다.

awk '/ PATTERN1 /, / PATTERN2 /'./file.txt

산출:

PATTERN1
Some line of text 3
Some line of text 4
Some line of text 5
PATTERN2

PATTERN1
Some line of text 9
Some line of text 10
Some line of text 11
PATTERN2

하지만 이제 다음과 같은 bash 스크립트를 만들려고합니다.

  1. awk를 사용하여 PATTERN1과 PATTERN2 사이의 줄을 찾습니다.
  2. 배열에 PATTERN1 + 줄 사이의 각 발생 + PATTERN2 저장
  3. 파일 끝까지 1 & 2를 수행합니다.

명확히하기 위해. 따옴표 안에 다음 줄을 저장하는 것을 의미합니다.

"PATTERN1
Some line of text 3
Some line of text 4
Some line of text 5
PATTERN2"

...에 array[0]

따옴표 안에 다음 줄을 저장하십시오.

"PATTERN1
Some line of text 9
Some line of text 10
Some line of text 11
PATTERN2"

...에 array[1]

등등 ..... PATTERN1 및 PATTERN2가 더 많이 발생하는 경우

내가 현재 가지고있는 것 :

#!/bin/bash
var0=`cat ./file.txt`
mapfile -t thearray < <(echo "$var0" | awk '/PATTERN1 /,/PATTERN2/')

위는 작동하지 않습니다.
스크립트가 지원하지 않는 시스템에서 실행될 수 있으므로 가능한 한 맵 파일을 사용하고 싶지 않습니다.

제공된 이 링크를 기반으로 :

myvar=$(cat ./file.txt)
myarray=($(echo "$var0" | awk '/PATTERN1 /,/PATTERN2/')) 

하지만 내가 할 때 echo ${myarray[1]}

빈 응답을받습니다.

그리고 내가 할 때 echo ${myarray[0]}

나는 얻다:

PATTERN1
Some line of text 3
Some line of text 4
Some line of text 5
PATTERN2

PATTERN1
Some line of text 9
Some line of text 10
Some line of text 11
PATTERN2

에코 할 때 기대하는 것 ${myarray[0]}

PATTERN1
Some line of text 3
Some line of text 4
Some line of text 5
PATTERN2

내가 할 때 기대하는 것 echo ${myarray[1]}

PATTERN1
Some line of text 9
Some line of text 10
Some line of text 11
PATTERN2

어떤 도움이라도 좋을 것입니다.

답변

2 PaulHodges Aug 20 2020 at 02:12

찰스 제안 ...

블록 에서 줄 바꿈을 제거하도록 편집 됨 (모든 레코드가 아님)

while IFS= read -r -d '' x; do array+=("$x"); done < <(awk ' /PATTERN1/,/PATTERN2/ { if ( $0 ~ "PATTERN2" ) { x=$0; printf "%s%c",x,0; next }
                          print }' ./file.txt)

다시 포맷했습니다. 조금 바쁘고 읽기가 어려워졌습니다.

그리고 그것을 테스트하기 위해-

$: echo "[${array[1]}]"
[PATTERN1
Some line of text 9
Some line of text 10
Some line of text 11
PATTERN2]

제쳐두고, 데이터 요소에 중복 된 센티넬 값을 포함하는 것은 매우 이상해 보입니다.

$: while IFS= read -r -d '' x; do array+=("$x"); done < <( awk '/PATTERN1/,/PATTERN2/{ if ( $0 ~ "PATTERN1" ) { next }
      if ( $0 ~ "PATTERN2" ) { len--; for (l in ary) { printf "%s%c", ary[l], l<len ? "\n" : 0; } delete ary; len=0; next } ary[len++]=$0;
    }' ./file.txt )

$: echo "[${array[1]}]"
[Some line of text 9
Some line of text 10
Some line of text 11]
3 M.NejatAydin Aug 20 2020 at 00:44

일반 구현은 bash다음과 같을 수 있습니다.

#!/bin/bash

beginpat='PATTERN1'
endpat='PATTERN2'

array=()
n=-1
inpatterns=
while read -r; do
    if [[ ! $inpatterns && $REPLY = $beginpat ]]; then array[++n]=$REPLY
        inpatterns=1
    elif [[ $inpatterns ]]; then array[n]+=$'\n'$REPLY if [[ $REPLY = $endpat ]]; then inpatterns= fi fi done # Report captured lines for ((i = 0; i <= n; ++i)); do printf "=== array[%d] ===\n%s\n\n" $i "${array[i]}"
done

로 실행 ./script < file. 의 사용은 awk필수는 아니지만 스크립트는 awk출력에서도 올바르게 작동합니다 .

ZYXRhythm Aug 20 2020 at 12:43

Paul의 대답은 내가 원하는 것을 수행하므로 수락 된 대답으로 표시했습니다. 그의 솔루션은 배열의 모든 저장된 값의 맨 아래에 빈 추가 라인을 생성하지만 괜찮습니다. 어쨌든 제거하기가 쉽기 때문에 신경 쓰지 않았습니다. 그러나 나는 또한이 같은 질문을 다른 사이트에 게시했으며 Paul의 대답은 좋았지 만 더 나은 해결책을 찾았습니다.

IFS=$'\r' read -d'\r' -a ARR < <(awk '/PATTERN1/,/PATTERN2/ {if($0 ~ /PATTERN2/) printf $0"\r"; else print}' file.txt)

위의 내용은 작업을 수행하고 빈 추가 줄을 생성하지 않으며 하나의 라이너입니다.

echo "${ARR[1]}"
echo "${ARR[0]}"

산출:

PATTERN1
Some line of text 9
Some line of text 10
Some line of text 11
PATTERN2

PATTERN1
Some line of text 3
Some line of text 4
Some line of text 5
PATTERN2