Perintah shell Linux untuk memfilter file teks berdasarkan panjang baris

19

Saya memiliki gambar disk 30GB dari partisi borked (berpikir dd if=/dev/sda1 of=diskimage) bahwa saya perlu memulihkan beberapa file teks. Alat pahat data seperti foremosthanya bekerja pada file dengan header yang terdefinisi dengan baik, yaitu bukan file teks biasa, jadi saya kembali ke teman baik saya strings.

strings diskimage > diskstrings.txt menghasilkan file teks 3gb yang berisi banyak string, sebagian besar barang tidak berguna, dicampur dengan teks yang sebenarnya saya inginkan.

Sebagian besar cruft cenderung sangat panjang, string omong kosong yang tak terputus. Barang-barang yang saya minati dijamin kurang dari 16kb, jadi saya akan memfilter file menurut panjang baris. Inilah skrip Python yang saya gunakan untuk melakukannya:

infile  = open ("infile.txt" ,"r");
outfile = open ("outfile.txt","w");
for line in infile:
    if len(line) < 16384:
        outfile.write(line)
infile.close()
outfile.close()

Ini berfungsi, tetapi untuk referensi di masa mendatang: Apakah ada mantra satu baris ajaib (berpikir awk, sed) yang akan memfilter file berdasarkan panjang baris?

Li-aung Yip
sumber

Jawaban:

28
awk '{ if (length($0) < 16384) print }' yourfile >your_output_file.txt

akan mencetak garis lebih pendek dari 16 kilobyte, seperti pada contoh Anda sendiri.

Atau jika Anda suka Perl:

perl -nle 'if (length($_) < 16384) { print }' yourfile >your_output_file.txt
Janne Pikkarainen
sumber
Yah, itu sangat sederhana. Terima kasih. :)
Li-aung Yip
Ditambahkan juga versi Perl :-)
Janne Pikkarainen
Dan skrip awk dapat ditulis sebagai awk 'length($0) < 16384' file > output, karena tindakan default adalah mencetak baris.
glenn jackman
8

Ini mirip dengan jawaban Ansgar, tetapi sedikit lebih cepat dalam pengujian saya:

awk 'length($0) < 16384' infile >outfile

Ini kecepatan yang sama dengan jawaban awk lainnya. Itu bergantung pada implisit printekspresi yang sebenarnya, tetapi tidak perlu meluangkan waktu untuk membagi garis seperti yang dilakukan Ansgar.

Perhatikan bahwa AWK memberi Anda secara ifgratis. Perintah di atas setara dengan:

awk 'length($0) < 16384 {print}' infile >outfile

Tidak ada yang eksplisit if(atau sekumpulan kurung kurawal di sekitarnya) seperti pada beberapa jawaban lainnya.

Ini cara untuk melakukannya sed:

sed '/.\{16384\}/d' infile >outfile

atau:

sed -r '/.{16384}/d' infile >outfile

yang menghapus baris apa pun yang berisi 16384 (atau lebih) karakter.

Untuk kelengkapan, inilah cara yang akan Anda gunakan seduntuk menyimpan garis lebih lama dari ambang Anda:

sed '/^.\{0,16383\}$/d' infile >outfile
Dijeda sampai pemberitahuan lebih lanjut.
sumber
2

Anda bisa awkseperti:

$ awk '{ if (length($0) < 16384) { print } }' /path/to/text/file

Ini akan mencetak garis yang lebih pendek dari 16K karakter (16 * 1024).

Anda grepjuga dapat menggunakan :

$ grep ".\{,16384\}" /path/to/text/file

Ini akan mencetak garis paling banyak 16 ribu karakter.

Khaled
sumber
Tidak yakin grepitu ide yang bagus - itu adalah regexp sederhana, tentu saja, tetapi lebih mahal dari komputasi awk. "Seorang pria bermasalah mengatakan," Aku akan menggunakan ekspresi reguler! "Sekarang dia memiliki dua masalah." ;)
Li-aung Yip
Itu hanyalah cara lain untuk melakukannya. Opsi pertama yang saya posting menggunakan awk.
Khaled
1
+1 untuk regexp, karena golf lebih baik, dan itu tidak membuat saya membaca halaman awk =)
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件
2

Tidak benar-benar berbeda dari jawaban yang sudah diberikan, tetapi masih lebih pendek:

awk -F '' 'NF < 16384' infile >outfile
Ansgar Esztermann
sumber