41

In the second method proposed by this page, one gets the tty in which bash is being run with the command:

ps ax | grep $$ | awk '{ print $2 }'

I though to myself that surely this is a bit lazy, listing all running processes only to extract one of them. Would it not be more efficient (I am also asking if this would introduce unwanted effects) to do:

ps -p $$ | tail -n 1 | awk '{ print $2 }'

FYI, I came across this issue because sometimes the first command would actually yield two (or more) lines. This would happen randomly, when there would be another process running with a PID that contains $$ as a substring. In the second approach, I am avoiding such cases by requesting the PID that I know I want.

Jonathan H
  • 2,303
  • 3
  • 20
  • 27
  • 9
    well most efficient of all would be run the `tty` command within your bash session. If you insist on using `ps` - `ps -p $$ -o tty=` – iruvar Mar 16 '16 at 18:50
  • @iruvar `tty` will output "not a tty" if the shell runs in background unlike the `ps` way. – jarno Jan 10 '20 at 17:54

6 Answers6

66

Simply by typing tty:

$ tty 
/dev/pts/20

Too simple and obvious to be true :)

Edit: The first one returns you also the pty of the process running grep as you can notice:

$ ps ax | grep $$
28295 pts/20   Ss     0:00 /bin/bash
29786 pts/20   S+     0:00 grep --color=auto 28295

therefore you would need to filter out the grep to get only one result, which is getting ugly:

ps ax | grep $$ | grep -v grep | awk '{ print $2 }'

or using

ps ax | grep "^$$" | awk '{ print $2 }'

(a more sane variant)

Jakuje
  • 20,974
  • 7
  • 51
  • 70
  • Yes, that is the first suggested solution indeed (actually it is `tty | sed -e "s:/dev/::"`). But I think the second suggested solution on that page is not only inefficient, but also wrong! I'll use `tty` and stop complaining though. :) – Jonathan H Mar 16 '16 at 18:54
  • The first one returns you also the `pty` of the process running `grep` as you can notice. – Jakuje Mar 16 '16 at 19:00
  • 2
    You don't need `grep` if you're using `awk`. e.g. `ps ax | awk "/^$$/ {print \$2}"` - note the use of double-quotes rather than single-quotes and the escaped `\$2`. But, as you say, using `tty` is the correct solution. – cas Mar 17 '16 at 01:19
  • 2
    Grepping like that can result in false matches, e.g. if your PID is 10 and there's also a PID 103. Use `awk -vpid=$$ '$1 == pid {print $2}'` – Barmar Mar 23 '16 at 17:32
  • I am just noting here that spawning `tty` in node.js does not work at all, while `ps` and friends work just fine. – Steven Lu May 22 '18 at 23:15
  • `$(tty)` is helpful in place of `$TTY` when you're running a shell script (because the latter is not set). – Sridhar Sarnobat Aug 28 '19 at 22:48
18

If you want to be more efficient, then yes, you're right that ps can filter to just the process in question (and it will be more correct, not running the risk of picking up commands that happen to have your process number in their names). Not only that, but it can be told not to generate the header (option h), eliminating the tail process, and to display only the TTY field (option o tty), eliminating the awk process.

So here's your reduced command:

ps hotty $$
Toby Speight
  • 8,460
  • 3
  • 26
  • 50
11

Other ways to do it:

readlink /dev/fd/0     #or 1 or 2 
readlink /proc/self/fd/0 #or 1 or 2
readlink -f /dev/stdin #or stdout or stderr; f to resolve recursively
#etc.

( If you're in a shell whose stdin, stdout and stderr are not connected to its controlling terminal, you can get a filedescriptor to the controlling terminal by opening /dev/tty:

( { readlink /dev/fd/0; } </dev/tty; ) </dev/null  >output 2>&1

)

Or with ps:

ps h -o tty -p $$ #no header (h); print tty column; for pid $$
Petr Skocik
  • 28,176
  • 14
  • 81
  • 141
  • 2
    (1) I’m glad you realized that the current/controlling tty of a process is not associated with any file descriptor, and is not guaranteed to be open on any fd.  But, did you try the command that you offer as a workaround for that contingency?  When I try it, all I get is `/dev/tty`, and not the controlling tty (as reported by `ps`). (2) I believe that `{ readlink /dev/fd/0; } < /dev/tty` is (and will always be) equivalent to `readlink /dev/fd/0 < /dev/tty` — do you believe otherwise?  If so, can you justify it? (3) The second semicolon in your command (the one after `/dev/tty`) is unnecessary. – Scott - Слава Україні Mar 17 '16 at 03:47
9

Just for completeness, while the other ps commands mentioned work on Linux, ps -p $$ -o tty= (as mentioned by @1_CR) is the most portable to all modern Unix systems, since it uses only options defined in the Unix Standard.

Random832
  • 10,476
  • 1
  • 34
  • 40
3

In the interactive shell, one could use w command for that. In the example bellow , w reports itself being run by specific user, and of course it shows TTY where that command is being ran.

$ w
 11:20:08 up 5 min,  3 users,  load average: 0.34, 0.39, 0.20
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
xieerqi  :0       :0               11:15   ?xdm?   1:47   0.34s init --user
xieerqi  pts/0    :0               11:18   23.00s  0.05s  0.05s /bin/mksh
xieerqi  pts/10   :0               11:20    0.00s  0.03s  0.01s w
Sergiy Kolodyazhnyy
  • 16,187
  • 11
  • 53
  • 104
0

This method (slightly different than what has been posted so far) worked best for me

echo "/dev/$(ps -p $$ -o tty=)"

To use it for a parent process e.g., substitute $$ with $PPID.

chtenb
  • 163
  • 8