Linuxコマンド:テキストファイルのみを「見つける」方法


100

Googleで数回検索した後、思いついたのは次のとおりです。

find my_folder -type f -exec grep -l "needle text" {} \; -exec file {} \; | grep text

これは非常に便利ではなく、mimeタイプ情報などの不要なテキストを出力します。より良い解決策はありますか?同じフォルダにたくさんの画像や他のバイナリファイルがあり、検索する必要のあるテキストファイルがたくさんあります。

回答:


184

私はこれが古いスレッドであることを知っていますが、それを偶然find見つけて、非バイナリファイルのみを見つけるために使用する非常に高速な方法であることがわかった自分のメソッドを共有したいと思いました。

find . -type f -exec grep -Iq . {} \; -print

-Igrep のオプションは、バイナリファイルをすぐに無視するように指示し.ます。オプションと一緒に使用すると、-qテキストファイルとすぐに一致するため、非常に高速になります。スペースが気になる場合は-print-print0にパイプするためにをに変更できxargs -0ます(ヒントに感謝、@ lucas.werkmeister!)

また、最初のドットはfindOS Xなどの特定のBSDバージョンの場合にのみ必要ですが、これをエイリアスなどに入れても、常にそこにあるだけでは何の問題もありません。

編集:@ruslanが正しく指摘したように、-and暗黙のうちに省略できます。


16
Mac OS Xでは、これをに変更する必要がありfind . -type f -exec grep -Il "" {} \;ます。
アレックジェイコブソン2014年

3
これはpeoroの回答より優れています。1。実際に質問に回答します。2.誤
検知が発生

3
を使用find -type f -exec grep -Iq . {} \; -and -printして、ファイルをに保持するという利点もありますfind。テキストファイルに対してのみ実行される-print別の-execものに置き換えることができます。(grepファイル名を印刷させた場合、改行を含むファイル名を区別できなくなります。)
Lucas Werkmeister '22

1
@ NathanS.Watson-Haighすぐに一致するテキストファイルになるはずなので、そうすべきではありません。共有できる具体的なユースケースはありますか?
crudcore 2017年

2
find . -type f -exec grep -Il . {} +はるかに高速です。欠点は、-exec@ lucas.werkmeisterが示唆するように、他のユーザーが拡張できないことです
Henning


10

なぜ使いにくいのですか?頻繁に使用する必要があり、毎回入力する必要がない場合は、bash関数を定義するだけです。

function findTextInAsciiFiles {
    # usage: findTextInAsciiFiles DIRECTORY NEEDLE_TEXT
    find "$1" -type f -exec grep -l "$2" {} \; -exec file {} \; | grep text
}

それをあなたの中に入れて、.bashrcただ走ってください:

findTextInAsciiFiles your_folder "needle text"

いつでも好きなときに。


EDIT OPの編集を反映します:

MIME情報を切り出す場合は、MIME情報をフィルターで除外するステージをパイプラインに追加するだけです。これは、前に来るものだけ取ることで、トリックを行う必要があります:cut -d':' -f1

function findTextInAsciiFiles {
    # usage: findTextInAsciiFiles DIRECTORY NEEDLE_TEXT
    find "$1" -type f -exec grep -l "$2" {} \; -exec file {} \; | grep text | cut -d ':' -f1
}

「grep text」が正確にすべてのテキストファイルを取得できるほど正確であるかどうかはわかりません。つまり、MIMEタイプの説明の文字列に「テキスト」がないテキストファイルタイプはありますか?
datasn.io

@ kavoir.com:はい。fileマニュアルから:「ユーザーは、ディレクトリ内のすべての読み取り可能なファイルに「テキスト」という単語が印刷されていることを知っていることに依存しています。」
peoro

2
grepを実行してからテキストファイルを除外するのではなく、grepを実行する前にテキストファイルを検索する方が少し賢明ではないでしょうか。
ユーザー不明

/proc/meminfo/proc/cpuinfoなどのテキストファイルですが、file /proc/meminfo言います/proc/meminfo: empty。「テキスト」に加えて「空」もテストする必要があるかどうか疑問に思いますが、他のタイプも「空」を報告できるかどうかはわかりません。
TimoKähkönen2013年

「どうして手に負えないの?」-「不要なテキストを出力する」。この答えはそれを和らげません。
user123444555621 14年

4
find . -type f -print0 | xargs -0 file | grep -P text | cut -d: -f1 | xargs grep -Pil "search"

残念ながら、これはスペースの節約にはなりません。これをbashスクリプトに入れると、少し簡単になります。

これはスペースセーフです:

#!/bin/bash
#if [ ! "$1" ] ; then
    echo "Usage: $0 <search>";
    exit
fi

find . -type f -print0 \
  | xargs -0 file \
  | grep -P text \
  | cut -d: -f1 \
  | xargs -i% grep -Pil "$1" "%"

2
スクリプトにはいくつかの問題があります。1.バイナリファイルに名前が付いているとtext.binどうなりますか?2.ファイル名に:?が含まれている場合はどうなりますか?
thkala

