จัดเก็บแต่ละเหตุการณ์ที่พบโดย 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

แต่ตอนนี้ฉันกำลังพยายามสร้างสคริปต์ทุบตีที่:

  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/')

ข้างต้นไม่ทำงาน
และเท่าที่จะเป็นไปได้ฉันไม่ต้องการใช้ mapfile เนื่องจากสคริปต์อาจถูกเรียกใช้งานบนระบบที่ไม่รองรับ

ตามลิงค์นี้ให้:

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]

ในทางกลับกันดูเหมือนเป็นเรื่องแปลกสำหรับฉันที่จะรวมค่า Sentinel ที่ซ้ำซ้อนในองค์ประกอบข้อมูลดังนั้นหากคุณต้องการตัดสิ่งเหล่านี้:

$: 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 จะดี แต่ฉันก็พบวิธีแก้ปัญหาที่ดีกว่า:

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