Grep baris terpanjang pertama
grep -Em1 "^.{$(wc -L <file.txt)}\$" file.txt
Perintah ini sangat sulit dibaca tanpa latihan karena ia mencampur sintaks shell- dan regexp.
Untuk penjelasan, saya akan menggunakan kodesemu yang disederhanakan terlebih dahulu. Garis yang dimulai dengan ##
tidak berjalan di shell.
Kode yang disederhanakan ini menggunakan nama file F, dan tidak mengutip dan bagian dari regexps untuk dibaca.
Bagaimana itu bekerja
Perintah memiliki dua bagian, a grep
- dan wc
doa:
## grep "^.{$( wc -L F )}$" F
The wc
digunakan dalam ekspansi proses, $( ... )
sehingga dijalankan sebelum grep
. Ini menghitung panjang garis terpanjang. Sintaks ekspansi shell dicampur dengan sintaksis pola ekspresi reguler dengan cara yang membingungkan, jadi saya akan menguraikan ekspansi proses:
## wc -L F
42
## grep "^.{42}$" F
Di sini, ekspansi proses diganti dengan nilai yang akan dikembalikan, menciptakan baris grep
perintah yang digunakan. Kita sekarang dapat membaca ekspresi reguler dengan lebih mudah: Ini cocok persis dari awal ( ^
) hingga akhir ( $
) pada baris. Ekspresi di antara mereka cocok dengan karakter apa pun kecuali baris baru, diulang sebanyak 42 kali. Gabungan, yaitu garis yang terdiri dari 42 karakter.
Sekarang, kembali ke perintah real shell: grep
Opsi -E
( --extended-regexp
) memungkinkan untuk tidak luput dari {}
keterbacaan. Opsi -m 1
( --max-count=1
) membuatnya berhenti setelah baris pertama ditemukan. Perintah <
in wc
menulis file ke stdin-nya, untuk mencegah wc
dari pencetakan nama file bersama dengan panjangnya.
Garis terpanjang mana?
Untuk membuat contoh lebih mudah dibaca dengan nama file muncul dua kali, saya akan menggunakan variabel f
untuk nama file; Masing-masing $f
dalam contoh dapat diganti dengan nama file.
f="file.txt"
Tampilkan garis terpanjang pertama - garis pertama sepanjang garis terpanjang:
grep -E -m1 "^.{$(wc -L <"$f")}\$" "$f"
Tampilkan semua garis terpanjang - semua garis sepanjang garis terpanjang:
grep -E "^.{$(wc -L <"$f")}\$" "$f"
Tampilkan garis terpanjang terakhir - baris terakhir sepanjang garis terpanjang:
tac "$f" | grep -E -m1 "^.{$(wc -L <"$f")}\$"
Tampilkan garis terpanjang tunggal - garis terpanjang lebih panjang dari semua garis lain, atau gagal:
[ $(grep -E "^.{$(wc -L <"$f")}\$" "$f" | wc -l) = 1 ] && grep -E "^.{$(wc -L <"$f")}\$" "$f"
(Perintah terakhir bahkan lebih tidak efisien daripada yang lain, karena ia mengulangi perintah grep lengkap. Perintah ini harus diurai sehingga output dari wc
dan baris yang ditulis oleh grep
disimpan ke variabel.
Perhatikan bahwa semua garis terpanjang mungkin sebenarnya semua baris Untuk menyimpan dalam suatu variabel, hanya dua baris pertama yang harus disimpan.)