V mém boxu mám nějaké skládky databází ze systému Windows. Jsou to textové soubory. K jejich procházení používám cygwin. Zdá se, že jde o soubory s prostým textem; otevírám je textovými editory, jako jsou poznámkový blok a wordpad, a vypadají čitelně. Když na ně ale spustím grep, řekne to binary file foo.txt matches.

Všiml jsem si, že soubory obsahují některé znaky ascii NUL, které jsou podle mého názoru artefakty z výpisu databáze.

Proč tedy grep považuje tyto soubory za binární? Znak NUL? Je v souborovém systému příznak? Co musím změnit, abych získal grep ukázat mi shodu řádku?

Komentáře

  • --null-data mohou být užitečné, pokud NUL je oddělovač.

Odpověď

Pokud existuje NUL znak kdekoli v souboru, grep jej bude považovat za binární soubor.

Může existovat takové řešení cat file | tr -d "\000" | yourgrep k odstranění nejdříve všechny null a poté prohledejte soubor.

Komentáře

  • … nebo použijte -a / --text, alespoň s GNU grep.
  • @derobert: ve skutečnosti na některých (starších) systémech grep vidí řádky, ale jeho výstup zkrátí každý odpovídající řádek na prvním NUL (pravděpodobně proto, že volá C ‚ s printf a dá mu odpovídající řádek?). V takovém systému grep cmd .sh_history vrátí tolik prázdných řádků, kolik řádků odpovídá ‚ cmd ‚, protože každý řádek sh_history má specifický formát s NUL na začátku každého řádku. (ale váš komentář “ alespoň na GNU grep “ se pravděpodobně splní. ‚ právě teď nemáte po ruce k testování, ale předpokládám, že to zvládnou pěkně)
  • Je přítomnost znaku NUL jediným kritériem? Pochybuji. Je to ‚ pravděpodobně chytřejší. Cokoli, co spadá mimo rozsah Ascii 32-126, by byl můj odhad, ale ‚ si pro jistotu musíme prohlédnout zdrojový kód.
  • Moje informace byla z manuálové stránky konkrétní instance grep. Váš komentář k implementaci je platný, zdroj trumfuje dokumenty.
  • Měl jsem soubor, který grep na cygwin považoval za binární, protože místo něj měl dlouhou pomlčku (0x96) běžný pomlčka ASCII / minus (0x2d). Myslím, že tato odpověď vyřešila problém OP ‚ s, ale zdá se, že je neúplný.

Odpověď

grep -a pro mě pracoval:

$ grep --help [...] -a, --text equivalent to --binary-files=text 

Komentáře

  • Toto je nejlepší a nejlevnější odpověď IMO.
  • Ale není kompatibilní s POSIX
  • Chtěli byste vysvětlit, proč tomu tak není? Bylo by dobré objasnit to pro nás všechny, kteří tuto odpověď považujeme za jednu z možností. Díky :).
  • Ahoj, ‚ jsem sem přišel DRUHÝ čas, abych se znovu naučil tuto LOL. Francouzský přízvuk (diakritika) v textu způsobil, že grep zablokoval

odpověď

Můžete použít strings k extrakci textového obsahu z libovolného souboru a jeho následnému propojení grep, například takto: strings file | grep pattern.

Komentáře

  • Ideální pro grepování souborů protokolu, které mohou být částečně poškozené
  • ano, někdy binární smíšené protokolování také se stane. To je dobré.

Odpověď

GNU grep 2.24 RTFS

Závěr: Pouze případy 2 a 2:

  • NUL, např printf "a\0" | grep "a"

  • chyba kódování podle C99 mbrlen(), např .:

    export LC_CTYPE="en_US.UTF-8" printf "a\x80" | grep "a" 

    protože \x80 nemůže být prvním bajtem bodu Unicode UTF-8: UTF-8 – Popis | en.wikipedia.org

Dále, jak uvádí Stéphane Chazelas Co dělá grep považován za soubor být binární? | Unix & Linux Stack Exchange , tyto kontroly se provádějí pouze do prvního přečtení vyrovnávací paměti o délce TODO.

Přečíst pouze do první vyrovnávací paměti

Pokud tedy dojde k chybě NUL nebo chybě kódování uprostřed velmi velkého souboru, může být stejně pozdraven.

Představuji si, že je to z důvodů výkonu.

Např .: tímto se vytiskne řádek:

printf "%10000000s\n\x80a" | grep "a" 

ale to není:

printf "%10s\n\x80a" | grep "a" 

Skutečná velikost vyrovnávací paměti závisí na tom, jak je soubor načten. Např.porovnat:

export LC_CTYPE="en_US.UTF-8" (printf "\n\x80a") | grep "a" (printf "\n"; sleep 1; printf "\x80a") | grep "a" 

U sleep se první řádek předá grepu, i když má pouze 1 bajt dlouho, protože proces přejde do režimu spánku a druhé čtení nekontroluje, zda je soubor binární.

RTFS

git clone git://git.savannah.gnu.org/grep.git cd grep git checkout v2.24 

Vyhledat, kde je zakódována chybová zpráva stderr:

git grep "Binary file" 

Vede nás k /src/grep.c:

