Unix - 删除除 PATTERN 之外的文件和文件夹

Unix - 删除除 PATTERN 之外的文件和文件夹

最近,我面临一项任务,需要删除目录中除符合特定模式的文件/文件夹之外的所有文件/文件夹。因此,我编写了一个单行 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”保存为其他文件(例如,如果文件“anotherfile.txt”或“morefiles.log”)。

问题是,有没有更好的(更优雅和正确的)方法来实现这一点?


编辑:
最近我注意到,“find” 可能是一个更好的选项:

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

该解决方案确实正确处理了包含换行符的路径。

答案1

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

对其通配符有一个负匹配扩展:

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

相同的语法可用于狂欢如果您设置了该extglob选项:

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

有其自己的语法:

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

它还可以使用-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*))

答案2

这是另一个find解决方案。我不确定这是否比你的方案有真正的优势,但它不需要xargs并且允许 * 扩展到太多名称的罕见可能性。

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

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

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

答案3

你可以使用这个 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
]

相关内容