要約:
~=
[type of file].[8-digit date]
という名前のテキストファイルがたくさんあります。find /path/ -name 'file.nnnn*' -print | xargs -e fgrep -nH -e 'text I seek'
(ここでnnnn
== 4桁の年)find /path/ -name 'file.201[89]*' -print | xargs ...
のように、find
グロブを何年にもわたって作成しましたfind /path/ -name 'file.20{19,20}*' -print | xargs ...
を使用して2019年と2020年にfind
グロブを作成できませんls
で正常に動作しますが!代わりにpost_find
のクリーンアップ(つまり、私が今行っていること)を行わずに、find
に必要なものを伝える{簡潔でエレガントな}方法はありますか
find /path/ -name 'file.*' -print | grep -e '\.2019\|\.2020' | xargs ...
? FWIW、私はxargs
で動作するソリューションを好みます。
詳細:
私はずっと以前からあり、変更することができない多くの規則を持つシステムに取り組んでいます。それらの1つは、~=
[type of file].[8-digit date]
という名前のたくさんのテキストファイルがあります(例:woohoo_log.20191230
)。これらのファイル内で特定のテキストを検索するとき、私は通常(ほとんどの場合)、find ... grep
イディオムを使用します(多くの場合、EmacsのM-x find-grep
を使用します)。 (FWIW、これはLinuxシステムで、
$ find --version
find (GNU findutils) 4.4.2
...
$ bash --version
GNU bash, version 4.3.30(1)-release (x86_64-pc-linux-gnu)
そして、私は現在、それらのいずれかを変更する必要がある場合、ステータスを欠いています。)対象の年の範囲をよく知っているので、find
が返すものを(処理を高速化するために)制約します(たとえば、 )
find /path/ -type f -name 'file.nnnn*' -print | xargs -e fgrep -nH -e 'text I seek'
ここで、nnnn
== 4桁の年。このWFM、そして私は上記のイディオムを使用するのが好き(そして使い続けたい)...特に、次のような長年にわたる検索にも使用できるので
find /path/ -type f -name 'file.201[89]*' -print | xargs ...
しかし、この新しい10年間はそのイディオムを壊しているようで、(少なくとも私にとっては)最も奇妙なことです。 (最後の10年が変わったとき、私はここにいませんでした。)私がknowが2019 &&のファイルにあるテキストを選択するとします&& 2020のファイル(のように、ファイルを開いてテキストを表示できます)。私が現在している場合
find /path/ -name 'file.20{19,20}*' -print | xargs ...
grep
が予期せず/迷惑にwith no matches found
を終了します。
$ find /path/ -name 'file.20{19,20}*' -print | wc -l
0
しかし、私がするなら
find /path/ -type f -name 'file.*' -print | grep -e '\.2019\|\.2020' | xargs ...
grep
は期待される結果を返します。これはいいことですが...うーん...醜いです。特に、この「中かっこグロブ」(この使用法が正しくないか、廃止されている場合は修正してください)がls
で機能するためです!つまり、関連する年の範囲(つまり、2019..2020)のファイルが表示されます
ls -al /path/file.20{19,20}*
したがって、私は知りたい:
find
にこのユースケースに適したグロブを与えていませんか? find
が適切に/正しく行っていることを実行させるために、ls
に何を伝える必要がありますか?xargs
の問題ですか?もしそうなら、私はfind ... -exec
ソリューションで暮らすことができますが...私の脳はxargs
でうまく機能するので、できればそれを使い続けたいと思います。 (私を弱々しく呼んでください、しかし-exec
の構文 私の脳を傷つけます 。)zsh
を使用すると、10進数の範囲で一致する再帰的グロビングとその<x-y>
グロブ演算子を使用できます。
grep -nHFe 'text I seek' /path/**/file.<2019-2020>*(D-.)
((D)
は、隠し(D
ot)ディレクトリーもfind
と同じように調べます。たくない場合は、省略できます。-.
はregularファイル(.
)に制限します。シンボリックリンクの解決後に識別されます(-
))。
file.00002020
(2019〜2020の間の10進数であるため)にも一致し、file.20201234
のfile.2020
がfile.<2019-2020>
に一致し、 1234
は*
と一致します。
それを行うための標準(POSIX sh
およびユーティリティ)の方法は次のようになります。
find /path \( -name 'file.2019*' -o -name 'file.2020*' \) -type f \
-exec grep -Fne 'text I seek' /dev/null {} +
(/dev/null
を追加すると、GNU grep
's -H
と同じ効果が得られ、ファイル名が強制的に表示されます))
find -print
の出力は、xargs
の予期される入力形式と互換性がないことに注意してください。 GNUユーティリティを使用すると、find -print0
とxargs -r0
を使用できますが、find -exec ... {} +
の動作は同じで、短く、移植性が高いため、これは不要です。
ls -al /path/file.20{19,20}*
では、{19,20}*
で何かをするのはls
ではありません。このコマンドでは、シェルは/path/file.20{19,20}*
に対して ブレース展開 および globbing を引用されていないとして実行します。
bash-5.0$ set -x
bash-5.0$ echo {a,b}
+ echo a b
a b
bash-5.0$ ls {a,b}
+ ls a b
ls: cannot access 'a': No such file or directory
ls: cannot access 'b': No such file or directory
bash-5.0$ find -iname {a,b}
+ find -iname a b
find: paths must precede expression: `b'
find /path/ -name 'file.20{19,20}*'
では、'file.20{19,20}*'
が引用されているため、シェルはそのままにし、find
は独自の パターンマッチングルール を適用します。ここで GNU find
manual を引用します:
パターン内のブレース( ‘
{}
’)は特別であるとは見なされません(つまり、find . -name 'foo{1,2}'
は、foo{1,2}
というファイルではなく、foo1
およびfoo2
というファイルとは一致しません。
本当に中かっこ展開を使用してディレクトリを再帰的に検索する場合は、bashで再帰的グロビング( globstar
)(およびdotglob
がfind
のように隠しディレクトリを調べることができる)を有効にして、printf
を次のように使用できますxargs
:
shopt -s globstar
printf "%s\0" /path/**/file.20{19,20}* | xargs -0 ...
または、いくつかのfind
実装でサポートされている-regex
の代わりに-name
でfind
を使用できます。 GNU find
:
find /path -regextype posix-extended -regex '.*/file.20(19|20)[^/]*'
これは、質問に対する一般的なケースの回答ではありませんが、ファイル履歴の量によっては、簡単な方法がある場合があります。私は9月/ 10月に物事を探しているときに、何ヶ月も同じような状況に遭遇することがよくあります。簡単な回避策の1つは、次のようなaパターンを使用することです。
file.20[12][90]*
2019と2020に加えて、それは2010と2029にも一致するため、同一ではありません。おそらく2029の日付のファイルはありません。アーカイブが2010年までさかのぼらない場合、これは機能するはずです。同等。