Bagaimana cara menampilkan baris tertentu dari file teks di Linux?

85

Saya kira semua orang tahu utilitas Linux cmd line headdan tail. headmemungkinkan Anda untuk mencetak garis X pertama file, tailmelakukan hal yang sama tetapi mencetak akhir file. Apa perintah yang baik untuk mencetak tengah file? sesuatu seperti middle --start 10000000 --count 20(cetak baris 10'000'000 ke 10'000'010).

Saya mencari sesuatu yang akan menangani file besar secara efisien. Saya mencoba tail -n 10000000 | head 10dan sangat lambat.

Boas
sumber
5
kemungkinan duplikat dari serverfault.com/questions/101900/…
Kyle Brandt

Jawaban:

111
sed -n '10000000,10000020p' filename

Anda mungkin bisa mempercepatnya sedikit seperti ini:

sed -n '10000000,10000020p; 10000021q' filename

Dalam perintah-perintah itu, opsi -nmenyebabkan sed"menekan pencetakan otomatis ruang pola". The pperintah "print [s] ruang pola saat ini" dan qperintah "Segera berhenti [s] script sed tanpa pengolahan lagi masukan ..." Kutipan berasal dari sed manhalaman .

Ngomong-ngomong, perintahmu

tail -n 10000000 filename | head 10

dimulai pada baris sepersejuta dari akhir file, sedangkan perintah "tengah" Anda tampaknya mulai pada sepersejuta dari awal yang setara dengan:

head -n 10000010 filename | tail 10

Masalahnya adalah bahwa untuk file yang tidak disortir dengan garis panjang variabel, proses apa pun harus melalui file penghitungan baris baru. Tidak ada cara untuk pintas itu.

Namun, jika file diurutkan (file log dengan stempel waktu, misalnya) atau memiliki garis panjang tetap, maka Anda dapat mencari ke dalam file berdasarkan posisi byte. Pada contoh file log, Anda bisa melakukan pencarian biner untuk berbagai kali sebagai script Python saya di sini * tidak. Dalam kasus file dengan catatan panjang tetap, sangat mudah. Anda hanya mencari linelength * linecountkarakter ke dalam file.

* Saya tetap ingin memposting pembaruan lain untuk skrip itu. Mungkin aku akan menyiasatinya suatu hari nanti.

Dennis Williamson
sumber
Berikut ini adalah sedversi Charles' middlefungsi: middle() { local s=$1 c=$2; shift 2; sed -n "$s,$(($s + $c -1))p; $(($s + $c))q" "$@"; }. Ini akan menangani beberapa argumen file, nama file dengan spasi, dll. Banyak file diproses bersama seolah-olah mereka telah di-catted dengan cara yang sama seperti sedbiasanya (jadi 1000 file 100 tengah1 file2 akan merentang di ujung file pertama ke awal) dari yang kedua jika yang pertama memiliki kurang dari 1100 baris).
Dennis Williamson
Fungsi dalam komentar saya sebelumnya dapat dipanggil dengan parameter nama file: middle startline count filenameatau beberapa nama file: middle startline count file1 file2 file3atau dengan pengalihan: middle startline count < filenameatau dalam sebuah pipa: some_command | hitung garis tengah tengah` ataucat file* | middle startline count
Dennis Williamson
Bukankah seharusnya `dalam perintah sed Anda menjadi '? Saya tidak bisa membuatnya bekerja dengan backtick tetapi berfungsi dengan baik dengan kutipan tunggal.
Ian Hunter
@beanland: Ya, ini salah ketik. Saya sudah memperbaikinya. Terima kasih.
Dennis Williamson
1
@ kev: Saya menambahkan beberapa penjelasan untuk jawaban saya.
Dennis Williamson
28

Saya menemukan penggunaan berikut sed

sed -n '10000000,+20p'  filename

Semoga bermanfaat bagi seseorang!

Dox
sumber
Baik untuk mengetahui bahwa ada alternatif untuk argumen baris terakhir yang diajukan oleh Dennis: baris dihitung sebagai sed -nargumen kedua yang membuatnya cukup mudah dibaca.
user3123159
Contoh penggunaan: extract_lines(){sed -n "$1,+$2p" <file>}yang menulis ke stdout.
user3123159
4

