grep -v 意外行为

Wan*_*rer 4 grep bash rm

假设我有一个简单的愚蠢脚本,它通过结尾删除文件,如下所示:

rm *.uvw *.xyz
Run Code Online (Sandbox Code Playgroud)

如果脚本rm无法找到至少一个具有指定结尾的文件,则该脚本,或者更准确地说,会在 stderr 上写入消息。

现在让我们说脚本有点大,并且对更多的文件类型做了更多的事情,我对哪些文件类型存在哪些不感兴趣,但是关于不存在的文件类型的抱怨阻碍了其余的我更感兴趣的输出和错误消息,所以我想过滤输出:

rm *.uvw *.xyz 2>&1 | grep -v "No such file or directory"
Run Code Online (Sandbox Code Playgroud)

这在大多数情况下工作正常,但它删除了交互式对话框的消息部分,例如询问是否应删除写保护的文件,因此我在没有相应消息的情况下收到提示。

我不理解这种行为,也找不到任何相关信息。有人可以解释一下吗?

Joh*_*024 10

问题

当 rm 提示 use for input 时,它不会在提示末尾放置换行符:

$ rm *.uvw *.xyz
rm: remove write-protected regular empty file 'a.xyz'?
Run Code Online (Sandbox Code Playgroud)

grep是基于线的。它只能处理完整的行。在该行完成之前,它无法判断是否应打印该行。因此,处理缓冲的标准实用程序,例如stdbuf,无济于事。

解决方案

使用 nullglob 并删除丢失的文件消息。

如果没有 nullglob,您不想要的消息就会出现:

$ rm *.uvw *.xyz
rm: cannot remove '*.uvw': No such file or directory
rm: remove write-protected regular empty file 'a.xyz'? n
Run Code Online (Sandbox Code Playgroud)

有了它,“没有这样的文件或目录”消息被抑制:

$ shopt -s nullglob
$ rm *.uvw *.xyz
rm: remove write-protected regular empty file 'a.xyz'? n
Run Code Online (Sandbox Code Playgroud)

细化

如果根本没有与任一 glob 匹配的文件,则会出现不同的错误消息:

$ shopt -s nullglob
$ rm *.uvw *.xyz
rm: missing operand
Try 'rm --help' for more information.
Run Code Online (Sandbox Code Playgroud)

避免这种情况的一种简单方法是确保至少存在一个这样的文件:

shopt -s nullglob
[ -e "deleteme.xyz" ] ||touch deleteme.xyz
rm *.uvw *.xyz
Run Code Online (Sandbox Code Playgroud)

既然deleteme.xyz反正都会被抹掉,跑之前摸一下也无妨rm