将多个目录传递给find中的-prune选项


9

find用来查找和删除备份文件,但希望从搜索中排除某些目录。备份文件名可能会终止.bckbak~,或backup

只有三个要排除的目录的最小工作示例(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中仅显示了三个。

是否有使用输入文件,排除目录列表或可以压入服务的类似数组或列表的构造的更优雅的方法?

很抱歉,我在写原始问题时没有说清楚。

注意:trash-put是一个实用程序,用于将文件移至Trashcan而不是将其删除[1]。

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

Answers:


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.backupdir2/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

@chandra看到更新的答案,相同的基本思想,不同的细节。
terdon

谢谢。您已经非常清楚,完美地回答了我的问题。我接受了你的回答。
chandra

6

使用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

对于FreeBSD或OSX,请使用-E代替-regextype posix-extended


感谢您提供出色的替代答案。很遗憾我不能接受两个答案。
chandra

2

使用()逻辑分组-path ... -prune为一个表达式。\( ... \)-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)

但是,无需更改find​​调用本身(eval find更改为$ IFS或更改$ IFS),它仅适用于没有空格的路径。

如果您想简化文件,可以编写脚本。

# 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

@chandra我既看不到您的问题如何清晰明了,也无法理解我的解决方案可能存在的问题(-nameby 的琐碎补充path)。
Hauke Laging

我上面的脚本可以工作,并且可以实现我想要的功能。我只是想知道是否有一种更整洁的方法,而不是\( -path "dir1" -o -path "dir2" ... -o -path "dirN" \) -prune从这样find做的递归搜索中排除某些目录。我不是文件搜索任何内容而是在搜索路径中删除某些文件并避免某些目录。我也不明白您的脚本正在尝试做什么。因此,看来我们沟通有误。抱歉。让我们保留它。
chandra
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.