为什么这个“grep -v”没有按预期运行?

为什么这个“grep -v”没有按预期运行?

我有一个与查询相关的奇怪问题grep -v。请允许我解释一下:

要显示连接,我使用who

$ who
harry    pts/0        2016-12-08 20:41 (192.168.0.1)
james    pts/1        2016-12-08 19:28 (192.168.0.1)
timothy  pts/2        2016-12-08 02:44 (192.168.0.1)

tty我的终端当前是pts/0

$ tty
/dev/pts/0
$ tty | cut -f3-4 -d'/'
pts/0

我尝试使用排除我自己的连接grep -v $(tty | cut -f3-4 -d'/')。在没有我的连接的情况下,该命令的预期输出应该是who。然而,输出是最出乎意料的:

$ who | grep -v $(tty | cut -f3-4 -d'/')
grep: a: No such file or directory
grep: tty: No such file or directory

我将其括$(...)在引号中,这似乎解决了“没有这样的文件或目录”问题。然而,即使我的 tty ( pts/0) 应该被排除,我的连接仍然被打印:

$ who | grep -v "$(tty | cut -f3-4 -d'/')"
harry    pts/0        2016-12-08 20:41 (192.168.0.1)
james    pts/1        2016-12-08 19:28 (192.168.0.1)
timothy  pts/2        2016-12-08 02:44 (192.168.0.1)

到目前为止,我完全不知道为什么grep查询出现故障。

答案1

从 tty 信息页面。

'tty' 打印连接到其标准输入的终端的文件名。如果标准输入不是终端,它会打印“not a tty”。

问题是在你的例子中 tty 的标准输入是一个管道,而不是你的终端。

从这个例子就可以看出。

$ tty
/dev/pts/29
$ echo | tty 
not a tty

要解决这个问题,你可以做这样的事情。

who | grep -wv "$(ps ax | awk "\$1 == $$ {print \$2}" )"

有一种更快/更有效的方法,但它需要两个命令。

t=$(tty)
who|grep -wv "${t:5}"

答案2

扎卡里已经解释了问题的根源。

虽然你可以解决它

tty=$(tty)
tty_without_dev=${tty#/dev/}
who | grep -v "$tty_without_dev"

这是错误的,例如如果 tty 是pts/1,您最终会排除所有包含 的行pts/10。有些grep实现可以-w选择进行单词搜索

who | grep -vw pts/1

不会匹配 on,pts/10因为pts/1in There 后面没有非单词字符。

或者您可以使用awk过滤第二个字段的确切值,例如:

who | awk -v "tty=$tty_without_dev" '$2 != tty'

如果你想用一个命令来完成它:

{ who | awk -v "tty=$(tty<&3)" '$2 != substr(tty,6)'; } 3<&0

原始标准输入被复制到文件描述符 3 上并为tty命令恢复。

相关内容