จะ grep ไฟล์ข้อความที่มีข้อมูลไบนารีได้อย่างไร?


123

ผลตอบแทน grep

ไฟล์ไบนารี test.log ตรงกัน

ตัวอย่างเช่น

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

ฉันหวังว่าผลลัพธ์จะแสดงบรรทัดที่ 1 และบรรทัดที่ 3 (รวมสองบรรทัด)

เป็นไปได้ไหมที่จะใช้การtrแปลงข้อมูลที่พิมพ์ไม่ได้ให้เป็นข้อมูลที่อ่านได้เพื่อให้ grep ทำงานอีกครั้ง


โปรดทราบว่ามีโปรแกรมที่กรองอักขระไบนารีออกจากไฟล์ไบนารีและเก็บเฉพาะอักขระข้อความ (อ่านได้) ที่นี่: soft.tahionic.com/download-words_extractor/index.html
InTheNameOfScience

ขอโทษนะ แต่ ... คุณไม่หายไป-eในechoคำสั่ง?
Sopalajo de Arrierez

หากคุณใช้ 'zsh' ก็ใช้ได้หากไม่มี -e หากคุณใช้ "bash" คุณควรเพิ่ม "-e"
Daniel YC Lin

คำตอบ:


68

คุณสามารถเรียกใช้ไฟล์ข้อมูลผ่านcat -vเช่น

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

ซึ่งสามารถนำไปประมวลผลเพิ่มเติมเพื่อลบขยะ สิ่งนี้คล้ายคลึงกับคำถามของคุณเกี่ยวกับการใช้trงานมากที่สุด


5
แก้ไขปัญหาของฉัน ขอบคุณ! นี่คือสิ่งที่man catพูดเกี่ยวกับ-v:-v, --show-nonprinting use ^ and M- notation, except for LFD and TAB
tommy.carstensen

โปรดทราบว่าสิ่งนี้ใช้ได้ในท่อเช่นกัน เช่นset | cat -v | grep variable
funroll

1
เหตุใดจึงต้องใช้สิ่งนี้หาก grep --text ใช้งานได้ สิ่งนี้ดูซับซ้อนกว่านี้มาก
Michael Haefele

grep --textไม่ได้ผลเสมอไป มันเคารพ CTRL + D เป็นตัวยุติไฟล์ ดังนั้นหากคุณมีสิ่งนั้นในไฟล์ไบนารี grep จะออกก่อนเวลา
Tommy

110
grep -a

มันไม่ง่ายไปกว่านั้น


3
นี่ก็เหมือนกับgrep --textที่paxdiabloได้กล่าวไว้เมื่อ 2 ปีก่อน
user829755

4
ใช่ยกเว้นว่าจะใช้ไม่ได้กับ OSX เว้นแต่คุณจะทำสิ่งต่อไปนี้:LC_ALL="C" grep -a
Chris Stratton

91

วิธีหนึ่งคือการจัดการไฟล์ไบนารีเป็นข้อความต่อไปด้วย grep --textแต่อาจส่งผลให้ข้อมูลไบนารีถูกส่งไปยังเทอร์มินัลของคุณ นั่นไม่ใช่ความคิดที่ดีจริงๆหากคุณกำลังใช้งานเทอร์มินัลที่ตีความสตรีมเอาต์พุต (เช่น VT / DEC หรืออื่น ๆ อีกมากมาย)

หรือคุณสามารถส่งไฟล์ของคุณผ่านtrคำสั่งต่อไปนี้:

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

สิ่งนี้จะเปลี่ยนอะไรก็ได้ที่น้อยกว่าอักขระเว้นวรรค (ยกเว้นขึ้นบรรทัดใหม่) และอะไรก็ตามที่มากกว่า 126 เป็น.อักขระโดยเหลือเพียงสิ่งที่พิมพ์ได้


หากคุณต้องการให้อักขระ "ผิดกฎหมาย" ทุกตัวถูกแทนที่ด้วยอักขระอื่นคุณสามารถใช้โปรแกรม C ต่อไปนี้ซึ่งเป็นตัวกรองอินพุตมาตรฐานคลาสสิก:

#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;
}

ซึ่งจะทำให้คุณ{{NN}}ที่NNเป็นรหัสฐานสิบหกสำหรับตัวละคร คุณสามารถปรับprintfรูปแบบเอาต์พุตที่คุณต้องการได้

คุณสามารถดูการทำงานของโปรแกรมนั้นได้ที่นี่โดยที่:

pax$ printf 'Hello,\tBob\nGoodbye, Bob\n' | ./filterProg
Hello,{{09}}Bob
Goodbye, Bob

วิธีนี้จะแมปถ่านไบนารีทั้งหมดให้เป็น "." สัญลักษณ์. มีวิธีอื่นในการแมปให้เป็นสัญลักษณ์ที่อ่านได้หรือไม่?
Daniel YC Lin

แน่นอนว่าคุณสามารถเรียกใช้ผ่านโปรแกรมตัวกรองอื่นซึ่งหนึ่งในนั้นฉันได้ให้ไว้ในการอัปเดต
paxdiablo

1
ฉันคิดว่าtr '[:cntrl:] '.'ดีกว่า และควรอยู่\000-\010\013\014\016-\037\177-\377'ในไวยากรณ์ tr ของคุณ
Daniel YC Lin

2
หลังจากการทดสอบtr '[\000-\010\013\014\016-\037\177-\377]' '_'ใช้งานได้ cntrl ไม่เหมาะกับกรณีของฉัน
Daniel YC Lin

