จัดเก็บแต่ละเหตุการณ์ที่พบโดย awk ไปยังอาร์เรย์
คำถามก่อนหน้านี้ของฉันถูกตั้งค่าสถานะ "ซ้ำ" และฉันก็ชี้ไปที่นี้และนี้ โซลูชันที่มีให้ในเธรดเหล่านั้นไม่สามารถแก้ปัญหานี้ได้เลย
เนื้อหาของ 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
แต่ตอนนี้ฉันกำลังพยายามสร้างสคริปต์ทุบตีที่:
- ใช้ awk เพื่อค้นหาเส้นระหว่าง PATTERN1 และ PATTERN2
- จัดเก็บแต่ละบรรทัด PATTERN1 + ระหว่าง + PATTERN2 ในอาร์เรย์
- ทำ 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
ความช่วยเหลือใด ๆ จะดีมาก
คำตอบ
ตามที่ชาร์ลส์แนะนำ ...
แก้ไขเพื่อตัดบรรทัดใหม่ออกจากและของบล็อก (ไม่ใช่ทุกระเบียน)
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]
การใช้งานแบบธรรมดา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
การส่งออกเช่นกัน
คำตอบของพอลทำในสิ่งที่ฉันต้องการฉันจึงตั้งค่าสถานะว่าเป็นคำตอบที่ยอมรับ แม้ว่าโซลูชันของเขาจะสร้างบรรทัดว่างที่ด้านล่างของทุกค่าที่เก็บไว้ในอาร์เรย์ซึ่งก็โอเค แต่ก็สามารถลบออกได้ง่ายดังนั้นฉันจึงไม่รังเกียจ แต่ฉันก็โพสต์คำถามเดียวกันนี้ในเว็บไซต์อื่นและแม้ว่าคำตอบของ 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