if (!out_quiet && (encoding_error_output || (0 <= nlines_first_null && nlines_first_null < nlines))) { printf (_("Binary file %s matches\n"), filename); 

Pokud byly tyto proměnné dobře pojmenovány, dospěli jsme v zásadě k závěru.

encoding_error_output

Rychlý grep pro encoding_error_output ukazuje, že jediná cesta kódu, která ji může upravit, prochází buf_has_encoding_errors:

clen = mbrlen (p, buf + size - p, &mbs); if ((size_t) -2 <= clen) return true; 

a pak pouze man mbrlen.

nlines_first_null a nlines

Inicializováno jako:

intmax_t nlines_first_null = -1; nlines = 0; 

takže když je nalezena null, 0 <= nlines_first_null se stane pravdou.

TODO kdy může nlines_first_null < nlines být nepravdivý? Zlenivěl jsem.

POSIX

Nedefinuje binární možnosti grep – vyhledat soubor pro vzor | pubs.opengroup.org a GNU grep to nezdokumentuje, takže RTFS je jediný způsob.

Komentáře

  • Působivé vysvětlení !
  • Upozorňujeme, že kontrola platného UTF-8 se děje pouze v národních prostředích UTF-8. Všimněte si také, že kontrola se provádí pouze na první vyrovnávací paměti načtené ze souboru, který se u běžného souboru v mém systému zdá být 32768 bajtů, ale pro potrubí nebo zásuvku může být tak malý jako jeden bajt. Porovnejte například (printf '\n\0y') | grep y s (printf '\n'; sleep 1; printf '\0y') | grep y.
  • @St é phaneChazelas “ Upozorňujeme, že kontrola platného UTF-8 se děje pouze v národních prostředích UTF-8 „: myslíte tím o export LC_CTYPE='en_US.UTF-8' jako v mém příkladu, nebo něco jiného? Buf číst: úžasný příklad, přidán k odpovědi. Zjevně jste přečetli zdroj více než já, připomíná mi ty hackerské koany “ Student byl osvícený “ 🙂
  • Ani jsem se ‚ moc podrobně nezabýval, ale udělal jste to nedávno
  • @CiroSantilli 巴拿馬 文件 六四 事件 法轮功 proti jaké verzi GNU grep jste testovali?

Odpověď

Jeden z mých textových souborů byl grepem najednou viděn jako binární:

$ file foo.txt foo.txt: ISO-8859 text 

Řešením bylo převést jej pomocí iconv:

iconv -t UTF-8 -f ISO-8859-1 foo.txt > foo_new.txt 

komentářů

  • To se stalo i mně. Příčinou byl zejména nerozbitný prostor kódovaný podle ISO-8859-1, který jsem musel nahradit běžným prostorem, abych získal grep pro vyhledávání v souboru.
  • grep 2.21 zachází s ISO -8859 textových souborů, jako by byly binární, přidejte před příkazem grep export LC_ALL = C.
  • @netawater Díky! To je např. v případě, že máte v textovém souboru něco jako M ü ller. To ‚ s 0xFC šestnáctkové, takže mimo rozsah by grep očekával pro utf8 (až 0x7F). Zkontrolujte pomocí printf ‚ a \ x7F ‚ | grep ‚ a ‚ jak popisuje Ciro výše.

Odpověď

Soubor /etc/magic nebo /usr/share/misc/magic obsahuje seznam sekvencí, které příkaz file slouží k určení typu souboru.

Všimněte si , že binární soubor může být pouze záložním řešením. Někdy se soubory s podivným kódováním považují také za binární.

grep v systému Linux má některé možnosti zpracování binárních souborů, jako je --binary-files nebo -U / --binary

Komentáře

Odpovědět

Jeden z mých studentů měl tento problém. V grep je chyba v Cygwin. Pokud soubor obsahuje jiné znaky než Ascii, považujte jej grep a egrep za binární.

Komentáře

  • To zní jako funkce, nikoli jako chyba.Obzvláště vzhledem k možnosti jeho ovládání pomocí příkazového řádku (-a / –text)

Odpověď

Ve skutečnosti na otázku „Co dělá grep, aby považoval soubor za binární?“, Můžete použít iconv:

$ iconv < myfile.java iconv: (stdin):267:70: cannot convert 

V mém případě byly španělské znaky, které se v textových editorech zobrazily správně, ale grep je považoval za binární; iconv výstup mě upozornil na čísla řádků a sloupců těchto znaků

V případě NUL znaků iconv je bude považovat za normální a nevytiskne tento druh výstupu, takže tato metoda není vhodná

Odpověď

Měl jsem stejný problém. Použil jsem vi -b [filename] k zobrazení přidaných znaků. Našel jsem kontrolní znaky ^@ a ^M. Potom ve vi zadejte :1,$s/^@//g a odstraňte ^@ znaky. Tento příkaz opakujte pro ^M.

Upozornění: Chcete-li získat „modré“ kontrolní znaky, stiskněte Ctrl + v a poté Ctrl + M nebo Ctrl + @ . Pak uložte a ukončete vi.

Odpověď

Také jsem měl tento problém, ale v mém případě to bylo způsobeno, když je shodná linka příliš dlouhý.

file myfile.txt myfile.txt: UTF-8 Unicode text, with very long lines 

grep by běžel celým souborem v pořádku s mnoha vzory, ale pokud by se vzor shodoval s “ velmi dlouhá řada “ se zastavila u Binary file myfile.txt matches.

Přidání -a tento problém také řeší, ale předběžná analýza souboru pro NULL nebo jiné neplatné znaky by neměla žádný účinek (neexistují žádné, jinak by se grep nedokončil pro jiné vzory). V tomto případě měla problematická linka 25k + znaků!

To, čemu nerozumím, je důvod, proč se to stane, jen když se grep pokusí linku vrátit, a ne když zpracovává to a hledá další vzory.

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *