Menangani 3 File menggunakan awk

9

Pertimbangkan file-file berikut:

file1:

boo,8,1024
foo,7,2048

file2:

foo,0,24,154
noo,0,10,561

file3:

24,154,7,1024,0

Yang saya butuhkan adalah pergi ke File1 dan periksa apakah $2==7; jika benar, ambil $1, $2dan $3dari File1 ; sekarang saya harus membandingkan jika $1dari File1 sama dengan $1dari File2 ; jika benar, saya harus mengambil $3dan $4dari File2 yang tidak ada di File1 , maka saya harus pergi ke File3 dan memeriksa apakah $1dari File3 sama dengan $3dari File2 , dan $2dari File3 sama dengan $4dari File2 ; jika ya, maka saya harus memeriksa jika $2dari File1adalah sama dengan $3dari file3 , maka jika kondisi ini benar, saya harus membandingkan $3dari File1 dengan $4dari file3 , jika $3dari File1 lebih dari $4dari file3 .

Saya mencoba skrip berikut:

cat [file1] [file2] [file3] | 
awk -F, 
'{if(NF==3)
    {if($2==7){a[$1]=$1; b[$1]=$2; c[$1]=$3}
    }else
        {if(NF==4){if(a[$1]==$1){d[$3]=$3; e[$4]=$4}
                  }else
                        {if(NF==5){if(d[$1]==$1 && e[$2]==$2){print a[$1], b[$1], c[$1], d[$1]}}
                        }
                  }

  }'

Output yang diinginkan adalah:

foo,7,2048,24,154,1024
Eng7
sumber

Jawaban:

9

Itu berhasil bagi saya:

awk -F, 'FNR==1{++f} \
  f==1 && $2==7 {a1[$1]++; a2[$2]=$3; o=$0} \
  f==2 && a1[$1] {o=o","$3","$4; a3[$3]=$4} \
  f==3 && a3[$1] && $2==a3[$1] && a2[$3] && $4<a2[$3] {print o}' \
file1 file2 file3

Penjelasan :

  • Baris pertama ( FNR==1{++f}) menambah indeks file untuk kemudian menentukan di mana file kita 1-3.
  • file1: jika $2sama dengan7
    • mengisi array a1dengan $1sebagai indeks dan a2dengan $2sebagai indeks dan $3sebagai nilai
    • tulis ovariabel (output) dengan 3 bidang pertama
  • file2: jika $1of file2equals $1dari file1(prevously ditulis dalam a1)
    • menambahkan $3dan $4ke variabel output o.
    • isi sebuah array a3dengan $3sebagai indeks dan $4sebagai nilai.
  • file3: jika:
    • $1sama dengan file2s $3(indeks a3)
    • $2sama dengan file2s $4(nilai a3)
    • $3sama dengan file1s $2(indeks a2)
    • $4lebih rendah dari file1s $3(nilai a2)
  • kemudian:
    • cetak nilai o.
kekacauan
sumber
Apakah ada kebutuhan untuk backslash (selain yang terakhir)? bagaimana dengan BEGINFILE (bukan FNR == 1)?
Archemar
@Archemar BEGINFILE dan ENDFILE adalah ekstensi melongo dan backslash semua dapat dihapus, saya sisipkan mereka, untuk keterbacaan yang lebih baik: Anda dapat menulis semuanya dalam satu baris tunggal, tetapi itu tidak akan terlihat bagus
kekacauan
@chaos, terima kasih, tapi sayangnya selalu mengembalikan nol.
Eng7
@ Azizieh7 Saya mengujinya dengan mawk dan gawk dengan 3 file contoh input Anda. Bagi saya itu berhasil. Apakah Anda menggunakan file input atau penyandian / linebreak yang berbeda?
chaos
@chaos, ada linebreak yang berbeda di file3, tapi saya menggunakan tr -d '\ 015' untuk mengatasi ini.
Eng7
1

Solusi TXR:

@(repeat)
@id,@val0,@val1
@  (next)
@  (skip)
@id,@nil,@val2,@val3
@  (next)
@val2,@val3,@val0,@val4,@val5
@  (require (< (int-str val4) (int-str val1)))
@  (output)
@id,@val0,@val1,@val2,@val3,@val4
@  (end)
@(end)

Lari:

$ txr join.txr file1 file2 file3
foo,7,2048,24,154,1024

Tetapi pengamat yang cerdik akan mencatat bahwa 7 belum ditentukan di mana pun dalam kode, hanya muncul di output! Itu karena kode sebenarnya berbaris melalui semua catatan file1dan mencetak semua kombinasi yang memenuhi kecocokan dan kendala . Satu-satunya di data sampel adalah satu dengan val0yang 7.

Jika ada lebih banyak kombinasi yang ditemukan, itu bisa dibatasi hanya yang 7seperti ini:

$ txr -Dval0=7 join.txr file1 file2 file3
foo,7,2048,24,154,1024

# how about 6?
$ txr -Dval0=6 join.txr file1 file2 file3
# no output

Bahasa ekstraksi pola TXR menyediakan di sini satu kecocokan pola besar dengan referensi balik implisit melalui pengulangan nama-nama variabel, mencakup beberapa file, dengan pola ekstraksi multi-garis, dan kendala non-tekstual, ditambah efek samping tertanam seperti output, dan sebagainya .

Solusi awk yang diterima dengan cermat menerjemahkan awkmakro TXR Lisp :

(awk (:begin (set fs "," ofs ","))
     (:let o (a1 (hash :equal-based)) (a2 (hash)) (a3 (hash)))
     (t (mf [orf int-str identity])) ;; map those fields to integers, which can be
     ((and (= arg 1) (= [f 1] 7)) (inc [a1 [f 0] 0])
                                  (set [a2 [f 1]] [f 2])
                                  (set o rec))
     ((and (= arg 2) [a1 [f 0]]) (set o `@o,@[f 2],@[f 3]`)
                                 (set [a3 [f 2]] [f 3]))
     ((and (= arg 3)
           [a3 [f 0]]
           (= [f 1] [a3 [f 0]])
           [a2 [f 2]]
           (< [f 3] [a2 [f 2]])) (prn o)))

Lari:

$ txr awkit.tl file1 file2 file3
foo,7,2048,24,154

Bagian yang ,1024diperlukan dalam output tidak ada; "Awk Classic" asli memiliki perilaku ini.

Kaz
sumber