2
คุณสามารถบันทึกcatขั้นตอนได้โดยการบีบgrep --textเข้าtrแทนที่จะเป็นในทางกลับกัน นอกจากนี้ยังช่วยให้คุณ grep หลายไฟล์และเก็บการอ้างอิงชื่อไฟล์ไว้ในเอาต์พุต
aaaantoine

33

คุณสามารถใช้ "สตริง" เพื่อแยกสตริงจากไฟล์ไบนารีตัวอย่างเช่น

strings binary.file | grep foo

ทำงานได้ดีสำหรับฉันเนื่องจากแหล่งที่มาคือบันทึกการดีบักที่มี UID ในแต่ละบรรทัด ขอบคุณ
mbrownnyc

ทำงานได้ดีสำหรับฉันด้วย ขอบคุณสำหรับคำตอบ. บันทึกวันของฉัน :)
Shekhar

2
ฉันขอขอบคุณคำตอบของ @paxdiablo แต่สำหรับคำตอบที่รวดเร็วและการทำงานต่อไปคุณจะไม่สามารถทำผิดได้
Wil

พยายามใช้โซลูชัน paxdiablo แต่ก็ไม่ได้ให้ผลลัพธ์ที่ฉันคาดหวัง @moodywoody วิธีแก้ปัญหาของคุณรวดเร็วง่ายและได้ผลลัพธ์ตรงตามที่ฉันต้องการ!
justinhartman

20

คุณสามารถบังคับให้ grep ดูไฟล์ไบนารีด้วย:

grep --binary-files=text

คุณอาจต้องการเพิ่ม-o( --only-matching) เพื่อที่คุณจะได้ไม่ต้องพูดพล่อยๆแบบไบนารีมากมายที่จะทำให้เทอร์มินัลของคุณแย่ลง


อาจส่งออกขยะไบนารีซึ่งอาจมีผลข้างเคียงที่น่ารังเกียจหากผลลัพธ์เป็นเทอร์มินัลและหากไดรเวอร์เทอร์มินัลตีความว่าบางส่วนเป็นคำสั่ง
Daniel YC Lin

หากคุณใช้--only-matchingและ regex ของคุณไม่ตรงกับข้อมูลไบนารีตามอำเภอใจคุณจะไม่มีปัญหา
AB

หากนิพจน์ทั่วไปเป็น 'first. * end' และข้อมูลไบนารีมีอยู่ในรูปแบบ ". * 'จะไม่สามารถแก้ไขกระบวนการสำหรับการประมวลผลภายหลังของฉันได้ ยังไงก็ขอบคุณ
Daniel YC Lin

16

เริ่มต้นด้วย Grep 2.21 ไฟล์ไบนารีจะได้รับการปฏิบัติที่แตกต่างกัน :

เมื่อค้นหาข้อมูลไบนารีตอนนี้ grep อาจถือว่าไบต์ที่ไม่ใช่ข้อความเป็นตัวยุติบรรทัด สิ่งนี้สามารถเพิ่มประสิทธิภาพได้อย่างมาก

ดังนั้นสิ่งที่เกิดขึ้นตอนนี้คือด้วยข้อมูลไบนารีไบต์ที่ไม่ใช่ข้อความทั้งหมด (รวมถึงบรรทัดใหม่) จะถือว่าเป็นตัวยุติบรรทัด หากคุณต้องการเปลี่ยนพฤติกรรมนี้คุณสามารถ:

  • ใช้--text. วิธีนี้จะช่วยให้มั่นใจได้ว่ามีเพียงการขึ้นบรรทัดใหม่เท่านั้นที่เป็นตัวยุติบรรทัด

  • ใช้--null-data. สิ่งนี้จะช่วยให้มั่นใจได้ว่ามีเพียงไบต์ว่างเท่านั้นที่เป็นตัวยุติบรรทัด




2

คุณทำได้

strings test.log | grep -i

สิ่งนี้จะแปลงให้เอาต์พุตเป็นสตริงที่อ่านได้เป็น grep


0

คุณยังสามารถลองใช้เครื่องมือWord Extractor Word Extractor สามารถใช้กับไฟล์ใดก็ได้ในคอมพิวเตอร์ของคุณเพื่อแยกสตริงที่มีข้อความ / คำของมนุษย์ออกจากรหัสไบนารี (แอปพลิเคชัน exe, DLL)


กรณีของฉันฉันไม่ต้องการตัวแยกคำฉันต้องการให้หมายเลขบรรทัด
Daniel YC Lin

0

นี่คือสิ่งที่ฉันใช้ในระบบที่ไม่ได้ติดตั้งคำสั่ง "สตริง"

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

สิ่งนี้จะพิมพ์ข้อความและลบอักขระที่ไม่สามารถพิมพ์ได้ในคราวเดียวซึ่งแตกต่างจาก "ชื่อไฟล์ cat -v" ซึ่งต้องมีการประมวลผลภายหลังเพื่อลบสิ่งที่ไม่ต้องการออก โปรดทราบว่าข้อมูลไบนารีบางส่วนอาจพิมพ์ได้ดังนั้นคุณจะยังคงพูดพล่อยๆระหว่างสิ่งดีๆ ฉันคิดว่าสตริงช่วยขจัดคำพูดพล่อยๆนี้ได้เช่นกันถ้าคุณสามารถใช้สิ่งนั้นได้

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.