Simpan setiap kemunculan yang ditemukan oleh awk ke sebuah array

Aug 20 2020

Pertanyaan saya sebelumnya ditandai "duplikat" dan saya diarahkan ke ini dan ini . Solusi yang diberikan pada utas tersebut tidak menyelesaikan masalah ini sama sekali.

Isi 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

Saya perlu mengekstrak baris "PATTERN1" dan "PATTERN2" + di antaranya, dan perintah berikut melakukannya dengan sempurna:

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

Keluaran:

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

Tapi sekarang saya mencoba membuat skrip bash yang:

  1. menggunakan awk untuk menemukan garis antara PATTERN1 dan PATTERN2
  2. simpan setiap kemunculan PATTERN1 + baris di antara + PATTERN2 dalam larik
  3. lakukan 1 & 2 hingga akhir file.

Untuk memperjelas. Berarti menyimpan baris berikut di dalam tanda kutip:

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

untuk array[0]

dan simpan baris berikut di dalam tanda kutip:

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

untuk array[1]

dan seterusnya ..... jika masih ada lagi PATTERN1 dan PATTERN2

Apa yang saya miliki saat ini:

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

Di atas tidak berhasil.
Dan sebisa mungkin saya tidak ingin menggunakan mapfile, karena script tersebut mungkin saja dijalankan pada sistem yang tidak mendukungnya.

Berdasarkan tautan ini disediakan:

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

Tapi saat aku melakukannya echo ${myarray[1]}

Saya mendapat jawaban kosong.

Dan saat aku melakukannya echo ${myarray[0]}

Saya mendapat:

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

Apa yang saya harapkan saat saya lakukan echo ${myarray[0]}

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

Apa yang saya harapkan saat saya melakukannya echo ${myarray[1]}

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

Segala bantuan akan sangat membantu.

Jawaban

2 PaulHodges Aug 20 2020 at 02:12

Seperti yang Charles sarankan ...

Diedit untuk menghapus baris baru dari dan blok (tidak setiap catatan)

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)

Saya memformatnya ulang. Agak sibuk dan sulit dibaca.

Dan untuk mengujinya -

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

Selain itu, tampaknya sangat aneh bagi saya untuk menyertakan nilai sentinel yang berlebihan dalam elemen data, jadi jika Anda ingin menghapusnya:

$: 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

Penerapan secara sederhana bashbisa jadi seperti itu:

#!/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

Jalankan sebagai ./script < file. Penggunaan awktidak diperlukan tetapi skrip akan bekerja dengan benar pada awkkeluaran juga.

ZYXRhythm Aug 20 2020 at 12:43

Jawaban Paul melakukan apa yang saya inginkan, jadi saya menandainya sebagai jawaban yang diterima. Meskipun solusinya menghasilkan baris tambahan kosong di bagian bawah setiap nilai yang disimpan dalam array, yang tidak masalah, tetap mudah untuk dihapus, jadi saya tidak keberatan. Tetapi saya juga memposting pertanyaan yang sama ini di situs lain, dan meskipun jawaban Paul bagus, saya menemukan solusi yang lebih baik:

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

Di atas melakukan tugasnya, tidak menghasilkan baris tambahan kosong, dan ini merupakan satu liner.

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

Keluaran:

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