複数のディレクトリをfindの-pruneオプションに渡す


9

findバックアップファイルの検索と削除に使用していますが、特定のディレクトリを検索から除外したいと考えています。バックアップファイル名はで終了する可能性があり.bckbak~、またはbackup

除外するディレクトリが3つだけのMinimal Working Example(MWE)コードは次のとおりです。

#! /bin/bash
find . -type d \( -path "./.*" -o -path "./Music" -o -path "./Documents" \) -prune -o -type f \( -name "*.bck" -o -name "*.bak" -o -name "*~" -o -name "*.backup" \) -print0 | xargs -0 --no-run-if-empty trash-put

構文\( -path "dir1" -o -path "dir2" ... -o -path "dirN" \) -pruneは少し不格好に見えます。特に、除外するディレクトリが約10ある場合、MWEでは3つしか示していません。

除外されたディレクトリのリストを含む入力ファイル、または配列またはリストのような構成のいずれかを使用して、サービスにプッシュできるよりエレガントな方法はありますか?

私が最初の質問を書いたとき、私はもっとはっきりしないことを残念に思います。

注意:trash-putファイルをTrashcan削除する代わりに移動するユーティリティです[1]。

[1]。https://github.com/andreafrancia/trash-cli

回答:


4

私の知る限りfind、ファイルからパターンを読み取るように指示するオプションはありません。簡単な回避策は、除外するパターンをファイルに保存し、そのファイルをリバースの入力として渡すことですgrep。例として、次のファイルとディレクトリを作成しました。

$ tree -a
.
├── a
├── .aa
├── .aa.bak
├── a.bck
├── b
├── .dir1
│   └── bb1.bak
├── dir2
│   └── bb2.bak
├── b.bak
├── c
├── c~
├── Documents
│   └── Documents.bak
├── exclude.txt
├── foo.backup
└── Music
    └── Music.bak

私はあなたが正しく掲載例を理解した場合は、移動したいa.bck.aa.bakb.bakc~foo.backup及びdir2/bb2.bakゴミや休暇に.aa.bak.dir1/bb1.bakDocuments/Documents.bakMusic/Music.bakどこにあります。したがって、exclude.txt次の内容のファイルを作成しました(必要なだけ追加できます)。

$ cat exclude.txt 
./.*/
./Music
./Documents

./.*/元の検索.foo結果が現在のディレクトリにある隠しバックアップファイル()を移動するが、隠しディレクトリ(.foo/bar)にあるバックアップファイルは除外することを理解しているので、使用しました。したがって、findコマンドを実行しgrepて、不要なファイルを除外するために使用できます。

$ find . -type f | grep -vZf exclude.txt | xargs -0 --no-run-if-empty trash-put

Grepオプション:

   -v, --invert-match
          Invert  the  sense  of matching, to select non-matching
          lines.  (-v is specified by POSIX.)
   -f FILE, --file=FILE
          Obtain patterns from FILE, one  per  line.   The  empty
          file  contains  zero  patterns,  and  therefore matches
          nothing.  (-f is specified by POSIX.)
   -Z, --null
          Output a zero byte (the ASCII NUL character) instead of
          the  character  that normally follows a file name.  For
          example, grep -lZ outputs a zero byte after  each  file
          name  instead  of the usual newline.  This option makes
          the output unambiguous, even in the  presence  of  file
          names  containing  unusual  characters  like  newlines.
          This  option  can  be  used  with  commands  like  find
          -print0,  perl  -0,  sort  -z,  and xargs -0 to process
          arbitrary file names, even those that  contain  newline
          characters.

露骨に申し訳ありません。親切に私がより明確であることを望んでいる改訂された質問を見てください。
チャンドラ

@chandraは、更新された回答、同じ一般的なアイデア、異なる詳細を参照してください。
terdon

ありがとうございました。あなたは私の質問に対して私の目的のために非常に明確かつ完璧に答えました。私はあなたの答えを受け入れました。
chandra 2013

6

GNU find(つまり、非組み込みのLinuxまたはCygwinの下)では、-regexこれらの-pathワイルドカードをすべて組み合わせて1つの正規表現にすることができます。

find . -regextype posix-extended \
     -type d -regex '\./(\..*|Music|Documents)' -prune -o \
     -type f -regex '.*(\.(bck|bak|backup)|~)' -print0 |
xargs -0 --no-run-if-empty trash-put

FreeBSDまたはOSXでは、の-E代わりにを使用してください-regextype posix-extended


優れた代替回答をありがとうございます。2つの答えを受け入れることができないのは残念です。
chandra 2013

2

または)ロジックを使用して-path ... -prune囲まれた1つの式にグループ化します。\( ... \)-o

find /somepath \( -path /a -prune -o \
                  -path /b -prune -o \
                  -path /c -prune \
               \) \
               -o -print

例では、反復ディレクトリやファイルのか、下のではないだろう/somepath/a/somepath/b/somepath/c

複数のアクションを使用したより具体的な例を次に示します。

find / \( -path /dev -prune -o \
          -path /proc -prune -o \
          -path /sys -prune \
       \) \
       -o -printf '%p ' -exec cksum {} \;

1

これは質問というよりは、シェルの質問のようfindです。( -name dir1 -o -name dir2 ) -prune(「\」なし!)を含むファイルを使用すると、これを簡単に実行できます。

find ... $(< /path/to/file)

eval find$ IFS への、または$ IFSの変更による)find呼び出し自体を変更せずに、これは空白なしのパスでのみ機能します。

ファイルをより単純にしたい場合は、スクリプトを記述できます。

# file content
dir1
dir2
dir3

# script content
#!/bin/bash
file=/path/to/file
# file may be checked for whitespace here
grep '[^[:space:]]' "$file" | { empty=yes
  while read dir; do
    if [ yes = "$empty" ]; then
      echo -n "( "
      empty=no
    else
      echo -n " -o "
    fi
    echo -n "-name ${dir}"
  done
  if [ no = "$empty" ]; then
    echo -n " ) -prune"
  fi; }

そして使う

find ... $(/path/to/script)

代わりに。


露骨に申し訳ありません。親切に私がより明確であることを望んでいる改訂された質問を見てください。
チャンドラ

@chandra私はあなたの質問がどのようにはっきりしているのかわかりませんし、私の解決策で何が問題になる可能性があるのか​​も理解していません(-nameによる些細な補充を除いてpath)。
Hauke Laging

上記の私のスクリプトは機能し、私が望んでいることを行います。私は単純\( -path "dir1" -o -path "dir2" ... -o -path "dirN" \) -pruneに、特定のディレクトリを再帰検索から除外するよりも適切な方法があるかどうかを知りたかっただけfindです。私はファイル内を検索するのではなく、特定のファイルを削除し、検索パス内の特定のディレクトリを回避します。あなたのスクリプトが何をしようとしているのかもわかりません。ですから、コミュニケーションに問題があるようです。ごめんなさい。そのままにしておきましょう。
チャンドラ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.