Unix-删除不包含PATTERN的文件和文件夹


10

最近,我面临着删除目录中所有文件/文件夹的任务,但不包括与特定模式匹配的文件/文件夹。因此,我编写了单行的unix命令来完成工作。只能是一行吗?我想不是,但是那样肯定更酷!

虽然问题很简单,但我对解决方案的复杂程度感到有些惊讶。这是我使用的命令;注意:这是一个糟糕的解决方案,因为它不处理包含换行符的文件名(在我的情况下这无关紧要)。

ls | grep -v PATTERN | xargs -n1 -IREPLACE rm -rf REPLACE

我没有使用“ find”命令,因为我不想递归到与PATTERN匹配的文件夹中。例如,考虑以下文件结构:

file_foo.txt
first_dir
  |
  +--> contents
  +--> ...
foo_dir
  |
  +--> anotherfile.txt
  +--> morefiles.log
foo_file.txt
somefile.txt

使用模式“ foo”只能删除“ first_dir”(当然是它的内容)和“ somefile.txt”(而不是 “ anotherfile.txt”或“ morefiles.log”)。

问题,是否有更好(更优雅,更正确)的方法来实现这一目标?


编辑:
最近引起我注意,“查找”可能是一个更好的选择:

find * -maxdepth 0 ! -name PATTERN -print0 | xargs -0n1 rm -rf

此解决方案可以正确处理包含换行符的路径。


编辑:更改错误的“ the_dir”以更正“ first_dir”。
joxl 2010年

Answers:


10

以下示例带有echo前缀,以便您可以在实际使用模式之前对其进行测试。删除echo以激活rm -rf。替换rm -ri以提示确认。

ksh对它的glob具有负匹配扩展名:

# ksh
echo rm -rf !(*foo*)

如果设置以下选项,则bash中可以使用相同的语法extglob

# bash
shopt -s extglob
echo rm -rf !(*foo*)

zsh为此具有自己的语法:

# zsh
setopt extended_glob
echo rm -rf ^*foo*

它还可以使用ksh -style语法:

# zsh: ksh-style glob syntax
setopt ksh_glob no_bare_glob_qual
echo rm -rf !(*foo*)

# zsh: ksh-style glob syntax, adapted for the default bare_glob_qual option
setopt ksh_glob bare_glob_qual
echo rm -rf (!(*foo*))

简单,优雅,可以处理换行符,(几乎)一行(我已经添加shopt -s extglob到我的.bashrc文件中,所以现在它单行的)。完善!我保证在我的声誉允许的情况下会立即投票。
joxl 2010年

7

这是另一个find解决方案。我不确定这是否会比您的有任何真正的优势,但是它并不需要,xargs并且允许*扩展为太多名称的可能性很小。

find . -maxdepth 1 ! -name PATTERN -type f -delete

我还添加-type f了它,使其不会尝试删除目录。

警告:-delete功能强大。我给我的测试文件之一授予0权限,上面的命令毫不犹豫地将其删除。


6
首先测试。替换-delete-print以查看是否找到了所需的文件。如果一切正常,请使用命令历史记录(例如,按向上按钮)返回上一个命令,以确保您使用的是相同的查找过滤器。
道格·哈里斯

请仔细阅读,注意我确实希望删除目录。并且find -delete不会删除非空目录。还要注意find -maxdepth 1匹配“。” (当前目录),这真的很糟糕。尽管我喜欢您消除的想法xargs,但也可以find -exec选择使用。 find * -maxdepth 0 ! -name PATTERN -exec rm -rf '{}' \;
joxl

0

您可以使用以下rebol脚本示例http://askcodegeneration.com/keep-subversion/ 代替,它更容易理解,并且可以管理用户交互,例如文件夹选择和确认:

delete-file: func[file][
    if/else none? find file "/.svn/" [
        delete file
    ][
        print ["keeping" file]
    ]
]
dir: request-dir
ans: ask rejoin ["Do you confirm " dir "? (Yes): "]
if (ans = "Yes") [
    foreach-file dir :delete-file
]
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.