假设我有一个包含多个文件的目录,所有这些文件都是二进制文件(没有声明扩展名的文件)和源文件(.c
扩展名)。我这样做:
$ ls
并得到:
README.md hello-world.c hello-world get-name.c get-name
我只想列出具有特定扩展名的文件(例如.c
和.md
),我这样做:
ls *.c *.md
没关系!
但是如果现在我想删除所有文件怎么办不要有一个.c
or.md
扩展名,我该怎么做?
我知道如何处理我知道扩展名的文件,例如:
ls *.c *.md | xargs rm
但是我如何告诉命令行删除那些文件不符合我的标准吗?
答案1
使用find
:
find -maxdepth 1 ! -name "*.c" -print0 | xargs -0 ...
请注意-maxdepth
, 、-print0
、-r
和-0
在一些实现中可以找到(由 GNU /find
引入),但 POSIX 并未指定。另一种方法是,正如 Stéphane 在他的评论中提到的,使用find 的操作 - 记住使用表单,因为它大大减少了调用的次数(它必须允许将文件名放在末尾的语法,否则你需要将其包装在一个调用中)。find
xargs
-exec
-exec command {} +
command
command
sh -c
或者grep
输出ls
ls | grep -v "\.c$" | xargs ...
您可以使用正则表达式过滤多个扩展名:
... | grep -v "\.\(c\|md\)$" | ...
使用扩展的正则表达式:
... | grep -Ev "\.(c|md)$" | ...
使用固定字符串选项(仅在文件名末尾不匹配!):
... | grep -vF ".c
.md" | ...
或者通过链接更多grep
s:
... | grep -v "\.c$" | grep -v "\.md$" | ...
也就是说,find
这可能是最好的选择,因为使用该-print0
选项,它可以处理文件名中可能需要转义的所有可能字符(前提是您的find
和xargs
能够使用以 NULL 结尾的字符串 - 例如 GNU 工具是)。
答案2
在 中ksh
,您可以使用:
rm -- !(*.c|*.md)
这些通配扩展也可以在bash
aftershopt -s extglob
和 in zsh
after中使用setopt kshglob
。
以下是 zsh 本机等效项:
setopt extended_glob
rm -- ^(*.c|*.md)
!
extglob 中的 是“not” 。对于您的原始命令,最好这样写:
rm -- *.c *.md
解析 的输出ls
是不可靠的,并且会在某些文件名上中断。请参阅 bash wiki解析 ls。