Why is this `grep -v` not functioning as expected

command linegreptty

I have a strange issue related to grep -v queries. Allow me to explain:

To display connections I use 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)

The current tty of my terminal is pts/0

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

I attempt to exclude my own connection using grep -v $(tty | cut -f3-4 -d'/'). The expected output of this command should be who, without my connection. However, the output is most unexpected:

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

I enclose the $(...) in quotes and that seems to fix the "No such file or directory" issue. However, my connection is still printed even though my tty (pts/0) should've been excluded:

$ 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)

As of this point, I have absolutely no idea why the grep query is malfunctioning.

Best Answer

Zachary has explained the source of the problem.

While you can work around it with

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

That would be wrong as for instance if that tty is pts/1, you would end up excluding all the lines containing pts/10. Some grep implementations have a -w option to do a word search

who | grep -vw pts/1

would not match on pts/10 because the pts/1 in there is not followed by a non-word character.

Or you could use awk to filter on the exact value of the second field like:

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

If you want to do it in one command:

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

The original stdin being duplicated onto file descriptor 3 and restored for the tty command.

Related Question