Grep'i bir dosya olarak ikili düşündüren nedir?


185

Kutumda bir Windows sisteminden bazı veritabanı dökümleri var. Onlar metin dosyalarıdır. Cygwin'i onlara bulaştırmak için kullanıyorum. Bunlar düz metin dosyaları gibi görünüyor; Onları not defteri ve wordpad gibi metin editörleriyle açıyorum ve okunaklı görünüyorlar. Ancak, onlara grep koşarken, söyleyeceğim binary file foo.txt matches.

Dosyaların NUL, veritabanı dökümü eseri olduğuna inandığım bazı ascii karakterler içerdiğini fark ettim .

Peki grep, bu dosyaların ikili olduğunu düşündüren nedir? NULKarakter? Dosya sisteminde bir bayrak var mı? Bana eşleşmeleri göstermek için grep elde etmek için neye ihtiyacım var?


2
--null-dataNULsınırlayıcı ise faydalı olabilir .
Steve-o

Yanıtlar:


125

NULDosyanın herhangi bir yerinde bir karakter varsa , grep onu ikili dosya olarak kabul eder.

cat file | tr -d '\000' | yourgrepÖnce tüm null'ları ortadan kaldırmak ve sonra dosyayı aramak için böyle bir geçici çözüm olabilir .


149
... veya -a/ --text, en azından GNU grep ile kullanın .
derobert

1
@derobert: aslında, bazı (eski) sistemlerde, satırları grep olarak görün, ancak çıktısı ilk önce her eşleşen satırı NULkesecektir (muhtemelen C'nin printf'ını çağırır ve eşleşen satırı verir?). Böyle bir sistemde, bir grep cmd .sh_history'shd' ile eşleşen satırlar olduğu kadar boş satırlar dönecektir, çünkü her sh_history satırının NULbaşlangıcında her satırın başında belirli bir formata sahip olması gerekir. (ama "en azından GNU grep'teki" yorumunuz muhtemelen gerçek oluyor. Şu anda test etmek için elimde bir tane yok, ama bunu güzelce idare etmelerini bekliyorum)
Olivier Dulac

4
NUL karakterinin varlığı tek kriter midir? Şüpheliyim. Muhtemelen bundan daha akıllıdır. Ascii 32-126 aralığının dışına düşen herhangi bir şey benim tahminim olurdu, ancak emin olmak için kaynak koduna bakmak zorunda kalacağız.
Michael Martinez,

2
Bilgilerim, belirli grep örneğinin man sayfasındandı. Uygulama hakkındaki yorumunuz geçerlidir, kaynak belgelere aittir.
bbaja42

2
Bir dosyayı vardı grepuzun bir çizgi (0x96) yerine düzenli bir ASCII tire / eksi (0x2D) vardı çünkü cygwin ikili düşündü. Sanırım bu cevap OP'nin sorununu çözdü, ancak eksik görünüyor.
cp.engr

121

grep -a benim için çalıştı:

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

4
IMO'nun en iyi, en ucuz cevabı budur.
pydsigner

Ancak POSIX uyumlu değil
Matteo,

21

Sen kullanabilirsiniz stringsmetin herhangi bir dosya içeriği ve sonra boru onu içinden ayıklamak için yardımcı programını grepbu gibi: strings file | grep pattern.


2
Kısmen bozulmuş olabilecek log dosyalarını greplemek için ideal
Hannes R.

evet, bazen ikili karışık günlük kaydı da olur. Bu iyi.
sdkks

13

GNU grep 2.24 RTFS

Sonuç: Sadece 2 ve 2 vaka:

  • NUL, Örneğin printf 'a\0' | grep 'a'

  • C99'a göre kodlama hatası mbrlen(), örneğin:

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

    çünkü \x80bir UTF-8 Unicode noktasının ilk baytı olamaz: UTF-8 - Açıklama | en.wikipedia.org

Dahası, Stéphane Chazelas tarafından belirtildiği gibi Grep'i bir dosya olarak ikili yapan nedir? | Unix ve Linux Stack Exchange'de , bu kontroller yalnızca TODO uzunluğundaki ilk okumaya kadar yapılır.

Yalnızca ilk tampon belleğe kadar okunabilir

Bu nedenle, NUL veya kodlama hatası çok büyük bir dosyanın ortasında meydana gelirse, yine de boğulabilir.

Bunun performans nedenleriyle olduğunu hayal ediyorum.

Örn: bu satır basar:

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

ama bu değil:

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

Gerçek arabellek boyutu, dosyanın nasıl okunacağına bağlıdır. Örneğin, karşılaştır:

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

Bu sleepişlemle ilk satır sadece 1 bayt uzunluğunda olsa bile grep'e geçer, çünkü işlem uykuya gider ve ikinci okuma dosyanın ikili olup olmadığını kontrol etmez.

RTFs

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

Stderr hata mesajının kodlandığı yeri bulun:

git grep 'Binary file'

Bizi bize yönlendirir /src/grep.c:

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

Eğer bu değişkenler iyi adlandırılmışsa, temel olarak sonuca vardık.

encoding_error_output

