ボックスにWindowsシステムからのデータベースダンプがいくつかあります。それらはテキストファイルです。私はcygwinを使用してそれらをgrepしています。これらはプレーンテキストファイルのようです。それらをメモ帳やワードパッドなどのテキストエディターで開いたところ、見やすくなっています。しかし、それらに対してgrepを実行すると、binary file foo.txt matches
。
ファイルにいくつかのASCII NUL
文字が含まれていることに気付きました。これはデータベースダンプのアーティファクトであると思います。
では、grepがこれらのファイルをバイナリであると見なす理由は何でしょうか。 NUL
文字?ファイルシステムにフラグはありますか?行の一致を表示するためにgrepを取得するには何を変更する必要がありますか?
ファイルのどこかにNUL
文字がある場合、grepはそれをバイナリファイルと見なします。
このような回避策があるかもしれませんcat file | tr -d '\000' | yourgrep
最初にすべてのnullを削除し、次にファイル全体を検索します。
grep -a
は私のために働きました:
$ grep --help
[...]
-a, --text equivalent to --binary-files=text
strings
ユーティリティを使用して、任意のファイルからテキストコンテンツを抽出し、次のようにgrep
を介してパイプできます。strings file | grep pattern
。
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
ファイル/etc/magic
または/usr/share/misc/magic
には、コマンドfile
がファイルタイプを判別するために使用するシーケンスのリストがあります。
注バイナリはフォールバックソリューションである可能性があります。奇妙なエンコーディングのファイルもバイナリと見なされることがあります。
Linux上のgrep
には、--binary-files
や-U / --binary
などのバイナリファイルを処理するためのオプションがいくつかあります
「grepがファイルをバイナリであると見なす原因は何ですか?」という質問に実際に答えると、iconv
を使用できます。
$ iconv < myfile.Java
iconv: (stdin):267:70: cannot convert
私の場合、テキストエディタで正しく表示されるスペイン語の文字がありましたが、grepはそれらをバイナリと見なしていました。 iconv
出力は、それらの文字の行番号と列番号を示しました
NUL
文字の場合、iconv
はそれらを通常と見なし、その種類の出力を印刷しないため、この方法は適していません。
私の生徒の一人がこの問題を抱えていました。 grep
のCygwin
にバグがあります。ファイルに非ASCII文字が含まれている場合、grep
およびegrep
はそれをバイナリとして表示します。
私も同じ問題を抱えていました。 vi -b [filename]
を使用して、追加された文字を確認しました。制御文字^@
と^M
が見つかりました。次に、viで:1,$s/^@//g
と入力して、^@
文字を削除します。 ^M
に対してこのコマンドを繰り返します。
警告:「青」の制御文字を取得するには、 Ctrl+v その後 Ctrl+M または Ctrl+@。次に、viを保存して終了します。