GNU/Linux >> Belajar Linux >  >> Linux

Bagaimana Cara Mengekstrak/Mengubah Baris Dalam File Teks Yang Datanya Dipisahkan Ke Dalam Bidang?

Bagaimana saya bisa memanipulasi data berbasis lapangan dari baris perintah? Misalnya

  • Bagaimana saya bisa mencetak hanya baris yang bidang ke-N-nya foo ?
  • Bagaimana saya bisa mencetak hanya baris yang bidang ke-N-nya bukan foo ?
  • Bagaimana saya bisa mencetak hanya baris yang bidang ke-N-nya cocok dengan foo ?
  • Bagaimana cara mengubah bidang N menjadi foo ?

Apakah ada pendekatan atau perangkat standar yang memfasilitasi manipulasi data berbasis lapangan pada sistem *nix?

Jawaban yang Diterima:

Ada dua pendekatan dasar yang dapat digunakan ketika berhadapan dengan bidang:i) menggunakan alat yang memahami bidang; ii) menggunakan ekspresi reguler. Dari keduanya, yang pertama biasanya lebih kuat dan lebih sederhana.

Banyak alat yang tersedia secara umum di *nix dirancang secara eksplisit untuk menangani bidang atau memiliki trik yang bagus untuk memfasilitasinya.

1. Gunakan alat yang memahami bidang

1.1 awk

Alat klasik di sini adalah awk . Ini akan secara otomatis membagi setiap baris input menjadi beberapa bidang (pemisah bidang adalah spasi putih secara default tetapi dapat diubah menggunakan -F flag) dan bidang tersebut kemudian tersedia untuk awk skrip sebagai $n dimana n adalah nomor lapangan. Kolom pertama adalah $1 , $2 yang kedua dll.

  • Cetak baris dengan bidang ke-3 foo .

    awk '$3=="foo"' file
    

    Mengubah pembatas menjadi :

    awk -F":" '$3=="foo"' file
    

    Tindakan default awk adalah untuk mencetak. Oleh karena itu perintah di atas akan mencetak semua baris yang bidang ke-3 adalah foo . Saat menggunakan -F , Anda dapat menyetel pemisah bidang arbitrer, dan bahkan menggunakan ekspresi reguler.

  • Bagaimana saya bisa mencetak hanya baris yang bidang ketiganya bukan foo ?

    awk '$3!="foo"' file
    
  • Bagaimana saya bisa mencetak hanya baris yang bidang ke-3 cocok dengan foo ?

    Jika Anda hanya mencari bidang yang cocok dengan pola (misalnya, foo cocok dengan foobar ), gunakan ~ bukannya == :

    awk '$3~/foo/' file
    
  • Bagaimana saya bisa mencetak hanya baris yang bidang ke-3 tidak cocok dengan foo ?

    awk '$3!~/foo/' file
    
  • Bagaimana saya bisa mengubah bidang ke-3 menjadi foo ?

    awk '$3="foo"' file
    

1.2 Perl

Pilihan lainnya adalah perl satu baris. Seperti awk, Perl adalah bahasa skrip berfitur lengkap tetapi juga dapat dijalankan sebagai program baris perintah dengan menggunakan skrip sebagai input. Perilakunya dimodifikasi oleh sakelar baris perintah, yang paling relevan untuk pertanyaan ini adalah:

  • -e :script yang perl harus dijalankan;
  • -n :membaca file input baris demi baris;
  • -p :mencetak setiap baris input setelah menerapkan skrip yang diberikan oleh -e;
  • -l :hapus baris baru yang tertinggal dari setiap baris input dan tambahkan baris baru ke setiap print panggilan;
  • -a :awk-mode, bagi setiap baris input ke dalam array @F;
  • -F :pemisah bidang untuk -a .

