4

If I run this command in a script it doesn't produce output except header from the ps:

 # Taken from Advanced Bash Usage on youtube:

 echo "$(echo "$(echo "$(echo "$(ps wwf -s $$)")")")"

This is the output:

$./testing.bash
  PID TTY      STAT   TIME COMMAND

but here it is run in a terminal which produces the expected output:

$echo "$(echo "$(echo "$(echo "$(ps wwf -s $$)")")")"
  PID TTY      STAT   TIME COMMAND
18289 pts/4    Ss+    0:00 /bin/bash
17917 pts/4    S+     0:00  \_ /bin/bash
17918 pts/4    S+     0:00      \_ /bin/bash
17919 pts/4    S+     0:00          \_ /bin/bash
17920 pts/4    S+     0:00              \_ /bin/bash
17921 pts/4    R+     0:00                  \_ ps wwf -s 18289

QUESTION:

Can you explain the difference and show me the right way to do this?

I've tried a lot of things and searched google for 4 hours, if you need I can list what I tried but I don't think that's relevant here.

$echo $SHELL
/bin/bash

and:

$head -1 testing.bash 
#!/bin/bash
Gilles 'SO- stop being evil'
  • 807,993
  • 194
  • 1,674
  • 2,175
somethingSomething
  • 5,721
  • 18
  • 58
  • 98
  • 2
    See also: https://unix.stackexchange.com/questions/18166/what-are-session-leaders-in-ps – muru Jun 29 '19 at 13:11

1 Answers1

10

ps' -s sessionid option is to select processes based on their session id.

You can use ps -j to see the session id of processes. Sessions along with process groups are generally used for shell job control (hence the -j).

Your terminal emulator creates a new session with the process that it then reuses to execute your preferred shell. So, in a terminal, the session id will generally be the same as the pid of that shell.

So, if you run ps -j -s "$$" in that shell, you'll get the processes in the session because "$$" happens to be the same as the session id.

If you run that command in any other shell (like the shell that is executed in a child process to interpret your testing script), any shell that is not a session leader, you'll get nothing because there's no session with an id that corresponds to the pid of that shell.

$ ps -j -s "$$"
  PID  PGID   SID TTY          TIME CMD
 7239  7239  7239 pts/7    00:00:00 zsh
21002 21002  7239 pts/7    00:00:00 ps

$$ is 7239, the session leader. So that ps -j -s 7239 gives me all the processes in that session.

$ sh -xc 'ps -j -s "$$"; ps -j -p "$$"'
+ ps -j -s 21044
  PID  PGID   SID TTY          TIME CMD
+ ps -j -p 21044
  PID  PGID   SID TTY          TIME CMD
21044 21044  7239 pts/7    00:00:00 sh

The first ps command returns nothing because, as the second ps shows, there's no session with id 21044 as the process of id 21044 is not a session leader. The session leader is still 7239, the shell started by the terminal emulator.

$ sh -xc 'ps -j -s "$(($(ps -o sid= -p "$$")))"'
+ ps -o sid= -p 21215
+ ps -j -s 7239
  PID  PGID   SID TTY          TIME CMD
 7239  7239  7239 pts/7    00:00:00 zsh
21215 21215  7239 pts/7    00:00:00 sh
21217 21215  7239 pts/7    00:00:00 ps

Now, we see all the processes in the session. We used ps -o sid= -p "$$" to get the id of the session that $$ belongs to.

Stéphane Chazelas
  • 522,931
  • 91
  • 1,010
  • 1,501
  • So would one possible "right way to do this" be to execute the script with `setsid` e.g. `setsid -w ./testing.bash`? – steeldriver Jun 29 '19 at 13:28
  • @steeldriver, yes that would create a new session with the shell interpreting the script being the session leader. You could also use `script` or `xterm` or any other terminal emulator or run it over ssh that would also create a new session. Or you could use `-G` instead of `-s` to get the processes in the job instead of the session (which would work as long as $$ is the process group leader which would generally be the case if the script is started on its one by an interactive shell) – Stéphane Chazelas Jun 29 '19 at 13:32