web-dev-qa-db-ja.com

grepがファイルをバイナリと見なすのはなぜですか?

ボックスにWindowsシステムからのデータベースダンプがいくつかあります。それらはテキストファイルです。私はcygwinを使用してそれらをgrepしています。これらはプレーンテキストファイルのようです。それらをメモ帳やワードパッドなどのテキストエディターで開いたところ、見やすくなっています。しかし、それらに対してgrepを実行すると、binary file foo.txt matches

ファイルにいくつかのASCII NUL文字が含まれていることに気付きました。これはデータベースダンプのアーティファクトであると思います。

では、grepがこれらのファイルをバイナリであると見なす理由は何でしょうか。 NUL文字?ファイルシステムにフラグはありますか?行の一致を表示するためにgrepを取得するには何を変更する必要がありますか?

203
user394

ファイルのどこかにNUL文字がある場合、grepはそれをバイナリファイルと見なします。

このような回避策があるかもしれませんcat file | tr -d '\000' | yourgrep最初にすべてのnullを削除し、次にファイル全体を検索します。

139
bbaja42

grep -aは私のために働きました:

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

stringsユーティリティを使用して、任意のファイルからテキストコンテンツを抽出し、次のようにgrepを介してパイプできます。strings file | grep pattern

21
holgero

GNU grep 2.24 RTFS

結論:2および2の場合のみ:

  • NUL、たとえば_printf 'a\0' | grep 'a'_

  • c99 mbrlen()に従ったエンコーディングエラー。例:

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

    _\x80_をUTF-8 Unicodeポイントの最初のバイトにすることはできないため、次のようになります。 TF-8-説明| en.wikipedia.org

さらに、StéphaneChazelasが述べたように grepがファイルをバイナリと見なすのはなぜですか?| Unix&Linux Stack Exchange 、これらのチェックは、長さTODOの最初のバッファー読み取りまでしか行われません。

最初のバッファ読み取りまでのみ

したがって、非常に大きなファイルの途中でNULまたはエンコーディングエラーが発生した場合でも、とにかくgrepさ​​れる可能性があります。

これはパフォーマンス上の理由によるものだと思います。

例:これは次の行を出力します:

_printf '%10000000s\n\x80a' | grep 'a'
_

しかし、これはしません:

_printf '%10s\n\x80a' | grep 'a'
_

実際のバッファサイズは、ファイルの読み取り方法によって異なります。例えば。比較:

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

sleepを使用すると、プロセスがスリープ状態になるため、1行目が1バイトであっても、最初の行がgrepに渡され、2回目の読み取りでは、ファイルがバイナリかどうかがチェックされません。

[〜#〜] rtfs [〜#〜]

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

Stderrエラーメッセージがエンコードされている場所を見つけます。

_git grep 'Binary file'
_

私たちを_/src/grep.c_に導きます:

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

これらの変数の名前が適切であれば、基本的に結論に達しました。

encoding_error_output

_encoding_error_output_のクイックgreppingは、それを変更できる唯一のコードパスが_buf_has_encoding_errors_を通過することを示しています。

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

次に、_man mbrlen_だけです。

nlines_first_nullおよびnlines

次のように初期化されます:

_intmax_t nlines_first_null = -1;
nlines = 0;
_

したがって、nullが見つかった場合、_0 <= nlines_first_null_はtrueになります。

TODO _nlines_first_null < nlines_がいつfalseになる可能性がありますか?私は怠惰になりました。

[〜#〜] posix [〜#〜]

バイナリオプションを定義しない grep-ファイルのパターンを検索する| pubs.opengroup.org 、およびGNU grepはそれを文書化しないため、RTFSが唯一の方法です。

テキストファイルの1つがgrepによって突然バイナリとして表示されました。

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

解決策は、iconvを使用して変換することでした:

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

ファイル/etc/magicまたは/usr/share/misc/magicには、コマンドfileがファイルタイプを判別するために使用するシーケンスのリストがあります。

バイナリはフォールバックソリューションである可能性があります。奇妙なエンコーディングのファイルもバイナリと見なされることがあります。

Linux上のgrepには、--binary-files-U / --binaryなどのバイナリファイルを処理するためのオプションがいくつかあります

5
klapaucius

「grepがファイルをバイナリであると見なす原因は何ですか?」という質問に実際に答えると、iconvを使用できます。

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

私の場合、テキストエディタで正しく表示されるスペイン語の文字がありましたが、grepはそれらをバイナリと見なしていました。 iconv出力は、それらの文字の行番号と列番号を示しました

NUL文字の場合、iconvはそれらを通常と見なし、その種類の出力を印刷しないため、この方法は適していません。

2
golimar

私の生徒の一人がこの問題を抱えていました。 grepCygwinにバグがあります。ファイルに非ASCII文字が含まれている場合、grepおよびegrepはそれをバイナリとして表示します。

2
Joan Pontius

私も同じ問題を抱えていました。 vi -b [filename]を使用して、追加された文字を確認しました。制御文字^@^Mが見つかりました。次に、viで:1,$s/^@//gと入力して、^@文字を削除します。 ^Mに対してこのコマンドを繰り返します。

警告:「青」の制御文字を取得するには、 Ctrl+v その後 Ctrl+M または Ctrl+@。次に、viを保存して終了します。

1
Not Sure