3

これを行う別の方法:

# find . |xargs file {} \; |grep "ASCII text"

空のファイルも必要な場合:

#  find . |xargs file {} \; |egrep "ASCII text|empty"

2

これはどう:

$ grep -rl "needle text" my_folder | tr '\n' '\0' | xargs -r -0 file | grep -e ':[^:]*text[^:]*$' | grep -v -e 'executable'

ファイルタイプなしのファイル名が必要な場合は、最後のsedフィルターを追加するだけです。

$ grep -rl "needle text" my_folder | tr '\n' '\0' | xargs -r -0 file | grep -e ':[^:]*text[^:]*$' | grep -v -e 'executable' | sed 's|:[^:]*$||'

-e 'type'最後のgrepコマンドにオプションを追加することで、不要なファイルタイプを除外できます。

編集:

ご使用のxargsバージョンが-dオプションをサポートしている場合、上記のコマンドはより簡単になります。

$ grep -rl "needle text" my_folder | xargs -d '\n' -r file | grep -e ':[^:]*text[^:]*$' | grep -v -e 'executable' | sed 's|:[^:]*$||'

ばかげた。再帰的なgrepに気付かなかった。私が理解しているように、多くのアプリケーションでは少し制限されていますが、実際にはかなり高速です。+1してください。
AnttiRytsölä11年

2

ここに私がそれをした方法があります...

1。ファイルがプレーンテキストであるかどうかをテストする小さなスクリプトを作成するistext:

#!/bin/bash
[[ "$(file -bi $1)" == *"file"* ]]

2。以前と同じように検索を使用

find . -type f -exec istext {} \; -exec grep -nHi mystring {} \;

== *"text"* ]]ってことかしら?
ユーザー不明

代わりにmatch-operator `=〜" text "]]`を使用できます。
ユーザー不明

2

私はヒストネスの答えに関して2つの問題を抱えています:

  • テキストファイルのみを一覧表示します。要求どおりに実際に検索することはありません。実際に検索するには、

    find . -type f -exec grep -Iq . {} \; -and -print0 | xargs -0 grep "needle text"
    
  • それは非常に遅いすべてのファイルのgrepプロセスを生成します。より良い解決策は

    find . -type f -print0 | xargs -0 grep -IZl . | xargs -0 grep "needle text"
    

    または単に

    find . -type f -print0 | xargs -0 grep -I "needle text"
    

    上記のソリューション(2.5GBデータ/ 7700ファイル)では、4秒と比較して0.2秒しかかかりません。つまり、20倍高速です。

また、代替案としてag、Silver Searcher、またはack-grepを引用した人はいません。これらのいずれかが利用可能な場合、それらははるかに優れた代替手段です。

ag -t "needle text"    # Much faster than ack
ack -t "needle text"   # or ack-grep

最後の注意として、誤検知に注意してください(テキストファイルとして取得されたバイナリファイル)。私はすでにgrep / ag / ackのいずれかを使用して誤検知していたので、ファイルを編集する前に、最初に一致したファイルをリストすることをお勧めします。


1

古い質問ですが、この情報が答えの質を高めると思います。

実行可能ビットが設定されているファイル無視するときは、次のコマンドを使用します。

find . ! -perm -111

再帰的に他のディレクトリに入らないようにするには:

find . -maxdepth 1 ! -perm -111

パイプで多くのコマンドを混在させる必要はありません。強力な単純なfindコマンドだけです。

  • 免責事項:それはない正確にファイルがある場合、それはチェックしないため、OPが尋ねバイナリか。たとえば、それ自体はテキストであるが実行可能ビットが設定されているbashスクリプトファイルを除外します。

とはいえ、これが誰にとっても役立つことを願っています。


0

私はこのようにしています:1)ファイルが多すぎる(〜30k)ため、検索することができないため、以下のコマンドを使用して、crontabを介して使用するテキストファイルリストを毎日生成します。

find /to/src/folder -type f -exec file {} \; | grep text | cut -d: -f1 > ~/.src_list &

2).bashrcに関数を作成します。

findex() {
    cat ~/.src_list | xargs grep "$*" 2>/dev/null
}

次に、以下のコマンドを使用して検索を実行できます。

findex "needle text"

HTH :)


0

私はxargsを好む

find . -type f | xargs grep -I "needle text"

ファイル名が奇妙な場合は、-0オプションを使用して検索します。

find . -type f -print0 | xargs -0 grep -I "needle text"

0
  • すべてのtext / asciiファイルの/ etcにあるテキスト「eth0」を検索するbashの例

grep eth0 $(find / etc / -type f -exec file {} \; | egrep -i "text | ascii" | cut -d ':' -f1)


0

これは、私のような初心者が1行に複数のコマンドを配置する方法を学習しようとしている人のための、拡張された説明付きの簡略版です。

問題を段階的に書き出すと、次のようになります。

// For every file in this directory
// Check the filetype
// If it's an ASCII file, then print out the filename

