Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

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. It is greatly appreciated if someone could shed some light on this strange issue.

share|improve this question
3  
How about using set -x first... Then run your command and see what are you actually trying to grep... – don_crissti 13 hours ago
    
@don_crissti ah, I see; it's telling me I'm actually greping "not a tty". How would you suggest I get around this? – perhapsmaybeharry 13 hours ago
    
use a variable: tldp.org/HOWTO/Bash-Prompt-HOWTO/x721.html – don_crissti 13 hours ago
up vote 15 down vote accepted

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.

share|improve this answer
2  
+1 for figuring out how to do it in one command and pointing out that mistake. – Zachary Brady 12 hours ago
    
One more one liner: tty | cut -f3-4 -d'/' | xargs -I % sh -c "who | grep -v %" – axxis 5 hours ago

From the tty info page.

'tty' prints the file name of the terminal connected to its standard input. It prints `not a tty' if standard input is not a terminal.

The problem is that in your example tty's stdin is a pipe, not your terminal.

You can see from this example.

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

To work around that you could do something like this.

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

There is a faster/more efficient way however it requires two commands.

t=$(tty)
who|grep -wv "${t:5}"
share|improve this answer
    
On Linux, why does this produce nothing? (who | grep -v "$(ps ax | grep "^$$" | awk '{ print $2 }')" – Christopher 12 hours ago
    
@Christopher are you the only one logged into your computer? – Zachary Brady 12 hours ago
    
No, I have many users logged in. One command line: t=$(tty) who|grep -v "${t:5}" – Christopher 12 hours ago
    
I guess it's this portion that produces nothing: ps ax | grep "^$$" – Christopher 12 hours ago
2  
ps ax | grep "^ *$$" could false-match e.g. your shell is 123 and 1234 exists; ps ax -otty= $$ is more robust and only one process. But I prefer your ${t:5} or Stephane's ${t#/dev/} (or substr(t,6)) – dave_thompson_085 8 hours ago

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.