ripgrepに出力されたパスリストの各パスを個別に処理する方法

ripgrepに出力されたパスリストの各パスを個別に処理する方法

私はLinux Ubuntu 18.04と20.04を使用しています。

Ripgrep( rg) は、次のように一致を含むファイルのパスのリストを出力できます。

# search only .txt files
rg 'my pattern to match' -g '*.txt' -l
# long form
rg 'my pattern to match' --glob '*.txt' --files-with-matches

出力は次のとおりです。

path/to/file1.txt
path/to/file2.txt
path/to/file3.txt

など。

tree $(dirname $PATH)次に、各パスで異なるコマンドを実行して、一致するファイルを含むディレクトリ内のすべてのファイルのリストを取得したいと思います。どうすればいいですか?

xargsそれが答えの一部になるかもしれませんか?しかし、xargsこのようなパイプラインで始めると、最後に印刷されたファイルだけを処理するようです。

rg 'my pattern to match' -g '*.txt' -l | xargs -0 -I {} dirname {}

注:Tooを使用してデモンストレーションできる場合は、ripgrepを持ってgrepいない人にも役立ちます。ripgrepインストールはとても簡単です。

引用:

  1. ripgrep:パターンに一致するファイル名のみを印刷する

ベストアンサー1

GNUシステムでは、次のように見えます。

rg -g '*.txt' -l0 'my pattern to match' | # list files NUL-delimited
  xargs -r0 dirname -z -- |               # takes dirnames
  LC_ALL=C sort -zu |                     # remove duplicates
  xargs -r0 tree --

両方dir/file.txtが一致すると、両方で実行されるため、dir/subdir/file.txt内容は2回表示されます。treedirdir/subdirdir/subdir

あなたの考えは正しいです。xargswhich isコマンドを使用してバイト文字列をパラメータリストに変換してコマンドに渡し、-0whichを使用すると、任意のパラメータリストを渡す最も信頼性の高い方法になります。

  • xargs -0入力は、パラメーター・リストがNUL文字(0バイト)で区切られた形式であると予想されます。この形式でファイルリストを印刷するには、-0/オプションが必要です。--nullrg
  • GNUはdirname呼び出しごとに複数の引数を処理できるため、-I{}これを使用する代わりにすべての引数を渡します。また、ファイルのリストが空の場合、それをまったく呼び出さずに-rNULで区切られたディレクトリを印刷するオプション自体もGNUに対応します。dirname-zdirnamedirname
  • 各ファイルにはプレフィックスが付いていないため、ファイル名の前に s が付く問題を回避するために、ファイルのリストを引数として渡すコマンドにrgオプションの区切り./文字を使用することが重要です。---

簡単に言うと、値がNULではなくバイトシーケンス(ファイルパスや任意のコマンド引数など)になる可能性があるリストの場合、NULで区切られたレコードを交換形式で使用するツールとツールの間でプログラムでリストを渡そうとします。 。人間の形式でのみユーザーにフィードバックを提供します(ここではツリー出力tree)。


GNU以外のシステムでは、zshシェルを使用して次のことができます。

files=( ${(0)"(rg -g '*.txt' -l0 'my pattern to match')"} )
typeset -U unique_dirs=( $files:h )
(( $#unique_dirs )) && tree -- $dirs

または一度に(一致するファイルが1つ以上あると仮定):

tree -- ${(u)${(0)"$(rg -g '*.txt' -l0 'my pattern to match')"}:h}

u(nique u)交換しましたtypeset -U。パラメータ拡張フラグは、NULで分割するように0 指示する方法です。あるいはzshIFS=$'\0'トークン化を設定して使用することもできます(引用符なしの引数拡張中に実行されます)。

IFS=$'\0'
tree -- ${(u)$(rg -g '*.txt' -l0 'my pattern to match'):h}

GNUユーティリティもGNUユーティリティもない場合は、zshいつでも次のものを使用できますperl

rg -g '*.txt' -l0 'my pattern to match' |
  perl -MFile::Basename -MList::Util=uniq  -0 -e '
    @dirs = uniq(map {dirname$_} <>);
    exec "tree", "--", @dirs if @dirs'

¹これは、コマンド引数には表示できない唯一の文字/バイト値です(引数は、execve()システムコールからNULで区切られた文字列に渡されるため)。しかし、パイプを介して供給されるバイトストリームには現れる可能性があるので、単純で明確です。任意のパラメータを分離する方法です。-0GNU実装の非標準的な拡張ですが、他の多くの実装xargsでも見つけることができます。

²または少なくとも1回の通話に入ることができるだけ、dirname必要なだけ通話してください。

おすすめ記事