获取 ls 命令结果的补码

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

但是我如何告诉命令行删除符合我的条件的文件?

pet*_*rph 6

使用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 工具)。


jor*_*anm 5

在 中ksh,您可以使用:

rm -- !(*.c|*.md)
Run Code Online (Sandbox Code Playgroud)

这些通配扩展也可以在bashaftershopt -s extglobzshafter 中使用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