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 adalahfoo
. 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 denganfoobar
), 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 yangperl
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 setiapprint
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