Perbedaan penting dengan awk apakah itu perl -a switch membagi file menjadi array. Di Perl, array dimulai dari 0, bukan 1. Ini berarti kolom ke-2 sebenarnya $F[1] dan bukan $F[2] . Dengan mengingat semua ini, perl padanan di atas adalah:

  • Cetak baris dengan bidang ke-3 foo .

    perl -ane 'print if $F[2] eq "foo"' file
    

    Mengubah pembatas menjadi :

    perl -F":" -ane 'print if $F[2] eq "foo"' file
    

    Tidak seperti awk , perl tidak dapat menggunakan ekspresi reguler sebagai pembatas bidang. Mereka harus berupa karakter atau string tertentu.

  • Bagaimana saya bisa mencetak hanya baris yang bidang ketiganya bukan foo ?

    perl -ane 'print unless $F[2] eq "foo"' file
    
  • Bagaimana saya bisa mencetak hanya baris yang bidang ke-3 cocok dengan foo ?

    perl -ane 'print if $F[2]=~/foo/' file
    
  • Bagaimana saya bisa mencetak hanya baris yang bidang ke-3 tidak cocok dengan foo ?

    perl -lane 'print unless $F[2]=~/foo/' file
    
  • Bagaimana saya bisa mengubah bidang ke-3 menjadi foo ?

    Yang ini sedikit lebih rumit di Perl. Pendekatan yang biasa dilakukan adalah mengubah nilai dalam @F array dan kemudian mencetak array. Dengan file sederhana yang dipisahkan oleh ruang, ini mudah:

    perl -lane '$F[2]="foo"; print "@F"' file
    

    Dengan pembatas yang berbeda, Anda harus join array. Jika tidak, akan dicetak dengan dipisahkan spasi:

    perl -F: -lane '$F[2]="foo"; print join ":",@F' file
    

2. Gunakan ekspresi reguler

Idenya di sini adalah menggunakan ekspresi reguler ("regex" untuk jangka pendek) yang menentukan posisi string target di baris. Misalnya, dalam file yang bidangnya dipisahkan oleh : , kita dapat menemukan kolom ke-2 dengan mencocokkan semuanya hingga : (bidang 1) dan kemudian mencari yang kedua:

^[^:]*:[^:]*:

Regex ini berarti:

  • ^ :awal baris;
  • [^] :kelas karakter yang dinegasikan. [^:] berarti “apa pun kecuali : “;
  • * :0 atau lebih dari pola sebelumnya;
  • : :sebuah : . literal;

Secara bersama-sama, ini berarti bahwa [^:]* pertama adalah bidang pertama dan yang kedua adalah bidang kedua. Jelas, ini tidak terlalu praktis jika Anda mencari bidang ke-14 tetapi dapat berguna untuk hal-hal yang lebih sederhana. Jadi, bagaimana kita menerapkan ini untuk memanipulasi data kita? Ada berbagai alat yang dapat melakukan ini; dalam contoh ini saya akan menggunakan sed tetapi Anda dapat melakukan hal yang sangat mirip dengan awk , perl atau python .

  • Bagaimana saya bisa mencetak hanya baris yang bidang ke-2 adalah foo ?

    sed -n '/^[^:]*:foo:/p' file
    

    -n menekan output normal dan /regex/p berarti “cetak semua baris yang cocok dengan ekspresi reguler.

  • Bagaimana saya bisa mencetak hanya baris yang bidang ke-2nya bukan foo ?

    sed '/^[^:]*:foo:/d' file
    

    Kebalikan logis dari di atas. Di sini, /regex/d berarti “hapus semua baris yang cocok dengan ekspresi reguler.

  • Bagaimana saya bisa mencetak hanya baris yang bidang ke-2 cocok dengan foo ?

    sed -n '/^[^:]*:[^:]*foo/p' file
    
  • Bagaimana saya bisa mencetak hanya baris yang bidang ke-2 tidak cocok dengan foo ?

    sed '/^[^:]*:[^:]*foo/d' file
    
  • Bagaimana saya bisa mengubah bidang ke-2 menjadi foo ?

    sed 's/([^:]*:)[^:]*/1foo/' file 
    

    Atau, karena sed substitusi dapat secara langsung mengatasi kemunculan pola dengan pengulangannya dengan flag numerik sederhana:

    sed 's/[^:]*/foo/2' file
    

Linux
  1. Bagaimana Cara Menghapus Garis Duplikat Di Dalam File Teks?

  2. Bagaimana Cara Menghapus Beberapa Baris Acak Dari File Teks Menggunakan Sed?

  3. Apa itu Mode Vim? Bagaimana Mengubahnya?

  1. Bagaimana cara menghitung jumlah nilai unik suatu bidang dalam file teks yang dibatasi tab?

  2. Mengubah banyak baris menjadi satu baris yang dipisahkan koma

  3. Bagaimana cara membagi satu file teks menjadi beberapa file *.txt?

  1. Bagaimana cara mengekstrak bagian teks dari file biner di linux/bash?

  2. bagaimana cara menyalin baris 10 hingga 15 file ke file lain, di unix?

  3. Bagaimana cara mengekstrak teks dari file besar, mulai dari kemunculan pertama string?