3

Let's say I'm running a bash script run.sh in the background and then I modify run.sh. Is there anyway to look at the original content of run.sh script?

For example:

echo "echo a1; sleep 120; echo a2" > run.sh; bash run.sh& 
aPid=$!
echo "echo bbbbbb" > run.sh

I'm expecting something like cat {magic file/path} and it will print out

echo a1; sleep 120; echo a2

I'm poking around /proc/$aPid , but couldn't find anything.

Sungam
  • 1,684
  • 1
  • 21
  • 24

2 Answers2

2

First make sure that your ulimit is set to allow core files. Try

ulimit -c unlimited

Next, run your script

./run.sh

While your script is running, modify or delete the run.sh script file.

Do ps ax to find the process ID (PID) of the first run.sh script. You should see something like

19365 pts/5    S+     0:00 /bin/bash ./run.sh

Then do

kill -SIGSEGV 19365

You should see something like

Segmentation fault (core dumped)

in the terminal window from which you first ran run.sh.

Finally, do

strings core

on the core file. Somewhere in the strings you should see the text of your original run.sh file.

Credits: This answer was adapted from Retrieve plain text script from compiled bash script.

Community
  • 1
  • 1
Jonathan Ben-Avraham
  • 4,615
  • 2
  • 34
  • 37
  • Bash (somewhat oddly) rereads the script during execution, so it could just terminate or die if you remove the script file while it runs. – tripleee Apr 10 '13 at 19:44
  • @tripleee: Do you have a specific example? I removed several script files after they were running in bash interpreters and did not see what you mention. – Jonathan Ben-Avraham Apr 10 '13 at 19:47
  • 1
    @tripleee: There is something to what you are saying. See http://stackoverflow.com/questions/7834667/self-deleting-bash-script – Jonathan Ben-Avraham Apr 10 '13 at 19:50
  • So what I'm saying is that the evidence suggests that Bash probably only reads the next block before executing it, and thus you will not find the entire script loaded into core at any time, except for very trivial scripts. – tripleee Apr 10 '13 at 19:58
  • @tripleee: Looks to me that bash parses the entire script file first, printing any errors, then executes. Doing an edit, ``mv`` or ``rm`` has no effect on the script you see in the core dump. Can you provide a counter-example? – Jonathan Ben-Avraham Apr 10 '13 at 20:03
  • No, I'm extrapolating from the fact that editing a running script with Emacs often produces weird errors from the shell running the script. – tripleee Apr 10 '13 at 20:13
  • This works OK because the strings in coredump doesn't preserve the newline/format of the original file. Also, I picked @twalberg answer over this one because this one need to kill the running process. – Sungam Apr 11 '13 at 01:06
  • This one will still work even the run.sh has a background subshell like this `echo '(echo a; sleep 120; echo a)&' > run.sh` – Sungam Apr 11 '13 at 01:08
2

bash seems to try to put the script it is currently interpreting on file descriptor 255, at least on my system, without any active non-default constraints on file descriptor maximums, etc... That's probably not guaranteed, so you may have to play with it a bit, but given the PID of a running bash /some/script/sh process, you can look in /proc/<PID>/fd/ at the file descriptor links - 0, 1 and 2 are of course the predefined stdin/stdout/stderr ones, and there may be others depending on what your script does, but it shouldn't be too difficult to sift through the contents of that directory to figure out which file descriptor corresponds to your script file, which you can than cat or whatever (e.g. cat /proc/12345/fd/255) to see the original script.

twalberg
  • 59,951
  • 11
  • 89
  • 84
  • Wow, was not aware of that. See also [here](http://lkml.indiana.edu/hypermail/linux/kernel/9803.3/0249.html) and [here](http://lists.gnu.org/archive/html/bug-bash/2009-08/msg00021.html). Google reveals that ksh uses fd 10 for the same purpose (so they seem to be de facto fixed, but yes, don't rely on it. +1! – Adrian Frühwirth Apr 10 '13 at 20:44
  • Thanks @twalberg, this does what I want. However, it will not work if there is a background subshell `echo '(echo a; sleep 120; echo a)&' > run.sh` – Sungam Apr 11 '13 at 00:58