Bagaimana cara grep file teks yang berisi beberapa data biner?

122

grep kembali

File biner test.log cocok

Sebagai contoh

echo    "line1 re \x00\r\nline2\r\nline3 re\r\n" > test.log  # in zsh
echo -e "line1 re \x00\r\nline2\r\nline3 re\r\n" > test.log  # in bash
grep re test.log

Saya berharap hasilnya akan menunjukkan baris1 dan baris3 (total dua baris).

Apakah mungkin menggunakan trkonversi data yang tidak dapat dicetak menjadi data yang dapat dibaca, agar grep berfungsi kembali?

Daniel YC Lin
sumber
Harap dicatat bahwa ada program yang memfilter karakter biner dari file biner dan hanya menyimpan karakter teks (dapat dibaca). Di sini: soft.tahionic.com/download-words_extractor/index.html
InTheNameOfScience
Maaf, tapi ... kau tidak hilang -edalam echoperintah?
Sopalajo de Arrierez
Jika Anda menggunakan 'zsh', tidak masalah tanpa -e. Jika Anda menggunakan 'bash', Anda harus menambahkan '-e'.
Daniel YC Lin
serverfault.com/questions/328101/…
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Jawaban:

67

Anda dapat menjalankan file data melalui cat -v, misalnya

$ cat -v tmp/test.log | grep re
line1 re ^@^M
line3 re^M

yang kemudian bisa diproses lebih lanjut untuk membuang sampah; ini paling mirip dengan kueri Anda tentang penggunaan truntuk tugas.

vielmetti
sumber
5
Memecahkan masalah saya. Terima kasih! Inilah yang man catdikatakan tentang -v:-v, --show-nonprinting use ^ and M- notation, except for LFD and TAB
tommy.carstensen
Perhatikan bahwa ini juga berfungsi di pipeline. Misalnyaset | cat -v | grep variable
funroll
1
Mengapa menggunakan ini jika grep --text berfungsi? Ini tampaknya jauh lebih kompleks.
Michael Haefele
grep --texttidak selalu berhasil; itu menghormati CTRL + D sebagai terminator file. Jadi jika Anda memilikinya di file biner Anda, grep akan keluar lebih awal.
Tommy
110
grep -a

Tidak bisa lebih sederhana dari itu.

James Selvakumar
sumber
3
ini sama dengan grep --textyang disebutkan paxdiablo 2 tahun sebelumnya
user829755
4
Ya, kecuali bahwa ini tidak akan berfungsi di OSX kecuali Anda melakukan hal berikut:LC_ALL="C" grep -a
Chris Stratton
91

Salah satu caranya adalah dengan memperlakukan file biner sebagai teks saja, grep --texttetapi ini dapat mengakibatkan informasi biner dikirim ke terminal Anda. Itu bukan ide yang bagus jika Anda menjalankan terminal yang menafsirkan aliran keluaran (seperti VT / DEC atau banyak lainnya).

Atau, Anda dapat mengirim file Anda melalui tr perintah berikut:

tr '[\000-\011\013-\037\177-\377]' '.' <test.log | grep whatever

Ini akan mengubah apa pun yang kurang dari karakter spasi (kecuali baris baru) dan apa pun yang lebih besar dari 126, menjadi a . karakter, hanya menyisakan barang cetakan.


Jika Anda ingin setiap karakter "ilegal" diganti dengan yang berbeda, Anda dapat menggunakan sesuatu seperti program C berikut, filter input standar klasik:

#include<stdio.h>
int main (void) {
    int ch;
    while ((ch = getchar()) != EOF) {
        if ((ch == '\n') || ((ch >= ' ') && (ch <= '~'))) {
            putchar (ch);
        } else {
            printf ("{{%02x}}", ch);
        }
    }
    return 0;
}

Ini akan memberimu {{NN}} , di mana NNkode hex untuk karakter tersebut. Anda cukup menyesuaikan fileprintf untuk gaya keluaran apa pun yang Anda inginkan.

Anda dapat melihat program itu beraksi di sini, di mana:

pax$ printf 'Hello,\tBob\nGoodbye, Bob\n' | ./filterProg
Hello,{{09}}Bob
Goodbye, Bob
paxdiablo
sumber
Metode ini memetakan semua karakter biner menjadi '.' simbol. Apakah ada metode lain yang memetakannya menjadi simbol yang dapat dibaca?
Daniel YC Lin
Tentu, Anda dapat menjalankannya melalui program filter yang berbeda, salah satunya saya berikan di pembaruan.
paxdiablo
1
Saya pikir tr '[:cntrl:] '.'lebih baik. Dan itu harus ada \000-\010\013\014\016-\037\177-\377'dalam sintaks tr Anda.
Daniel YC Lin
2
Setelah pengujian, tr '[\000-\010\013\014\016-\037\177-\377]' '_'bisa diterapkan, cntrl tidak cocok untuk kasus saya.
Daniel YC Lin
2
Anda dapat menyimpan catlangkah dengan menyalurkan grep --textke tralih-alih sebaliknya. Ini juga memungkinkan Anda menggrep beberapa file dan menyimpan referensi nama file dalam output.
aaaantoine
33

