Saya mencari metode paling sederhana untuk mencetak baris terpanjang dalam file. Saya melakukan beberapa pencarian di Google dan secara mengejutkan tidak menemukan jawaban. Saya sering mencetak panjang garis terpanjang dalam sebuah file, tetapi saya tidak tahu bagaimana cara mencetak garis terpanjang. Adakah yang bisa memberikan solusi untuk mencetak baris terpanjang dalam file? Terima kasih sebelumnya.
35
Jawaban:
UPD : merangkum semua saran dalam komentar
sumber
cat
), dan menggunakan pipa adalah operasi yang mahal, belum lagi bahwa awk lebih efisien untuk hanya membaca file. Implikasi kinerja jelas terlihat jika hal ini sering dilakukan, dan meskipun demikian, Anda sepenuhnya menyalahgunakancat
.cat
tidak ada gunanya di sini. Mungkin tidak berguna untuk komputer tetapi bagi pembaca manusia itu bisa memberikan nilai. Varian pertama dengan jelas menunjukkan input. Alurnya lebih alami (dari kiri ke kanan). Dalam kasus kedua Anda tidak tahu apa inputnya kecuali Anda menggulir jendela.cat
.< file command
berfungsi dengan baik.< filename command
setara denganfilename < command
di setiap shell yang saya coba. Tetapi begitu Anda menyadarinya, Anda dapat memanfaatkannya saat menulis pipa panjang yang dengan jelas menunjukkan arah aliran data (tanpa menggunakan perintah tambahan):< input-file command1 | command2 | command3 > output-file
sumber
Ini pertama kali membaca file di dalam substitusi perintah dan menampilkan panjang baris terpanjang, (sebelumnya,
expand
mengkonversi tab menjadi spasi, untuk mengatasi semantikwc -L
- setiap tab di baris akan menambah 8 bukannya 1 ke panjang baris). Panjang ini kemudian digunakan dalamsed
ekspresi yang berarti "temukan garis yang panjangnya karakter ini, cetak, lalu keluar". Jadi ini sebenarnya bisa seoptimal garis terpanjang dekat dengan bagian atas file, heheh (terima kasih untuk komentar yang luar biasa dan konstruktif).Lain, saya telah berpikir lebih awal daripada yang sed (dalam bash):
sumber
-L, --max-line-length
mencetak panjang garis terpanjang, menurut halaman manual, tetapi jika Anda menggali lebih dalam (seperti ketika Anda mendapatkan hasil yang salah / tidak terduga ), Anda menemukan bahwa opsi ini menambah panjang dengan 8 untuk setiap 1 tab karakter\x09
lihat Unix & Linux T / Ased -rn "/.{$(<file expand -t1 |wc -L)}/p" file
read line
akan menafsirkan karakter backslash-lolos sebagai char literal, misalnya\A
resloves untukA
, yang tentu saja secara efektif melaporkan lebih pendek dari yang sebenarnya byte-penggunaan ... Untuk mencegah hal ini lolos interpretasi, gunakan:read -r line
. . . . Juga, untuk membuat versi sed + wc berhenti setelah "garis terpanjang" pertama, ubahp
ke{p;q}
..sed -rn "/.{$(<file expand -t1 |wc -L)}/{p;q}" file
Inilah solusi Perl:
Atau, jika Anda ingin mencetak semua garis terpanjang
Karena tidak ada yang lebih baik untuk dilakukan, saya menjalankan beberapa tolok ukur pada file teks 625M. Anehnya, solusi Perl saya secara konsisten lebih cepat daripada yang lain. Memang, perbedaan dengan
awk
solusi yang diterima kecil, tetapi ada di sana. Jelas, solusi yang mencetak beberapa baris lebih lambat jadi saya telah mengurutkannya berdasarkan jenis, tercepat hingga paling lambat.Cetak hanya satu dari garis terpanjang:
Cetak semua garis terpanjang:
sumber
Grep baris terpanjang pertama
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
- danwc
doa:## grep "^.{$( wc -L F )}$" F
The
wc
digunakan dalam ekspansi proses,$( ... )
sehingga dijalankan sebelumgrep
. 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<
inwc
menulis file ke stdin-nya, untuk mencegahwc
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.Tampilkan garis terpanjang pertama - garis pertama sepanjang garis terpanjang:
Tampilkan semua garis terpanjang - semua garis sepanjang garis terpanjang:
Tampilkan garis terpanjang terakhir - baris terakhir sepanjang garis terpanjang:
Tampilkan garis terpanjang tunggal - garis terpanjang lebih panjang dari semua garis lain, atau gagal:
(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 olehgrep
disimpan ke variabel.Perhatikan bahwa semua garis terpanjang mungkin sebenarnya semua baris Untuk menyimpan dalam suatu variabel, hanya dua baris pertama yang harus disimpan.)
sumber
Contoh berikut akan menjadi, dan seharusnya, komentar untuk jawaban dmitry.malikov , tetapi karena Penggunaan Ruang Komentar Terlihat yang Tidak Berguna di sana, saya telah memilih untuk menyajikannya di sini, di mana setidaknya akan terlihat. ..
Ini adalah variasi sederhana dari metode single-pass awk dmitry .
Ini mencetak semua garis "sama terpanjang". (Catatan.
delete array
Adalah ekstensi gawk).sumber
Dalam bash murni:
sumber
_max_line[0]=${_line}
tidak menghapus sisa dari "garis terpanjang" yang terakumulasi sebelumnya ... ...unset _max_line
akan menghapus seluruh array ...Saya telah mengembangkan skrip shell kecil untuk ini. Ini menampilkan panjang, garis # dan garis itu sendiri dengan panjang yang melebihi ukuran tertentu seperti 80 karakter:
https://github.com/lordofrain/tools/blob/master/longest-line/longest-line.sh
sumber
$*
jarang ide yang baik, Anda ingin"$@"
. Di/.*/
Andaawk
tidak melakukan apa-apa karena itu cocok dengan garis kosong juga. Anda dapat menghindari melarikan diri\$0
jika Anda mengutip tunggal'EOF'
. Mengapa menggunakanBEGIN{}
blok kosong ? Akhirnya, Anda tidak perlucat
, hanyaawk . . . "$file" | . . .
awk -vmax=15 '{len=length($0); if(len>=max){printf("%s, %d at line # %d %s\n", FILENAME, len, NR, $0);}}' file*
Anda bisa menggunakan
wc
:sumber
wc -L
kelemahannya.