find -exec grepを使用してデフォルトの名前のみを印刷したり、ファイル名/行の内容を別々の行に分割するにはどうすればよいですか?

find -exec grepを使用してデフォルトの名前のみを印刷したり、ファイル名/行の内容を別々の行に分割するにはどうすればよいですか?

ソースファイルを見ています。実際にはPureBasicの場合ですが、言語に関係なく共通の要素があります。私の場合は、カバー拡張と次pbのコマンドを使用します。pbipbfpbp

find . -name "*.pb*" -exec grep -Hnr ... \;

問題はこれが原因ですfull/path/filename.ext:ln#:contents of that line

2つのうちの1つを実行したいと思います。パスを完全に切り取って(/最初のパスの前の最後のパス:)、残します。

filename.ext:ln#:contents of that line

または、区切り線を使用して次の操作を行います。

full/path/filename.ext:    
ln#:contents of that line

どちらにしても結果を読みやすくします。次の場所に分割することもできます。

full/path/filename.ext:ln#:  
contents of that line

読みやすさを高めるため。私は柔軟です。それはそれらの一つかもしれません。 1行のコマンドやこれらの特定のコマンドに限定される必要はありません。

findを含むgrep私が見つけることができるすべてのリストされたスキルを試しましたが、sed必要に応じて組み合わせを実装することはできません。

答え1

あなたの説明によると、これを行うようです(水平スクロールを避けるために4行に分割しました)。

>tmp.txt;
find . -type f -name "*.pb*" \
     -exec grep -Hn pattern "{}" ";" >>tmp.txt;
cat tmp.txt | more

-execdirGnu findを使用している場合は;を代わりに使用できます。-execこれにより、コマンドがターゲットファイルのディレクトリで実行され、そのgrep結果、ファイル名はそのディレクトリに相対的になります。 (今すぐ./filename.ext)。それじゃないかなり要求された内容ですがかなり近く、使用する必要がある他の理由もあります-execdir

     -execdir grep -Hn pattern "{}" ";"      # See note 1

別のオプションは、中間シェルを使用してファイル名タグを編集することです。これにはGnugrepオプションが必要です--label

     -exec bash -c 'grep -Hn --label="$(basename "$1")" pattern "$1"' \
           _ "{}" ";"

これはオペレーティングシステムに対してかなり長く、より多くの作業を実行しますが./

sed2番目のオプションでは、各行の最初(または2番目)行の後に改行文字を挿入して出力全体をパイプすることができます:

find . -type f -name "*.pb*" \
     -exec grep -Hn pattern "{}" ";" |
sed 's/:/&\n/' >>tmp.txt.

または(2番目のコロン):

find . -type f -name "*.pb*" \
     -exec grep -Hn pattern "{}" ";" |
sed 's/:[^:]*:/&\n/' >>tmp.txt.

ノート

  1. grepに再帰的に-r検索するように指示することは、ディレクトリを引数として提供しないので意味がありません。findすべてのファイルが再帰的に見つかりました。だから、すべての例からそのオプションを削除しました。

  2. cat tmp.txt | more猫の無駄な使用(UUOC)です。ただ使用してくださいmore tmp.txt

  3. ;より良い効率のためにGnu findに置き換えられました+(使用されている例を除くbash -c)。

答え2

探している前提から始めてください。模様あなたのファイルには、あなたが提案した各レイアウトのソリューションがあります。

  1. パス名の先頭を削除します。

    find . -name '*.pb*' -type f -execdir grep -Hn 'PATTERN' {} \; | cut -c3- >tmp.txt
    more tmp.txt
    

    参照するプログラムを使用するときはexecdir常にターゲットディレクトリから呼び出され、現在のファイルのパス名は単にパス./名からcut -c3-先行を削除することによって。./

  2. パス名で行を分割し、行番号に一致するものに従います。

    find . -name '*.pb*' -type f -exec grep -Hn 'PATTERN' {} \; | sed 's/:/:\n/' >tmp.txt
    
  3. パス名と行番号を使用して行を分割し、一致させます。

    find . -name '*.pb*' -type f -exec grep -Hn 'PATTERN' {} \; | sed 's/^\([^:]*:[^:]*:\)/\1\n/' >tmp.txt
    

    ここでsedパターンは2番目のコロンで分割されます(REは次のように読み取られます)。行の先頭から始めます。コロンが続くゼロ個以上の非コロン文字と一致します。そしてまた。次に、一致を自分で置き換えてからラップします。)。

ファイル名にコロンまたは改行文字が含まれている場合、これらの回避策のいずれも機能しません。

答え3

awk代わりに試してみてくださいgrep。たとえば、デフォルト名のみを印刷します。

find . -name '*.pb*' -exec awk 'function basename(file) {
sub(".*/", "", file)
return file
}
/pattern/{
print basename(FILENAME)":"FNR":"$0
}' {} +

パス/行の内容を分割します。

find . -name '*.pb*' -exec awk '/pattern/{print FILENAME"\n"FNR":"$0}' {} +

または

find . -name '*.pb*' -exec awk '/pattern/{print FILENAME":"FNR":\n"$0}' {} +

grepファイル名を一度だけ印刷し、そのファイル内の一致するすべての行を2つのsで印刷したい場合:

find . -name '*.pb*' -exec grep -l pattern {} \; -exec grep -n pattern {} \;

これはすべての種類のファイル名(コロンを含むファイル名を含む)で機能します。

答え4

使用grep -l

find . -type f  -exec grep -ilHn --color=always 'searchphrase' {} \;

関連情報