Anda dapat menggunakan "string" untuk mengekstrak string dari file biner, misalnya

strings binary.file | grep foo
murung
sumber
Bekerja dengan baik untuk saya karena sumbernya adalah log debug dengan UID di setiap baris. Terima kasih.
mbrownnyc
bekerja dengan baik untuk saya juga. Terima kasih atas jawaban anda. Menyelamatkan hari saya :)
Shekhar
2
Saya menghargai jawaban @paxdiablo tetapi untuk jawaban cepat dan melanjutkan pekerjaan Anda tidak dapat menyalahkan ini.
Wil
Mencoba menggunakan solusi paxdiablo namun tidak memberi saya hasil yang saya harapkan. @moodywoody solusi Anda cepat, sederhana dan menghasilkan apa yang saya butuhkan!
justinhartman
20

Anda dapat memaksa grep untuk melihat file biner dengan:

grep --binary-files=text

Anda mungkin juga ingin menambahkan -o( --only-matching) sehingga Anda tidak mendapatkan banyak omong kosong biner yang akan mengganggu terminal Anda.

AB
sumber
mungkin mengeluarkan sampah biner, yang dapat memiliki efek samping yang buruk jika keluarannya adalah terminal dan jika pengandar terminal menafsirkan sebagian sebagai perintah.
Daniel YC Lin
Jika Anda menggunakan --only-matching, dan regex Anda tidak cocok dengan data biner arbitrer, Anda tidak akan mendapat masalah.
AB
jika ekspresi reguler adalah 'first. * end' dan data biner berisi pola '. *', itu tidak dapat memperbaiki proses untuk pemrosesan posting saya. Terima kasih.
Daniel YC Lin
16

Dimulai dengan Grep 2.21, file biner diperlakukan secara berbeda :

Saat mencari data biner, grep sekarang dapat memperlakukan byte non-teks sebagai terminator baris. Ini dapat meningkatkan kinerja secara signifikan.

Jadi yang terjadi sekarang adalah dengan data biner, semua byte non-teks (termasuk baris baru) diperlakukan sebagai terminator baris. Jika Anda ingin mengubah perilaku ini, Anda dapat:

  • gunakan --text. Ini akan memastikan bahwa hanya baris baru yang merupakan terminator baris

  • gunakan --null-data. Ini akan memastikan bahwa hanya null byte yang merupakan terminator baris

Steven Penny
sumber
5

grep -a akan memaksa grep untuk mencari dan mengeluarkan dari file yang menurut grep adalah biner. grep -a re test.log

Kevin Buchs
sumber
3

Seperti yang sudah dikatakan James Selvakumar, grep -alakukan triknya. -a atau --text memaksa Grep untuk menangani inputstream sebagai teks. Lihat Manpage http://unixhelp.ed.ac.uk/CGI/man-cgi?grep

mencoba

cat test.log | grep -a somestring
DerKnorr
sumber
2

Anda dapat melakukan

strings test.log | grep -i

ini akan mengubah keluaran give sebagai string yang dapat dibaca ke grep.

Mrid
sumber
0

Anda juga dapat mencoba alat Word Extractor . Word Extractor dapat digunakan dengan file apa pun di komputer Anda untuk memisahkan string yang berisi teks / kata manusia dari kode biner (aplikasi exe, DLL).

MattCollW
sumber
Saya kasus saya, saya tidak memerlukan ekstraktor kata, saya perlu menyimpan nomor baris.
Daniel YC Lin
0

Inilah yang saya gunakan dalam sistem yang tidak menginstal perintah "string"

cat yourfilename | tr -cd "[:print:]"

Ini mencetak teks dan menghapus karakter yang tidak dapat dicetak dalam satu gerakan, tidak seperti "cat -v nama file" yang memerlukan beberapa proses pasca untuk menghapus hal-hal yang tidak diinginkan. Perhatikan bahwa beberapa data biner mungkin dapat dicetak sehingga Anda masih akan mendapatkan beberapa omong kosong di antara hal-hal yang bagus. Saya pikir string juga menghilangkan omong kosong ini jika Anda bisa menggunakannya.

Muurder
sumber