Hızlı tarama, encoding_error_outputonu değiştirebilecek tek kod yolunun geçtiğini gösterir buf_has_encoding_errors:

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

o zaman sadece man mbrlen.

nlines_first_null ve nlines

İlk olarak başlatıldı:

intmax_t nlines_first_null = -1;
nlines = 0;

yani bir boş bulunan bulunursa 0 <= nlines_first_nullgerçek olur.

TODO ne zaman nlines_first_null < nlinesyanlış olabilir? Tembel oldum.

POSIX

İkili opsiyon grep tanımlamıyor - bir dosya için bir kalıp arayın | pubs.opengroup.org ve GNU grep belgelenmiyor, bu yüzden RTFS tek yol.


1
Etkileyici açıklama!
kullanıcı394

2
Geçerli UTF-8 kontrolünün yalnızca UTF-8 yerel ayarlarında yapıldığını unutmayın. Ayrıca, yalnızca düzenli bir dosya için sistemimde 32768 bayt gibi görünen dosyadan okunan ilk tamponda kontrol yapıldığını, ancak bir boru veya soket için bir bayt kadar küçük olabileceğini de unutmayın. Örneğin (printf '\n\0y') | grep yile karşılaştırın (printf '\n'; sleep 1; printf '\0y') | grep y.
Stéphane Chazelas

@ StéphaneChazelas "Geçerli UTF-8 kontrolünün sadece UTF-8 yerel ayarlarında yapıldığını unutmayın": Örneğimdeki export LC_CTYPE='en_US.UTF-8'gibi mi, yoksa başka bir şeyden mi bahsediyorsunuz ? Buf read: şaşırtıcı bir örnek, cevaplamak için eklendi. Belli ki o hatırlatıyor, benden daha kaynak daha okudum korsan koans "öğrenciydi aydınlanmış" :-)
Ciro Santilli新疆改造中心法轮功六四事件

1
Ben de çok fazla ayrıntıya
bakmadım

1
@CiroSantilli 巴拿馬 文件 六四 事件 法轮功 hangi GNU grep versiyonuna karşı test ettiniz?
jrw32982

6

Metin dosyalarımdan biri birden grep tarafından ikili olarak görüldü:

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

Çözüm, onu kullanarak dönüştürmekti iconv:

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

1
Bu bana da oldu. Özellikle, dosyada arama yapmak için normal bir boşlukla değiştirmek zorunda kaldığım, ISO-8859-1 kodlu bir kopmaz alandı.
Gallaecio

4
grep 2.21, ISO-8859 metin dosyalarını ikiliymiş gibi ele alır, grep komutundan önce LC_ALL = C dışa aktarma ekleyin.
netawater,

@netawater Teşekkürler! Bir metin dosyasında Müller gibi bir şey varsa bu örnektir. Bu 0xFConaltılık, aralık dışında grep utf8 (kadar 0x7F) beklenir . Printf 'a \ x7F' ile kontrol edin | Ciro'yu yukarıda tanımlandığı gibi 'a' ile çizin.
Anne van Rossum

5

Dosyada /etc/magicveya /usr/share/misc/magickomutun filedosya türünü belirlemek için kullandığı bir dizi listesi vardır .

İkili sadece bir geri dönüş çözümü olabileceğini unutmayın . Bazen garip kodlamaya sahip dosyalar da ikili olarak kabul edilir.

grepLinux’ta, --binary-filesya da-U / --binary


Daha doğrusu, C99'lara göre kodlama hatası mbrlen(). En Örneği ve kaynak yorumlama: unix.stackexchange.com/a/276028/32558
Ciro Santilli新疆改造中心法轮功六四事件

2

Öğrencilerimden birinin bu sorunu vardı. Bir hata içinde bulunmaktadır grepiçinde Cygwin. Dosyanın Ascii olmayan karakterleri varsa grepve egreponu ikili olarak görün.


Kulağa değil, bir özellik gibi geliyor. Özellikle kontrol etmek için bir komut satırı seçeneği var (-a / --text)
Will Sheppard,

2

Aslında "grep'in bir dosyayı ikili olarak görmesini sağlayan nedir?" Sorusuna cevap vererek, şunları kullanabilirsiniz iconv:

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

Benim durumumda, metin editörlerinde doğru olarak görünen ancak bunları ikili olarak kabul eden grep; iconvçıktı beni bu karakterlerin satır ve sütun numaralarına işaret etti.

NULKarakterler durumunda, iconvonları normal olarak kabul eder ve bu tür bir çıktıyı yazdırmaz; bu nedenle bu yöntem uygun değildir.


1

Ben de aynı problemi yaşadım. Kullandığım vi -b [filename]eklenen karakterleri görmek için. Kontrol karakterlerini buldum ^@ve ^M. Sonra karakterleri :1,$s/^@//gkaldırmak için vi yazın ^@. İçin bu komutu tekrarlayın ^M.

Uyarı: "mavi" kontrol karakterleri basın almak için Ctrl+ vsonra Ctrl+ Mveya Ctrl+ @. Sonra kaydedin ve vi'den çıkın.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.