これを実現するために、我々は3つのUNIXコマンドを使用することができますfindfilegrep

find ディレクトリ内のすべてのファイルをチェックします。

fileファイルタイプが表示されます。私たちのケースでは、「ASCIIテキスト」の戻りを探しています。

grep からの出力でキーワード「ASCII」を探します file

では、これらを1行にまとめる方法を教えてください。これには複数の方法がありますが、疑似コードの順に実行するのが最も理にかなっています(特に私のような初心者にとって)。

find ./ -exec file {} ";" | grep 'ASCII'

複雑に見えますが、分解すると悪くありません。

find ./=このディレクトリ内のすべてのファイルを調べます。このfindコマンドは、「式」に一致するファイルのファイル名、またはパスの後に続くもの(この場合は現在のディレクトリまたは./

理解する最も重要なことは、その最初のビットの後のすべてがTrueまたはFalseとして評価されることです。Trueの場合、ファイル名が印刷されます。そうでない場合、コマンドは次に進みます。

-exec=このフラグは、他のコマンドの結果を検索式として使用できるようにするfindコマンド内のオプションです。関数内で関数を呼び出すようなものです。

file {}=内で呼び出されるコマンドfind。このfileコマンドは、ファイルのファイルタイプを示す文字列を返します。通常、次のようになりますfile mytextfile.txt。この例では、findコマンドが参照しているファイルを使用するため、中括弧{}を挿入して空の変数またはパラメーターとして機能させます。つまり、ディレクトリ内のすべてのファイルの文字列を出力するようにシステムに要求するだけです。

";"=これは必須findであり、-execコマンドの最後の句読点です。を実行して必要な場合の詳細については、「find」のマニュアルを参照してくださいman find

| grep 'ASCII'= |はパイプです。パイプは左側にあるものの出力を受け取り、右側にあるものへの入力としてそれを使用します。findコマンドの出力(単一ファイルのファイルタイプである文字列)を取得し、文字列が含まれているかどうかをテストします'ASCII'。そうであれば、trueを返します。

現在、コマンドがtrueを返すfind ./と、右側の式grepはtrueを返します。出来上がり。


0

fileユーティリティと組み合わせた素晴らしいユーティリティを使用して、マジックバイトで任意のファイルタイプを見つけることに興味がある場合find、これは便利です。

$ # Let's make some test files
$ mkdir ASCII-finder
$ cd ASCII-finder
$ dd if=/dev/urandom of=binary.file bs=1M count=1
1+0 records in
1+0 records out
1048576 bytes (1.0 MB, 1.0 MiB) copied, 0.009023 s, 116 MB/s
$ file binary.file
binary.file: data
$ echo 123 > text.txt
$ # Let the magic begin
$ find -type f -print0 | \
    xargs -0 -I @@ bash -c 'file "$@" | grep ASCII &>/dev/null && echo "file is ASCII: $@"' -- @@

出力:

file is ASCII: ./text.txt

凡例:$コマンドを入力するインタラクティブなシェルプロンプトです

&&他のスクリプトを呼び出したり、他の何かをインラインで実行したりするために後の部分を変更できます。つまり、そのファイルに特定の文字列が含まれている場合は、ファイル全体をキャットするか、その中の2番目の文字列を探します。

説明:

  • find ファイルであるアイテム
  • メイクはxargs1つのライナーにラインとして各項目を養うbash コマンド/スクリプト
  • fileマジックバイトでファイルのタイプをgrepチェックし、ASCIIが存在するかどうかを確認します。存在する場合は&&、次のコマンドが実行された後。
  • find結果をnull区切って出力します。これは、スペースとメタ文字を含むファイル名をエスケープするのに適しています。
  • xargs-0オプションを使用しnullて、それらを分離して読み取り、-I @@ 各レコードを取得し、スクリプトをbashする位置パラメータ/引数として使用します。
  • --for bashは、bashオプションとして解釈できる-ようなlike で始まっていても、それが引数であることを保証し-cます

ASCII以外のタイプを見つける必要がある場合はgrep ASCII、次のように他のタイプに置き換えるだけです。grep "PDF document, version 1.4"


-1
find . -type f | xargs file | grep "ASCII text" | awk -F: '{print $1}'

findコマンドを使用してすべてのファイルを一覧表示し、fileコマンドを使用してそれらがテキスト(tar、keyではない)であることを確認し、最後にawkコマンドを使用して結果をフィルター処理して出力します。


-4

これはどう

 find . -type f|xargs grep "needle text"

これは探しません"needle text"
peoro

@Navi:提供されるサンプルOPは、次を含むファイルのみを検索します"needl text"
peoro

3
@Navi:テキストファイルを検索しなく"needle text"なりました:バイナリファイルに含まれている場合は見つかります
peoro

なぜ私もあなたの言うことを聞いているのですか?
ナビ

1
@Navi:ワンライナーはファイルタイプをチェックせず、ファイル名の空白に大きな問題があります...
thkala
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.