(OSX 10.7) An application we use let us assign scripts to be called when certain activities occur within the application. I have assigned a bash script and it's being called, the problem is that what I need to do is to execute a few commands, wait 30 seconds, and then execute some more commands. If I have my bash script do a "sleep 30" the entire application freezes for that 30 seconds while waiting for my script to finish.
I tried putting the 30 second wait (and the second set of commands) into a separate script and calling "./secondScript &" but the application still sits there for 30 seconds doing nothing. I assume the application is waiting for the script and all child processes to terminate.
I've tried these variations for calling the second script from within the main script, they all have the same problem:
I do not have the ability to change the application and tell it to launch my script and not wait for it to complete.
How can I launch a process (I would prefer the process to be in a scripting language) such that the new process is not a child of the current process?
Thanks, Chris
p.s. I tried the "disown" command and it didn't help either. My main script looks like this:
[initial commands] echo Launching second script ./secondScript & echo Looking for jobs jobs echo Sleeping for 1 second sleep 1 echo Calling disown disown echo Looking again for jobs jobs echo Main script complete
and what I get for output is this:
Launching second script Looking for jobs [1]+ Running ./secondScript & Sleeping for 1 second Calling disown Looking again for jobs Main script complete
and at this point the calling application sits there for 45 seconds, waiting for secondScript to finish.
p.p.s
If, at the top of the main script, I execute "ps" the only thing it returns is the process ID of the interactive bash session I have open in a separate terminal window.
The value of $SHELL is /bin/bash
If I execute "ps -p $$" it correctly tells me
PID TTY TIME CMD 26884 ?? 0:00.00 mainScript
If I execute "lsof -p $$" it gives me all kinds of results (I didn't paste all the columns here assuming they aren't relevant):
FD TYPE NAME cwd DIR /private/tmp/blahblahblah txt REG /bin/bash txt REG /usr/lib/dyld txt REG /private/var/db/dyld/dyld_shared_cache_x86_64 0 PIPE 1 PIPE -> 0xffff8041ea2d10 2 PIPE -> 0xffff 8017d21cb 3r DIR /private/tmp/blahblah 4r REG /Volumes/DATA/blahblah 255r REG /Volumes/DATA/blahblah
Yes. The process creates a child, which then creates another child, becoming it's parent. You can differentiate child and parent by using fork return number.
A process can only have a single parent process, which is always obtainable by calling getppid . The child is a copy of the parent, it gets a copy of the parent's data space, heap and stack. They do not share these portions of memory!
A child process may also be known as subprocess or a subtask. A child process is created as a copy of its parent process. The child process inherits most of its attributes. If a child process has no parent process, then the child process is created directly by the kernel.
Also, Linux uses copy on write when creating child processes. This means that the parent and child will share the parent address space until one of them does a write, at which point the memory will be physically copied to the child. This eliminates unneeded copies when exec ing a new process.
The typical way of doing this in Unix is to double fork. In bash, you can do this with
( sleep 30 & )
(..)
creates a child process, and &
creates a grandchild process. When the child process dies, the grandchild process is inherited by init.
If this doesn't work, then your application is not waiting for child processes.
Other things it may be waiting for include the session and open lock files:
To create a new session, Linux has a setsid
. On OS X, you might be able to do it through script
, which incidentally also creates a new session:
# Linux: setsid sleep 30 # OS X: nohup script -q -c 'sleep 30' /dev/null &
To find a list of inherited file descriptors, you can use lsof -p yourpid
, which will output something like:
sleep 22479 user 0u CHR 136,32 0t0 35 /dev/pts/32 sleep 22479 user 1u CHR 136,32 0t0 35 /dev/pts/32 sleep 22479 user 2u CHR 136,32 0t0 35 /dev/pts/32 sleep 22479 user 5w REG 252,0 0 1048806 /tmp/lockfile
In this case, in addition to the standard FDs 0, 1 and 2, you also have a fd 5 open with a lock file that the parent can be waiting for.
To close fd 5, you can use exec 5>&-
. If you think the lock file might be stdin/stdout/stderr themselves, you can use nohup
to redirect them to something else.
Another way is to abandon the child
#!/bin/bash yourprocess & disown
As far as I understand, the application replaces the normal bash shell because it is still waiting for a process to finish even if init
should have taken care of this child process. It could be that the "application" intercepts the orphan handling which is normally done by init
.
In that case, only a parallel process with some IPC can offer a solution (see my other answer)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With