web-dev-qa-db-ja.com

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

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

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

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

90
datasn.io

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

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

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

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

[〜#〜] edit [〜#〜]:@ruslanが正しく指摘したように、-andは暗示されているため省略できます。

157
crudcore

this SO question に基づく:

grep -rIl "needle text" my_folder

10
crayzeewulf

なぜ不便なのですか?頻繁に使用する必要があり、毎回入力したくない場合は、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
}
10
peoro
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" "%"

これはどう:

$ 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|:[^:]*$||'

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

編集:

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

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

Histumnessの答えには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のいずれかを使用して誤検知していました。そのため、ファイルを編集する前に、一致したファイルを最初にリストすることをお勧めします。

2
fuujuhi

これが私がやった方法です...

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

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

2。前と同じように検索を使用します

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

これを行う別の方法:

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

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

#  find . |xargs file {} \; |egrep "ASCII text|empty"
1
The IT Guy

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

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

find . ! -perm -111

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

find . -maxdepth 1 ! -perm -111

多くのコマンドを混合するためのpipesは不要で、強力なプレーンfindコマンド。

  • 免責事項:ファイルがbinaryであるかどうかをチェックしないため、exactlyではありません。たとえば、bash scriptファイル、つまりtextそれ自体が実行可能ビットセットを持ちます。

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

1
Dr Beco

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
Frank Fang

これは、1行に複数のコマンドを入力する方法を学ぼうとしている私のような初心者向けの拡張説明付きの簡易バージョンです。

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

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

これを実現するには、findfile、およびgrepの3つのUNIXコマンドを使用できます。

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

fileはファイルタイプを提供します。私たちの場合、「ASCIIテキスト」の戻り値を探しています

grepは、fileからの出力でキーワード 'ASCII'を探します

これらを1行にまとめるにはどうすればよいでしょうか?それを行うには複数の方法がありますが、擬似コードの順序でそれを行うのが最も理にかなっています(特に私のような初心者にとって)。

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

複雑に見えますが、分解しても悪くはありません。

find ./ =このディレクトリ内のすべてのファイルを調べます。 findコマンドは、 'expression'に一致する任意のファイルのファイル名、またはパスの後にあるもの(この場合は現在のディレクトリまたは./)を出力します

理解する最も重要なことは、最初のビット以降はすべてTrueまたはFalseとして評価されることです。 Trueの場合、ファイル名が出力されます。そうでない場合、コマンドは続行します。

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

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

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

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

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

0
mepler

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

凡例:$は、コマンドを入力する対話型のシェルプロンプトです

&&の後の部分を変更して、他のスクリプトを呼び出すか、インラインで他の処理を行うことができます。つまり、そのファイルに特定の文字列が含まれる場合、ファイル全体をcatするか、その中の2番目の文字列を探します。

説明:

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

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

0
sdkks

私はxargsが好きです

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

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

find . -type f -print0 | xargs -0 grep -I "needle text"
0
dalore
  • grep eth0 $(find/etc/-type f -exec file {} \; | egrep -i "text | ascii" | cut -d ':' -f1)

0
Gabriel G