すべての「非バイナリ」ファイルの検索


43

findコマンドを使用して、ディレクトリ内のすべての「非バイナリ」ファイルを検索することは可能ですか?これが私が解決しようとしている問題です。

Windowsユーザーからファイルのアーカイブを受け取りました。このアーカイブには、ソースコードと画像ファイルが含まれています。ビルドシステムは、Windowsの行末が含まれるファイルではうまく動作しません。flip -u* nixとウィンドウの間で行末を反転するコマンドラインプログラム()があります。だから、私はこのようなことをしたいです

find . -type f | xargs flip -u

ただし、このコマンドをイメージファイルまたはその他のバイナリメディアファイルに対して実行すると、ファイルが破損します。ファイル拡張子のリストを作成し、それを使用してフィルターをかけることができることを認識していますが、そのリストを最新の状態に保つことに依存しないものが欲しいです。

だから、ディレクトリツリー内のすべての非バイナリファイルを見つける方法はありますか?または、考慮すべき代替ソリューションはありますか?


1
あなたは使用することができfile、ファイルがデータまたはテキストであるかどうかを識別するために、スクリプト/パイプラインのユーティリティのどこかに
lk-

1
非バイナリとはどういう意味ですか(現代のコンピュータ上のすべてはバイナリです)。テキストファイルとバイナリファイルを持っていた古いC / PMオペレーティングシステムとの違いを使用していると思います。テキストファイルの長さは任意ですが、ctrl-zで終わる必要があり、バイナリファイルは512バイトブロックの倍数である必要がありました。もしそうなら、あなたはテキストファイルを意味しています。(非バイナリファイルで終了する行について書いていることにも注意してください。これは、テキストファイルであることも示唆しています)これは正しいですか?
ctrl-alt-delor

すべてのファイルはバイナリであり、単なる解釈の材料です。テキストファイルを見つける方法を求めていますか?
ctrl-alt-delor

@richardプレーンテキストプレーンテキストとして解釈されることを意図したファイル、および他のすべてのファイル(画像、ワードプロセッシングドキュメントなど)バイナリと呼ばれる時代になりました。私はそのすべてを1つと0がボンネットの下にあることを知っています:)
アランストーム

1
ああ、私はあなたが私の用語について何を意味するのかわかります-混乱を避けるために、将来的にはバイナリ/テキストを使用します。再:\ r \ nのこと-タイプライターのキャリッジリターン(行の先頭に移動)およびラインフィード(1行下に移動)のASCII文字であることを理解しています。したがって、\ r \ nは、行末文字が対象であった現実世界の物理的な物の「より正確な」モデルです。OS X以前では、Macはこのために\ rを使用していました。私は通常、「私たちがまだ対処しているラッシュで行われた任意の選択」
アラン・ストーム

回答:


20

file出力を使用してgrepまたはawkに出力し、テキストファイルを検索してから、の出力のファイル名部分のみを抽出し、filexargsに出力します。

何かのようなもの:

file * | awk -F: '/ASCII text/ {print $1}' | xargs -d'\n' -r flip -u

grepは単なる「テキスト」ではなく「ASCIIテキスト」を検索することに注意してください-おそらくリッチテキストドキュメントやUnicodeテキストファイルなどを台無しにしたくないでしょう。

find(または何でも)を使用して、検査するファイルのリストを生成することもできますfile

find /path/to/files -type f -exec file {} + | \
  awk -F: '/ASCII text/ {print $1}' | xargs -d'\n' -r flip -u

