最近,我面临一项任务,需要删除目录中除符合特定模式的文件/文件夹之外的所有文件/文件夹。因此,我编写了一个单行 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
]