私は(例えば、ディレクトリを持っているabc/def/efg
多くのサブディレクトリ(例えば,:で)abc/def/efg/(1..300)
)。これらのサブディレクトリにはすべて共通のファイル(例:)がありますfile.txt
。file.txt
他のファイルを除いて、これだけで文字列を検索したい。これどうやってするの?
を使用しましたが grep -arin "pattern" *
、サブディレクトリとファイルが多数ある場合は非常に遅くなります。
私は(例えば、ディレクトリを持っているabc/def/efg
多くのサブディレクトリ(例えば,:で)abc/def/efg/(1..300)
)。これらのサブディレクトリにはすべて共通のファイル(例:)がありますfile.txt
。file.txt
他のファイルを除いて、これだけで文字列を検索したい。これどうやってするの?
を使用しましたが grep -arin "pattern" *
、サブディレクトリとファイルが多数ある場合は非常に遅くなります。
回答:
建物grep
でコマンドをfind
Zannaの答えのように、(も参照これを行うには非常に堅牢で、汎用性、および移植可能な方法であるsudodusの答えを)。そしてmuruは、使用しての優れたアプローチ掲載しているgrep
の--include
オプションを。ただし、grep
コマンドとシェルだけを使用する場合は、別の方法があります。シェル自体に必要な再帰を実行させることができます。
shopt -s globstar # you can skip this if you already have globstar turned on
grep -H 'pattern' **/file.txt
-H
フラグ作るには、grep
一つだけ一致するファイルが見つかった場合でも、ファイル名を示しています。あなたが渡すことができ-a
、-i
および-n
フラグ(あなたの例から)へのgrep
それはだ場合にも、あなたが必要なもの。しかし、合格しない-r
か、-R
このメソッドを使用している場合。それは、シェルグロブパターン含む拡大にディレクトリを再帰的**
、そしてませんがgrep
。
これらの手順は、Bashシェルに固有のものです。BashはUbuntu(および他のほとんどのGNU / Linuxオペレーティングシステム)のデフォルトのユーザーシェルです。したがって、Ubuntuを使用していて、シェルが何であるかわからない場合は、ほぼ確実にBashです。一般的なシェルは通常、ディレクトリトラバース**
グロブをサポートしていますが、常に同じように機能するとは限りません。詳細については、ステファンChazelasの優れた答えに*** LS **とLS、LS *の結果を上Unix.SE。
globstar bash シェルオプションをオンにすると**
、ディレクトリセパレーター(/
)を含むパスに一致します。したがって、これはディレクトリを再帰するグロブです。具体的には、man bash
次のとおりです。
ときglobstarのシェルオプションが有効になっている、と*パス名展開のコンテキストで使用され、隣接する二つの*は、すべてのファイルと0個以上のディレクトリおよびサブディレクトリに一致する単一のパターンとして使用するのです。/が後に続く場合、2つの隣接する*はディレクトリとサブディレクトリのみに一致します。
特に**
を意図したときに書き込む場合は、意図したよりもはるかに多くのファイルを変更または削除するコマンドを実行できるため、これには注意が必要です*
。(このコマンドでは安全でshopt -u globstar
、ファイルは変更されません。)globstarシェルオプションをオフに戻します。
find
ます。find
globstarよりもはるかに多用途です。globstarでできることは何でも、find
コマンドでもできます。私はglobstarが好きで、時にはもっと便利ですが、globstarはの一般的な代替手段ではありませんfind
。
上記のメソッドは、名前が.
。で始まるディレクトリ内を検索しません。そのようなフォルダを再帰したくない場合もありますが、そうする場合もあります。
通常のグロブと同様に、シェルは一致するすべてのパスのリストを作成しgrep
、グロブ自体の代わりにコマンド()に引数として渡します。呼び出さfile.txt
れたファイルが非常に多く、結果のコマンドが長すぎてシステムを実行できない場合、上記の方法は失敗します。実際には、(少なくとも)何千ものそのようなファイルが必要ですが、それは起こる可能性があります。
使用するメソッドはfind
、次の理由によりこの制限を受けません。
Zannaの方法は、grep
潜在的に多くのパス引数を使用してコマンドをビルドおよび実行します。しかし、単一のパスにリストできるよりも多くのファイルが見つかった場合、+
-terminated -exec
アクションは、いくつかのパスでコマンドを実行し、さらにいくつかのパスでコマンドを実行します。以下の場合、grep
複数のファイル内の文字列のためのINGのは、これは正しい動作を生成します。
ここで説明するglobstarメソッドのように、これは一致するすべての行を出力し、それぞれにパスを付加します。
sudodusの方法は、検出grep
されたそれぞれに対して個別に実行されますfile.txt
。多くのファイルがある場合、他の方法よりも遅いかもしれませんが、動作します。
このメソッドはファイルを見つけてパスを出力し、続いて一致する行があればそれを出力します。これは、私のメソッドであるZanna'sおよびmuru'sによって生成された形式とは異なる出力形式です。
find
globstarを使用する直接の利点の1つは、Ubuntuのデフォルトでは、grep
カラー化された出力を生成することです。しかし、これも簡単に取得できfind
ます。
Ubuntuのユーザーアカウントは、実際に実行する(表示するために実行する)エイリアスを使用して作成されます。エイリアスは、インタラクティブに発行する場合にのみ展開されるのは良いことですが、フラグで呼び出す場合は、明示的に記述する必要があります。例えば:grep
grep --color=auto
alias grep
find
grep
--color
find . -name file.txt -exec grep --color=auto -H 'pattern' {} +
bash
これを機能させるにはシェルを使用する必要があることをより明確に述べたい場合があります。「グロブスターbashシェルオプション」では暗黙のうちにそれを言っていますが、速すぎて読む人には簡単に見落とされる可能性があります。
**
グロブを、あなたのコアの批判は正しいです:のプレゼンテーション**
この答えでは唯一のshoptいるbashのとでは、bashに固有の用語「globstar」である(と思う)はbashとtcshのみ。もともとこれらの複雑さのためにこれについて説明しましたが、あなたはそれがやや紛らわしいことは正しいです。この回答で詳細に説明するのではなく、私は重いリフティングを行う別の(非常に徹底的な)投稿にリンクしました。
-e
パスに適用すべきではないのは事実ですが、これは簡単に修正できます。最初のコマンドについては、単に省略し-e
ます。2番目の場合、find . -name file.txt -printf $'\e[32m%p:\e[0m\n' -exec grep -i "pattern" {} \;
またはを使用しますfind . -name file.txt -exec printf '\e[32m%s:\e[0m\n' {} \; -exec grep -i "pattern" {} \;
。ユーザーは-e
、一致する行ごとに1つのパスを出力する他の方法よりも(使用方法を固定して)あなたの方法を好む場合があります。yoursは、見つかったファイルごとに1つのパスを出力し、その後にgrep
結果を出力します。
grep
それ自体はあなたがしていることをしません。他の批判も間違っていました。grep -H
run by -exec
はなしでは色付けしません--color
(またはGREP_COLOR
)。IEEE 1003.1-2008では{}
拡張が保証されていません##### {}:
が、UbuntuにはGNU findがあります。よろしければ、投稿を編集して-e
バグを修正し(そしてユースケースを明確にします)、削除を取り消すかどうかを確認します。(削除された投稿を表示/編集する担当者がいます。)
find
これは必要ありません。grep
これを単独で完全に処理できます:
grep "pattern" . -airn --include="file.txt"
からman grep
:
--exclude=GLOB
Skip files whose base name matches GLOB (using wildcard
matching). A file-name glob can use *, ?, and [...] as
wildcards, and \ to quote a wildcard or backslash character
literally.
--exclude-from=FILE
Skip files whose base name matches any of the file-name globs
read from FILE (using wildcard matching as described under
--exclude).
--exclude-dir=DIR
Exclude directories matching the pattern DIR from recursive
searches.
--include=GLOB
Search only files whose base name matches GLOB (using wildcard
matching as described under --exclude).
find?
多くの場合、muruの回答に記載されている、ファイル名を指定するフラグを指定grep
して実行する方法--include
が最良の選択です。ただし、これはでも実行できfind
ます。
この回答のアプローチでは、見つかった各ファイルに対して個別find
に実行grep
し、各ファイルに見つかった一致する行の上に、各ファイルへのパスを1回だけ出力します。(一致するすべての行の前にパスを印刷する方法は、他の回答で説明されています。)
これらのファイルがあるディレクトリツリーの最上部にディレクトリを変更できます。次に実行します:
find . -name "file.txt" -type f -exec echo "##### {}:" \; -exec grep -i "pattern" {} \;
これは、.
という名前の各ファイルのパス(現在のディレクトリに対する相対パス、およびファイル名自体を含む)を出力しfile.txt
、その後にファイル内のすべての一致する行が続きます。これ{}
は、見つかったファイルのプレースホルダーであるため機能します。各ファイルのパスは#####
、接頭辞としてを付けることで内容とは別に設定され、そのファイルの一致する行の前に一度だけ印刷されます。(file.txt
一致するものを含まないファイルのパスは印刷されます。)この出力は、一致するすべての行の先頭にパスを印刷するメソッドから得られるものよりも整然としています。
正しい名前のファイルを検索し、他のすべてのファイルをスキップするため、find
このように使用すると、ほとんどの場合grep
、すべてのファイルで実行するよりも高速になります(grep -arin "pattern" *
)find
。
UbuntuはGNUの検索使用し、常に拡大し{}
、それが長い文字列で表示された場合でも同様に、##### {}:
。これをサポートしない可能性のあるシステムでコマンドを使用find
する必要がある場合、または-exec
絶対に必要な場合にのみアクションを使用する場合は、次を使用できます。
find . -name "file.txt" -type f -printf '##### %p:\n' -exec grep -i "pattern" {} \;
出力を読みやすくするために、 ANSIエスケープシーケンスを使用して色付きのファイル名を取得できます。これにより、各ファイルのパス見出しは、その下に印刷される一致する行から目立ちやすくなります。
find . -name file.txt -printf $'\e[32m%p:\e[0m\n' -exec grep -i "pattern" {} \;
それはあなたのシェルが原因オンにするエスケープコードの端末に緑の生成、実際のエスケープシーケンスに緑のために、通常の色のエスケープコードで同じことをやって。これらのエスケープはに渡されfind
、ファイル名を出力するときに使用されます。($'
'
ここでは、ANSIエスケープコードの解釈に対してfind
'の-printf
アクションが認識さ\e
れないため、引用が必要です。)
ご希望の場合は、代わりに使用することができ-exec
て、システムのprintf
コマンド(サポートしています\e
)。同じことをする別の方法は次のとおりです。
find . -name file.txt -exec printf '\e[32m%s:\e[0m\n' {} \; -exec grep -i "pattern" {} \;
find abc/def/efg -name "file.txt" -type f -exec echo -e "##### {}:" \; -exec grep -i "pattern" {} \;
cd abc/def/efg
「ディレクトリの変更」コマンドは削除されます:-)
-e
オプションを指定するのecho
ですか?これにより、バックスラッシュを含むファイル名が破損します。(2)引数の一部{}
としての使用は、機能することが保証されていません。-exec echo "#####" {} \;
またはと言う方が良いでしょう-exec printf "##### %s:\n" {} \;
。(3)-print
またはを単に使用しないのはなぜ-printf
ですか?(4)も考慮してくださいgrep -H
。
find . -name "file.txt" -type f -exec echo -e "\0033[32m{}:\0033[0m" \; -exec grep -i "pattern" {} \;
2)あなたは正しいかもしれませんが、今のところこれは私のために働いています。3)-printおよび-printfも選択肢です。4)これはすでに主要な回答にあります。-とにかく、あなた自身の答えを歓迎します:
-exec
呼び出しは必要ありません。使用するだけでgrep -H
、ファイル名(色)と一致したテキストが印刷されます。
質問の条件を文学的にとることができる場合、直接grepを使用できることを指摘するだけです。
grep 'pattern' abc/def/efg/*/file.txt
または
grep 'pattern' abc/def/efg/{1..300}/file.txt