web-dev-qa-db-ja.com

ニューディケイド: `find / path / -name 'file.20 {19,20} *'`のようなものを発声する方法(ただし動作​​します)

要約:

  1. 特定のシステムには、~=[type of file].[8-digit date]という名前のテキストファイルがたくさんあります。
  2. これらのファイルを検索するには、次のイディオムを使用するのが好きです(そして保持したい):find /path/ -name 'file.nnnn*' -print | xargs -e fgrep -nH -e 'text I seek'(ここでnnnn == 4桁の年)
  3. ...そして過去10年間、find /path/ -name 'file.201[89]*' -print | xargs ...のように、findグロブを何年にもわたって作成しました
  4. ...しかし、今ではfind /path/ -name 'file.20{19,20}*' -print | xargs ...を使用して2019年と2020年にfindグロブを作成できません
  5. ...「カーリーブレースグロビング」(正しい用語?)は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}*

したがって、私は知りたい:

  1. 私は単にfindにこのユースケースに適したグロブを与えていませんか? findが適切に/正しく行っていることを実行させるために、lsに何を伝える必要がありますか?
  2. これはxargsの問題ですか?もしそうなら、私はfind ... -execソリューションで暮らすことができますが...私の脳はxargsでうまく機能するので、できればそれを使い続けたいと思います。 (私を弱々しく呼んでください、しかし-execの構文 私の脳を傷つけます 。)
3
TomRoche

zshを使用すると、10進数の範囲で一致する再帰的グロビングとその<x-y>グロブ演算子を使用できます。

grep -nHFe 'text I seek' /path/**/file.<2019-2020>*(D-.)

(D)は、隠し(Dot)ディレクトリーもfindと同じように調べます。たくない場合は、省略できます。-.regularファイル(.)に制限します。シンボリックリンクの解決後に識別されます(-))。

file.00002020(2019〜2020の間の10進数であるため)にも一致し、file.20201234file.2020file.<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 -print0xargs -r0を使用できますが、find -exec ... {} +の動作は同じで、短く、移植性が高いため、これは不要です。

12

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 )(およびdotglobfindのように隠しディレクトリを調べることができる)を有効にして、printfを次のように使用できますxargs

shopt -s globstar
printf "%s\0" /path/**/file.20{19,20}* | xargs -0 ...

または、いくつかのfind実装でサポートされている-regexの代わりに-namefindを使用できます。 GNU find

find  /path -regextype posix-extended -regex '.*/file.20(19|20)[^/]*'
6
muru

これは、質問に対する一般的なケースの回答ではありませんが、ファイル履歴の量によっては、簡単な方法がある場合があります。私は9月/ 10月に物事を探しているときに、何ヶ月も同じような状況に遭遇することがよくあります。簡単な回避策の1つは、次のようなaパターンを使用することです。

file.20[12][90]*

2019と2020に加えて、それは2010と2029にも一致するため、同一ではありません。おそらく2029の日付のファイルはありません。アーカイブが2010年までさかのぼらない場合、これは機能するはずです。同等。

0
Drew