-d'\n'xargs の引数により、xargsは各入力行を個別の引数として扱い、スペースやその他の問題のある文字を含むファイル名に対応します。つまりxargs -0、入力ソースがNULLで区切られた出力(find's -print0オプションなど)を生成しない、または生成できない場合の代替手段です。changelogによると、xargsは2005年9月に-d/ --delimiterオプションを取得したため、非古代のLinuxディストリビューションに含まれているはずです(確認できなかったため、「最近の」追加であったことを漠然と覚えています)。

改行はファイル名の有効な文字であるため、ファイル名に改行が含まれていると改行されます。典型的なUNIXユーザーにとって、これは病理学的に正気ではありませんが、ファイルがMacマシンまたはWindowsマシンのどちらで作成されたかは聞いたことのないことではありません。

また、file完璧ではないことに注意してください。ファイル内のデータの種類の検出は非常に優れていますが、混乱する場合があります。

過去に何度もこの方法の多くのバリエーションを使用して成功しました。


1
この解決策をありがとう!何らかの理由で、SolarisシステムでfileEnglish textなくディスプレイが表示されるためASCII text、それに応じてその部分を変更しました。また、awk -F: '{print $1}'同等のに置き換えましたcut -f1 -d:
アンドリューチョン

3
言う価値がgrep -Iあるバイナリをフィルター
xenoterracide

単語textを探すだけで十分です。これは、またはのfileような説明も取得します。ASCII Java program textHTML document texttroff or preprocessor input text
user1024

私の回答は、この回答に対する部分的な回答/改善です。RTFのASCII text混乱を避けるためのgrepの非常に良い点。
ワイルドカード

1
xenoterracide:あなたは私の命を救った!ただの旗
セルジオ・アブレウ

9

いいえ。バイナリファイルまたは非バイナリファイルについて特別なことはありません。「0x01〜0x7Fの文字のみを含む」などのヒューリスティックを使用できますが、非ASCII文字のバイナリファイルや不運なバイナリファイルのテキストファイルを含むテキストファイルを呼び出します。

さて、それを無視したら...

zipファイル

Windowsユーザーからzipファイルとして送信された場合、zip形式はアーカイブ自体のファイルをバイナリまたはテキストとしてマークすることをサポートします。unzipの-aオプションを使用して、これに注意を払い、変換できます。もちろん、これが良い考えではない理由については、最初の段落を参照してください(zipプログラムはアーカイブを作成したときに間違った推測をした可能性があります)。

zipinfoは、zipファイルのリストで、どのファイルがバイナリ(b)またはテキスト(t)であるかを示します。

他のファイル

ファイルコマンドはファイルを見て、それを識別しようとします。特に、おそらくその-i(出力MIMEタイプ)オプションが役立つでしょう。タイプtext / *のファイルのみを変換します


6

bash使用して非バイナリファイルのみを処理する一般的なソリューションfile -b --mime-encoding

while IFS= read -d '' -r file; do
  [[ "$(file -b --mime-encoding "$file")" = binary ]] &&
    { echo "Skipping   $file."; continue; }

  echo "Processing $file."

  # ...

done < <(find . -type f -print0)

ファイルユーティリティの作成者に連絡し、-00バージョン5.26で気の利いたパラメーターを追加しました(2016-04-16リリース、現在のArchとUbuntu 16.10など)。file\0result\0一度にフィードされる複数のファイルを印刷します。例えば:

find . -type f -exec file -00 --mime-encoding {} + |
  awk 'BEGIN{ORS=RS="\0"}{if(NR%2)f=$0;else if(!/binary/)print f}' | 

awk一部は、非バイナリではないすべてのファイルを除外することです。ORS出力セパレータです。)

もちろん、ループでも使用できます。

while IFS= read -d '' -r file; do

  echo "Processing $file."

  # ...

done < <(find . -type f -exec file -00 --mime-encoding {} + |
  awk 'BEGIN{ORS=RS="\0"}{if(NR%2)f=$0;else if(!/binary/)print f}')

これと前のものに基づいて、新しいバージョンのパラメータをbash使用して新しい方法を利用し、古いバージョンでは前の方法にフォールバックする、バイナリファイルをフィルタリングするための小さなスクリプトを作成しました。-00file

#!/bin/bash

# Expects files as arguments and returns the ones that do
# not appear to be binary files as a zero-separated list.
#
# USAGE:
#   filter_binary_files.sh [FILES...]
#
# EXAMPLE:
#   find . -type f -mtime +5 -exec ./filter_binary_files.sh {} + | xargs -0 ...
# 

