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

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

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

コメント

  • --null-dataは、は区切り文字です。

回答

NUL文字はファイル内のどこにでもあり、grepはそれをバイナリファイルと見なします。

このcat file | tr -d "\000" | yourgrepのような回避策があります。最初にすべてnull、そして次に、ファイルを検索します。

コメント

  • …または-a /

、少なくともGNUgrepでは。

  • @derobert:実際、一部の(古い)システムでは、grepは行を参照しますが、その出力は最初に一致する各行を切り捨てます。 NUL(おそらく、C 'のprintfを呼び出して、一致する行を指定するためですか?)このようなシステムでは、grep cmd .sh_historyは' cmd '、sh_historyの各行には特定の形式があり、各行の先頭にNULがあります。 (ただし、少なくともGNU grep "に関するコメント"はおそらく実現します。私は'現在テスト用のものはありませんが、これをうまく処理できると思います)
  • NUL文字の存在が唯一の基準ですか?疑わしい。 'はおそらくそれよりも賢いでしょう。 Ascii 32-126の範囲外のものはすべて私の推測ですが、'確実にソースコードを確認する必要があります。
  • 私の情報は特定のgrepインスタンスのmanページから。実装に関するあなたのコメントは有効です、ソースはドキュメントよりも優先されます。
  • cygwinのgrepは、ダッシュの代わりに長いダッシュ(0x96)があったため、バイナリと見なされたファイルがありました。通常のASCIIハイフン/マイナス(0x2d)。この回答でOP 'の問題は解決したと思いますが、不完全なようです。
  • 回答

    grep -aは私のために働いた:

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

    コメント

    • これは、IMOの最良で最も安価な回答です。
    • ただし、POSIXに準拠していません
    • なぜ準拠していないのか説明していただけますか?この答えを選択肢として見つけた私たち全員にとって、それを明確にするのは良いことです。ありがとう:)。
    • こんにちは'このLOLを再学習するために2回目にここに来ました。テキスト内のフランス語のアクセント(diacritic)により、grepがbarfになりました

    回答

    を使用できますdiv id = “907fa53eca”>

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

    コメント

    • 部分的に破損している可能性のあるログファイルのgrepに最適
    • はい、場合によってはバイナリ混合ログまた起こります。これは良いことです。

    回答

    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-8Unicodeポイントの最初のバイトにすることはできないため: UTF-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バイトしかない場合でも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は、それを変更できる唯一のコードパスが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 when can nlines_first_null < nlines間違ったことはありますか?怠け者になりました。

    POSIX

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

    コメント

    • 印象的な説明!
    • 有効なUTF-8のチェックは、UTF-8ロケールでのみ行われることに注意してください。また、チェックはファイルから読み取られた最初のバッファでのみ実行されることに注意してください。通常のファイルの場合、システムでは32768バイトのようですが、パイプまたはソケットの場合は1バイトまで小さくすることができます。たとえば、(printf '\n\0y') | grep y(printf '\n'; sleep 1; printf '\0y') | grep yを比較します。
    • @St é phaneChazelas "有効なUTF-8のチェックはUTF-8ロケールでのみ行われることに注意してください":

      、または何か他のもの? Buf read:素晴らしい例、答えに追加。あなたは明らかに私よりもソースを読んでいて、それらのハッカー公案 "学生が悟りを開いたことを思い出させます" 🙂

    • 私も'詳細を調べませんでしたが、ごく最近
    • @CiroSantilli巴拿馬文件六四事件法轮功どのバージョンのGNUgrepに対してテストしましたか?

    回答

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

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

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

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

    コメント

    • これは私にも起こりました。特に、原因はISO-8859-1でエンコードされた改行なしスペースでした。これは、grepでファイルを検索するために、通常のスペースに置き換える必要がありました。
    • grep2.21はISOを扱います。 -8859テキストファイルをバイナリのように、grepコマンドの前にexport LC_ALL = Cを追加します。
    • @netawaterありがとうございます!これは例えばテキストファイルにM ü llerのようなものがある場合。その' s 0xFC 16進数なので、範囲外ではgrepはutf8を期待します(最大0x7F)。 printf ' a \ x7F ' |で確認してくださいgrep ' a '上記のCiroの説明

    回答

    ファイル/etc/magicまたは/usr/share/misc/magicには、コマンド

    はファイルタイプの決定に使用します。

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

    grep Linuxでは--binary-filesまたは-U / --binary

    コメント

    回答

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

    コメント

    • これは機能のように聞こえますが、バグではありません。特に、それを制御するためのコマンドラインオプションがある場合(-a / –text)

    回答

    「grepがファイルをバイナリと見なす理由」という質問に実際に答えるには、iconvを使用できます:

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

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

    NUL文字の場合、iconvはそれらを正常と見なし、そのような出力を出力しないため、このメソッドは適切ではありません

    回答

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

    警告:「青」の制御文字を取得するには、 Ctrl + v を押してから、 Ctrl + M <を押します。 / kbd>または Ctrl + @ 。次に、viを保存して終了します。

    回答

    この問題も発生しましたが、私の場合は、一致した行が長すぎます。

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

    grepは、多くのパターンでファイル全体を正常に処理しますが、パターンが"非常に長い行"で停止しましたBinary file myfile.txt matches

    -aを追加してもこの問題は解決しますが、ファイルのNULLまたはその他の無効な文字を事前に解析しても効果はありません(それ以外の場合、grepが他のパターンで完了しないことはありません)。この場合、問題のある行には25k以上の文字が含まれていました!

    私が理解していないのは、grepが行を返そうとしたときにのみ発生し、返そうとしたときではない理由です。他のパターンを探して処理しています。