Simpan setiap kemunculan yang ditemukan oleh awk ke sebuah array
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:
- menggunakan awk untuk menemukan garis antara PATTERN1 dan PATTERN2
- simpan setiap kemunculan PATTERN1 + baris di antara + PATTERN2 dalam larik
- 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
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]
Penerapan secara sederhana bash
bisa 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 awk
tidak diperlukan tetapi skrip akan bekerja dengan benar pada awk
keluaran juga.
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