バックアップファイルを見つけて削除するために使用していますが、find
特定のディレクトリを検索から除外したいと思います。バックアップファイル名は、.bck
またはで終わることができます。bak
~
backup
3 つのディレクトリのみを除外する最小作業例 (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
MWEでは3つしか表示していませんが、除外するディレクトリが10個ほどある場合、構文が少し薄暗く見えます。
サービスにプッシュできる入力ファイル(除外ディレクトリのリストを含む)や、配列やリストなどの設定を使用するよりエレガントな方法はありますか?
もともと質問を書くときは明確ではないので申し訳ありません。
注:trash-put
ファイルを削除する代わりにファイルを移動するTrashcan
ユーティリティです[1]。
答え1
使用-path ... -prune
(-o
または)括弧でグループ化された論理\( ... \)
find /somepath \( -path /a -prune -o \
-path /b -prune -o \
-path /c -prune \
\) \
-o -print
この例では、/somepath/a
ディレクトリやファイルは繰り返されません。/somepath/b
/somepath/c
これは、いくつかの式と複雑な操作を使用して設計された例です-exec
。これは、Linuxホスト上の純粋ファイルへのファイルパスとチェックサムを印刷し、主に一時ファイルまたは文字デバイスを含むパスを切り取ります。
$ find / \( -path /dev -prune -o \
-path /proc -prune -o \
-path /sys -prune \
\) \
-o -type f \
-printf '%p ' -exec sh -c 'md5sum -- "{}" | cut -f1 -d" "' \;
/etc/services 00060e37207f950bf0ebfd25810c19b9
/etc/lsb-release f317530ede1f20079f73063065c1684e
/etc/protocols bb9c019d6524e913fd72441d58b68216
/etc/rsyslog.conf 8f03326e3d7284ef50ac6777ef8a4fb8
...
答え2
GNU findを使用すると(つまり、組み込みのLinuxまたはCygwinでは)、-regex
これらすべての-path
ワイルドカードを単一の正規表現に組み合わせることができます。
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
BSDまたはmacOS-E
では-regextype posix-extended
。
また、それをより短い標準語に置き換えることもできます-print0 | xargs -0 --no-run-if-empty trash-put
。--no-run-if-empty
-exec trash-put {} +
1 ただし、より短い-r
形式は他のいくつかの実装でサポートされており、一部のBSDではデフォルトの実装でもあります。
答え3
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.bak
b.bak
c~
foo.backup
dir2/bb2.bak
.aa.bak
.dir1/bb1.bak
Documents/Documents.bak
Music/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
グレブオプション:
-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.
答え4
これは問題ではなくシェル問題のように見えますfind
。 (「\」なし!)を含むファイルの場合は、( -name dir1 -o -name dir2 ) -prune
単に次のことができます。
find ... $(< /path/to/file)
ただし、これは検索呼び出し自体を変更せずに($ IFSを変更または変更することで)、eval 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)
代わりに。