Bash – How to See the Exact Command Line Being Executed

bashdebuggingprocess

I have a long running bash instance (inside a screen session) that is executing a complex set of commands inside a loop (with each loop doing pipes, redirects, etc).

The long command line was written inside the terminal – it's not inside any script. Now, I know the bash process ID, and I have root access – how can I see the exact command line being executed inside that bash?

Example

bash$ echo $$
1234
bash$ while true ; do \
    someThing | somethingElse 2>/foo/bar | \
    yetAnother ; sleep 600 ; done

And in another shell instance, I want to see the command line executed inside PID 1234:

bash$ echo $$
5678
bash$ su -
sh# cd /proc/1234
sh# # Do something here that will display the string  \
   'while true ; do someThing | somethingElse 2>/foo/bar | \
    yetAnother ; sleep 600 ; done'

Is this possible?

EDIT #1

Adding counter-examples for some answers I've got.

  1. About using the cmdline under /proc/PID: that doesn't work, at least not in my scenario. Here's a simple example:

    $ echo $$
    8909
    
    $ while true ; do echo 1 ; echo 2>/dev/null ; sleep 30 ; done
    

    In another shell:

    $ cat /proc/8909/cmdline
    bash
    
  2. Using ps -p PID --noheaders -o cmd is just as useless:

    $ ps -p 8909 --no-headers -o cmd
    bash
    
  3. ps -eaf is also not helpful:

    $ ps -eaf | grep 8909
    ttsiod    8909  8905  0 10:09 pts/0    00:00:00 bash
    ttsiod   30697  8909  0 10:22 pts/0    00:00:00 sleep 30
    ttsiod   31292 13928  0 10:23 pts/12   00:00:00 grep --color=auto 8909
    

    That is, there's no output of the ORIGINAL command line, which is what I'm looking for – i.e the while true ; do echo 1 ; echo 2>/dev/null ; sleep 30 ; done.

Best Answer

I knew I was grasping at straws, but UNIX never fails!

Here's how I managed it:

bash$ gdb --pid 8909
...
Loaded symbols for /lib/i386-linux-gnu/i686/cmov/libnss_files.so.2
0xb76e7424 in __kernel_vsyscall ()

Then at the (gdb) prompt I ran the command, call write_history("/tmp/foo") which will write this history to the file /tmp/foo.

(gdb) call write_history("/tmp/foo")
$1 = 0

I then detach from the process.

(gdb) detach
Detaching from program: /bin/bash, process 8909

And quit gdb.

(gdb) q

And sure enough...

bash$ tail -1 /tmp/foo
while true ; do echo 1 ; echo 2>/dev/null ; sleep 30 ; done

For easy future re-use, I wrote a bash script, automating the process.