Ini pertama kali saya memposting di sini! Bagaimanapun, ini mudah. Katakanlah Anda ingin menarik garis 8872 dari file Anda bernama file.txt. Inilah cara Anda melakukannya:

cat -n file.txt | grep '^ * 8872'

Sekarang pertanyaannya adalah menemukan 20 baris setelah ini. Untuk mencapai ini Anda lakukan

cat -n file.txt | grep -A 20 '^ * 8872'

Untuk garis di sekitar atau sebelum lihat flag -B dan -C di manual grep.

Dennis
sumber
Sementara itu secara teknis benar dan cara yang menarik untuk melakukannya pada file berukuran cukup, saya ingin tahu kemanjurannya ketika bekerja dengan file ukuran poster bertanya.
Jenny D
Beberapa baris: cat -n file.txt | grep "^ \ s \ + (10 \ | 20 \ | 30) \ s \ +"
Jeffrey Knight
cat -n file.txt | grep '^ *1'hasilkan semua garis yang memiliki 1 di sisi kanan mereka. Bagaimana cara output jalur 1 dengan teknik ini? Saya tahu saya bisa menuju ke-n 1 .... tapi bagaimana cara menggunakan grep?
Sean87
1

Jawaban sed Dennis adalah cara untuk pergi. Tetapi hanya dengan menggunakan kepala & ekor, di bawah bash:

middle () {head -n $ [$ 1 + $ 2] | ekor -n $ 2; }

Ini memindai $ 1 + $ 2 baris pertama dua kali, jadi jauh lebih buruk daripada jawaban Dennis. Tapi Anda tidak perlu mengingat semua surat-surat sed untuk menggunakannya ....

Charles Stewart
sumber
Penggunaan $[...]sudah usang, setidaknya di Bash. Selain itu, Anda kehilangan parameter file.
Dennis Williamson
@ Dennis: Tidak ada parameter yang hilang: Anda seharusnya menggunakan ini di stdin, sesuai middle 10 10 < /var/log/auth.log.
Charles Stewart
1

Gunakan perintah berikut untuk mendapatkan rentang garis tertentu

awk 'NR < 1220974{next}1;NR==1513793{exit}' debug.log | tee -a test.log

Di sini debug.log adalah file saya yang terdiri dari kurangnya garis dan saya digunakan untuk mencetak garis dari 1220974 nomor baris ke 1513793 ke file test.log. Saya harap ini akan membantu untuk menangkap rentang garis.

pemula13
sumber
Jawaban yang sama dengan serverfault.com/a/641252/140016 . Diturunkan.
Pemburu Rusa
Itu bukan jawaban yang sama. Ini harus lebih cepat untuk file besar karena sebenarnya dibatalkan setelah mencetak baris terakhir daripada melanjutkan pemindaian melalui file.
fobia
0

Versi oneliner ruby.

ruby -pe 'next unless $. > 10000000 && $. < 10000020' < filename.txt

Ini bisa bermanfaat bagi seseorang. Solusi dengan 'sed' yang disediakan oleh Dennis dan Dox sangat bagus, bahkan karena tampaknya lebih cepat.

beling
sumber
0

Anda dapat menggunakan 'nl'.

nl filename | grep <line_num>
Ajay
sumber
0

Misalnya orang awk ini akan mencetak garis antara 20 dan 40

awk '{if ((NR> 20) && (NR <40)) cetak $ 0}' / etc / passwd

Hrvoje Špoljar
sumber
0

Jika Anda tahu numebr baris, katakan Anda ingin mendapatkan baris 1, 3 dan 5 dari file, katakan / etc / passwd:

perl -e 'while(<>){if(++$l~~[1,3,5]){print}}' < /etc/passwd
Dagelf
sumber
0

Perl adalah raja:

perl -ne 'print if ($. == 10000000 .. $. == 10000020)' filename
Peter V. Mørch
sumber