[[ $# -eq 0 ]] && exit

if [[ "$(file -v)" =~ file-([1-9][0-9]|[6-9]|5\.([3-9][0-9]|2[6-9])) ]]; then
  file -00 --mime-encoding -- "$@" |
    awk 'BEGIN{ORS=RS="\0"}{if(NR%2)f=$0;else if(!/binary/)print f}'
else
  for f do
    [[ "$(file -b --mime-encoding -- "$f")" != binary ]] &&
      printf '%s\0' "$f"
  done
fi

または、ここにもっとPOSIX-yがありますが、次のサポートが必要ですsort -V

#!/bin/sh

# Expects files as arguments and returns the ones that do
# not appear to be binary files as a zero-separated list.
#
# USAGE:
#   filter_binary_files.sh [FILES...]
#
# EXAMPLE:
#   find . -type f -mtime +5 -exec ./filter_binary_files.sh {} + | xargs -0 ...
# 

[ $# -eq 0 ] && exit

if [ "$(printf '%s\n' 'file-5.26' "$(file -v | head -1)" | sort -V)" = \
    'file-5.26' ]; then
  file -00 --mime-encoding -- "$@" |
    awk 'BEGIN{ORS=RS="\0"}{if(NR%2)f=$0;else if(!/binary/)print f}'
else
  for f do
    [ "$(file -b --mime-encoding -- "$f")" != binary ] &&
      printf '%s\0' "$f"
  done
fi

6

受け入れられた答えは私のためにそれらのすべてを見つけませんでした。grepを使用して-Iバイナリを無視し、すべての隠しファイルを無視する例を次に示します...

find . -type f -not -path '*/\.*' -exec grep -Il '.' {} \; | xargs -L 1 echo 

ここでは、実際のアプリケーションで使用されています:dos2unix

https://unix.stackexchange.com/a/365679/112190


4

Casの答えは良いのですが、それはまともなファイル名を想定しています。特に、ファイル名には改行が含まれないと想定されています。

ここでこの仮定を立てる正当な理由はありません。なぜなら、そのケースを正しく処理することも非常に簡単だからです(そして、実際には私の意見ではよりきれいです)。

find . -type f -exec sh -c 'file "$1" | grep -q "ASCII text"' sh {} \; -exec flip -u {} \;

このfindコマンドは、POSIX指定の機能のみを使用します-execブールテストとして任意のコマンドを実行するために使用することは、シンプルで堅牢(奇数のファイル名を正しく処理する)であり、より移植性があり-print0ます。

実際、コマンドのすべての部分は、を除いてPOSIXによって指定されflipます。

file返される結果の精度を保証するものではないことに注意してください。ただし、実際には、出力で「ASCIIテキスト」をgrepすることは非常に信頼できます。

(おそらくいくつかのテキストファイルを見逃すかもしれませんが、バイナリファイルを「ASCIIテキスト」として誤って識別してマングルすることはほとんどありません。


引数のないファイルcallsは非常に遅くなる可能性があります。たとえば、ビデオの場合、エンコードに関するすべての情報が表示されます。
phk

また、で始まるファイルがないと仮定しています-
phk

また、を1回呼び出すだけでなく、file複数のファイルを引数として使用できる理由はありません。
phk

@phk、あなたのコメントに対処するために:(1)潜在的な遅延を知るのは良いことですが、それを防ぐPOSIXの方法は見当たりません。(2)コマンドはシェルコマンドに渡されるファイル名の前に付けられるため、ファイル名についてはゼロと仮定します。(3)一度に1つのコマンド出力でテストとして使用することが、改行を含む可能性のあるファイル名の正しい処理を保証するために確認できる唯一のPOSIX方法です。find./grepfile
ワイルドカード

最終的な「POSIX-y」ソリューションを検討しましたが、賢明だと思いますがfile--mime-encodingフラグと--セパレータをサポートしていると仮定しますが、どちらもPOSIXによって保証されていません。
ワイルドカード

2
find . -type f -exec grep -I -q . {} \; -print

これ-type fにより、現在のディレクトリ(または以下)で、grep空でなくバイナリでないと考えられるすべての通常ファイル()が検索されます。

grep -Iバイナリファイルと非バイナリファイルを区別するために使用します。この-Iフラグgrepは、ファイルがバイナリであることを検出すると、ゼロ以外の終了ステータスで終了します。「バイナリ」ファイルは、によればgrep、印刷可能なASCII範囲外の文字を含むファイルです。

-qオプションgrep任意のデータを放出せずに、与えられたパターンが見つかった場合、それはゼロの終了ステータスで終了します。使用するパターンは単一のドットであり、任意の文字に一致します。

ファイルが非バイナリであることが判明し、少なくとも1文字が含まれている場合、ファイルの名前が出力されます。

勇気があるなら、flip -uそれにプラグインすることもできます:

find . -type f -exec grep -I -q . {} \; -print -exec flip -u {} \;

1

これを試して :

find . -type f -print0 | xargs -0 -r grep -Z -L -U '[^         -~]' | xargs -0 -r flip -u

の引数はgrep '[^ -~]'です'[^<tab><space>-~]'

シェルコマンドラインで入力する場合は、前にCtrl+ Vを入力しTabます。エディターでは、問題はないはずです。

  • '[^<tab><space>-~]'ASCIIテキストではない任意の文字に一致します(復帰は無視されますgrep)。
  • -L 一致しないファイルのファイル名のみを出力します
  • -Zヌル文字で区切られたファイル名を出力します(for xargs -0

Perlのような正規表現grep -P(利用可能な場合)\tを使用できることは注目に値します。または、シェルがサポートしている場合はロケール変換を使用します$'\t'bashおよびzshdo)。
phk

1

代替ソリューション:

dos2unixコマンドは、行末をWindows CRLFからUnix LFに変換し、バイナリファイルを自動的にスキップします。私はそれを再帰的に適用します:

find . -type f -exec dos2unix {} \;

以来dos2unix、それを行うにははるかに効率的である引数として複数のファイル名を取ることができますfind . -type f -exec dos2unix {} +
Anthonの

0

sudo find /(-type f -and -path '* / git / *' -iname 'README')-exec grep -liI '100644 \ | 100755' {} \; -exec flip -u {} \;

i。(-type f -and -path '* / git / *' -iname 'README'):gitという名前とREADMEという名前のファイルを含むパス内のファイルを検索します。特定のフォルダとファイル名を知っていれば、それが検索に役立ちます。

ii.-execコマンドは、findによって生成されたファイル名でコマンドを実行します

iii。\; コマンドの終了を示します

iv。{}は、前の検索で見つかったファイル/フォルダー名の出力です

v。複数のコマンドを続けて実行できます。-exec "command" \;を追加することにより -exec flip -u \など。

vii.grep

1.-l lists the name of the file
2.-I searches only non-binary files
3.-q quiet output
4.'100644\|100755' searches for either 100644 or 100755 within the file found. if found it then runs flip -u. \| is the or operator for grep. 

このテストディレクトリのクローンを作成して試してみてくださいhttps : //github.com/alphaCTzo7G/stackexchange/tree/master/linux/findSolution204092017

詳細な回答はこちら:https : //github.com/alphaCTzo7G/stackexchange/blob/master/linux/findSolution204092017/README.md

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.