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