
(元のタイトル: 行ではなく段落単位での grep)
この質問の動機はfzf
、巨大なファイルシステム内の特定のファイルを見つけることを可能にすることです。曖昧に、そして段階的に非常に高速な検索体験を提供します(この記事)。
私が考えているのは、自分のメモに同じようなことをすることです。私は、プレーンテキスト形式で、たくさんのメモ、日記、メモなどを持っています。読みやすさ、各行には 72 文字以下しか含まれません。 、などの既存の検索ツールに関する私の素朴な知識に基づくと、このため私のメモは検索されにくくなりますgrep
。ripgrep
これで、(もっと/少ない) コンテキストで一致したパターンを囲むように記述したいのですが、それは私が求めているものではありません。ここでは、より正確にするために例を示します。
1 Victim mentality is an acquired personality trait in which a person
2 tends to recognize or consider themselves as a victim of the negative
3 actions of others, and to behave as if this were the case in the face
4 of contrary evidence of such circumstances. Victim mentality depends
5 on clear thought processes and attribution.
6
7 (from wikipedia: Victim mentality)
半年前にこのメモを取ったとしましょう。そして、それが私のファイルシステムのどこかにあると分かっています。いつものように、正確な言葉を暗唱することはできませんが、私たちは文脈を覚えている! 、、などgrep
のテキストをファイルシステムにコピーすると、personality
clear thought
victim
あまりにも私にとって本当に絞り込むべき関連事項がたくさんあります。
このようなテキストを検索するのに役立つツール(存在するかどうかは関係なく)があるはずです。私たちの古いメモ(プレーンテキスト)ははるかに価値があるでしょう. 私たちの古くからの友人とその親戚と一緒にそれを行う方法はあるでしょうかgrep
? または、他に機能する方法はあるでしょうか? ご意見も大歓迎です。
答え1
(検索) プロセスを小さな部分に分割してみましょう。
.
まず、現在のディレクトリ ( ) 内の、txt 拡張子 ( ) を持つすべてのファイル ( )など、検索するファイルのリストを取得する必要があります。-name "*.txt"
これは確かにファイル ( -type f
) です。
find . -name "*.txt" -type f
この結果は、大文字と小文字を無視して行番号とファイル名を出力に含めて、それらのファイル内をgrep
検索するための入力として使用できます。最終的には、すべてのファイルが 1 回の実行で grep されるようになります (一度に 1 つずつではありません)。something
-nHi
+
find . -name "*.txt" -type f -exec grep -nHi 'something' {} +
ファイル数が大きすぎる場合(> $ARG_MAX
)、+
と\;
。
前のコマンドの出力は次のようになります。
./some/dir/somewhere/songs.txt:128:But had me believing it was always something that I'd done
./some/dir/somewhere/songs.txt:883:Was never something I pursued
./some/dir/somewhere/songs.txt:2905:I know something about love
./some/dir/somewhere/songs_other.txt:11780:will come across something like this: F (Dshape).
したがって、これらの行を分割すると、:
ファイル名、一致が見つかった行番号、および行自体の 3 つのコンポーネントが得られます。
ここで、一致したファイルごとにこの情報を保持すると、次の用語を検索し、一致距離を合計して、検索した用語が最も近いファイルを見つけることができます。
例のテキストで 3 つの用語 ( personality
、、 ) を検索するとclear thought
、victim
対応する行番号は 1、5、2 になります。したがって、このファイルの距離は (最初の用語から) です。
abs(1-5) + abs(1-2) = 5
したがって、すべての用語を含み、そのファイル内で最も近いものになるようにファイルを並べ替えることができます。
もちろん、これは全体像ではありません。たとえば、一部のファイルには同じ用語が複数回含まれており、このアルゴリズムは距離を計算する方法を決定する必要がありますが、上記は出発点になると思います。
答え2
簡単な Perl ワンライナーでこの作業を実行できます。次のコードは、すべてのキーワード (つまり、および とpersonality
がclear thought
ファイルvictim
内に存在する場合) がある場合に、ファイル名の後に "found" を出力します。
perl -0777 -ane 'print "$ARGV: found\n" if /^(?=.*personality)(?=.*clear thought)(?=.*victim)/s' file.txt
出力:
file.txt: found
説明:
-0777 # slurp mode
-ane # read the file ans execute the following
print "$ARGV: found\n" # print,$ARGV contains the current filename
if # if
/ # regex delimiter
^ # begining of file
(?=.*personality) # positive lookahead, make sure we have "personality"
(?=.*clear thought) # positive lookahead, make sure we have "clear thought"
(?=.*victim) # positive lookahead, make sure we have "victim"
/s # regex delimiter, s = dot matches newline
すべてのtxtファイルを検索する場合は、perl ...... *.txt