Wait up, bash!
December 8, 2005 11:01 PM Subscribe
UnixFilter: How can I force a shell or other execution environment to wait for a process to finish, instead of allowing normal behavior for apps which like to fork / go into the background?
The specific problem I'm having is that I am trying to do crazy local/remote editing with a MOO, a local textmode MOO client, and vim (don't worry if you have no idea what a MOO is, it's not terribly relevant to my main question). The MOO client downloads text to a temp file, launches an editor to edit the temp file, and then sends the temp file's edited contents back to the server once the editor terminates.
During this process, an executable is called; it launches another executable and then immediately exits, not paying any attention to the status of its child executable.
Unfortunately, this is very bad, because that second executable is the real editor, and thus the 'launch editor; edit file; quit editor; send edited file back to server' process is rather shortened to 'launch "editor"; immediately send the now UNEDITED file back to the server'.
So...what I need is a way to force the first process to "wait" for a return value from its child process, and this is something I haven't yet had to do, so I'm quite in the dark.
Apologies for any incoherence, it's 2am and I'm rather tired :)
The specific problem I'm having is that I am trying to do crazy local/remote editing with a MOO, a local textmode MOO client, and vim (don't worry if you have no idea what a MOO is, it's not terribly relevant to my main question). The MOO client downloads text to a temp file, launches an editor to edit the temp file, and then sends the temp file's edited contents back to the server once the editor terminates.
During this process, an executable is called; it launches another executable and then immediately exits, not paying any attention to the status of its child executable.
Unfortunately, this is very bad, because that second executable is the real editor, and thus the 'launch editor; edit file; quit editor; send edited file back to server' process is rather shortened to 'launch "editor"; immediately send the now UNEDITED file back to the server'.
So...what I need is a way to force the first process to "wait" for a return value from its child process, and this is something I haven't yet had to do, so I'm quite in the dark.
Apologies for any incoherence, it's 2am and I'm rather tired :)
What is the first executable? Do you have control over it? Why is it launching the editor in the background?
You can probably get around this by using the shell to launch these processes instead of launching them directly. Have the shell launch the editor, then call wait (the shell built-in) to wait for the editor to finish. Since the MOO is wait()ing on the shell process, it won't continue until the shell exits, which won't happen until the editor exits.
posted by Rhomboid at 11:48 PM on December 8, 2005
You can probably get around this by using the shell to launch these processes instead of launching them directly. Have the shell launch the editor, then call wait (the shell built-in) to wait for the editor to finish. Since the MOO is wait()ing on the shell process, it won't continue until the shell exits, which won't happen until the editor exits.
posted by Rhomboid at 11:48 PM on December 8, 2005
Not sure if this is a possibility in your situation, but you may want to consider writing your script in perl instead of a shell scripting language if you can. In perl, the "system" command will wait for the child process to finish. Perl is also going to be much easier to maintain if you ever extend your script. Whether or not perl is an option, of course, depends on your circumstances.
Otherwise, I think creeront and Rhomboid have the answer: man wait.
posted by Loudmax at 11:59 PM on December 8, 2005
Otherwise, I think creeront and Rhomboid have the answer: man wait.
posted by Loudmax at 11:59 PM on December 8, 2005
wait assumes you can get the pid which means either replacing the first process or grabbing the pid using "ps aux | grep name | cut ...". if i understood correctly.
alternative solutions might include looking at the locking on the file (fuser, lsof - not very standard, afaik). or checking when the file modification date changes (assuming you know when the process starts, and that there's a single "save").
posted by andrew cooke at 1:42 AM on December 9, 2005
alternative solutions might include looking at the locking on the file (fuser, lsof - not very standard, afaik). or checking when the file modification date changes (assuming you know when the process starts, and that there's a single "save").
posted by andrew cooke at 1:42 AM on December 9, 2005
You may want to look into using expect, which is ideal for interactive applications.
posted by gaby at 3:08 AM on December 9, 2005
posted by gaby at 3:08 AM on December 9, 2005
No it is not necessary to give a PID to wait. If you just call wait without arguments it will wait for all currently active child processes.
And even if you wanted to wait on a specific process, grepping the output of 'ps' is a terrible way to do it, when $! holds the pid of the last launched child. For example.
posted by Rhomboid at 4:44 AM on December 9, 2005
And even if you wanted to wait on a specific process, grepping the output of 'ps' is a terrible way to do it, when $! holds the pid of the last launched child. For example.
prog1 & prog1_pid=$!
prog2 &
prog3 &
wait $prog1_pid
posted by Rhomboid at 4:44 AM on December 9, 2005
thanks for the info, but the way i understood the question, there's an extra task in the middle. so you're not waiting for a chile, but the child of a child. and a quick experiment with cygwin bash (not really unix, i know) suggests that wait doesn't wait for a grandchild, and that $! isn't passed back either.
posted by andrew cooke at 5:13 AM on December 9, 2005
posted by andrew cooke at 5:13 AM on December 9, 2005
...which is exactly why I suggested launching "program1" (whatever that is) and the editor both from bash, so that it can wait until the editor actually exits before itself exiting.
I think without more details (what is this "program1", what does it do, why is it needed, etc) nobody can actually give a sensible answer to this question.
posted by Rhomboid at 6:20 AM on December 9, 2005
I think without more details (what is this "program1", what does it do, why is it needed, etc) nobody can actually give a sensible answer to this question.
posted by Rhomboid at 6:20 AM on December 9, 2005
Response by poster: Thanks for the replies thus far!
I figured I'd have to go into more detail, but didn't want to make the original post too big...it's rather convoluted :P
So, to start from the beginning: the MOO client is TinyFugue. I have some add-on scripts which give it the ability to use the 'MCP' protocol which enables local editing; the core command in these scripts is one which launches the local editor with the text-to-be-edited which is sent from the server.
The main problem is that the command used to launch the editor has to open it in another terminal or window somehow, because there's no easy way to coexist with TinyFugue's process in the current one.
The original command used by the script is to launch an xterm window; xterm, by default, exhibits the behavior I'm looking for, e.g. when you call 'xterm' your current shell waits for the xterm window to close before it continues.
My problem, of course, is that I'm a picky idiot, and I'm on a Mac, so I'd rather not have to run X11 and use icky xterm windows to do this whole thing, but instead use my native OSX terminal application (iTerm) which is worlds nicer than any X11 terminal could be.
So, I emulate the process of opening a new xterm by running an AppleScript to open a new terminal window (with vim) in iTerm, or by running gvim. Unfortunately, they both exhibit the same behavior--they launch (or otherwise communicate with) a graphical application and thus immediately return control to the calling shell. Which is where I came in in my original post.
'wait' doesn't seem to want to work, but I think that's due to all this convoluted business with GUI apps and whatnot...at any rate, I think I'm going to try Loudmax's suggestion and see if writing a script might do the trick.
Not necessarily because of the system() call (I use Python but I'm pretty sure their system calls are similar) but because I think if the script becomes the initial process, and I can force it to stay executing until the editor is finished (by checking pids or the status of the file to be edited, or whatnot) then that might do the trick. Guess we'll see.
Thanks again, and sorry for all this dumb crap--I tend to get mulish about really asinine stuff like this, it would've been much easier at this point to use a different client with built-in editor, or to just suck it up and use X11/xterms for my MOO business :)
posted by cyrusdogstar at 8:12 AM on December 9, 2005
I figured I'd have to go into more detail, but didn't want to make the original post too big...it's rather convoluted :P
So, to start from the beginning: the MOO client is TinyFugue. I have some add-on scripts which give it the ability to use the 'MCP' protocol which enables local editing; the core command in these scripts is one which launches the local editor with the text-to-be-edited which is sent from the server.
The main problem is that the command used to launch the editor has to open it in another terminal or window somehow, because there's no easy way to coexist with TinyFugue's process in the current one.
The original command used by the script is to launch an xterm window; xterm, by default, exhibits the behavior I'm looking for, e.g. when you call 'xterm' your current shell waits for the xterm window to close before it continues.
My problem, of course, is that I'm a picky idiot, and I'm on a Mac, so I'd rather not have to run X11 and use icky xterm windows to do this whole thing, but instead use my native OSX terminal application (iTerm) which is worlds nicer than any X11 terminal could be.
So, I emulate the process of opening a new xterm by running an AppleScript to open a new terminal window (with vim) in iTerm, or by running gvim. Unfortunately, they both exhibit the same behavior--they launch (or otherwise communicate with) a graphical application and thus immediately return control to the calling shell. Which is where I came in in my original post.
'wait' doesn't seem to want to work, but I think that's due to all this convoluted business with GUI apps and whatnot...at any rate, I think I'm going to try Loudmax's suggestion and see if writing a script might do the trick.
Not necessarily because of the system() call (I use Python but I'm pretty sure their system calls are similar) but because I think if the script becomes the initial process, and I can force it to stay executing until the editor is finished (by checking pids or the status of the file to be edited, or whatnot) then that might do the trick. Guess we'll see.
Thanks again, and sorry for all this dumb crap--I tend to get mulish about really asinine stuff like this, it would've been much easier at this point to use a different client with built-in editor, or to just suck it up and use X11/xterms for my MOO business :)
posted by cyrusdogstar at 8:12 AM on December 9, 2005
Best answer: fghack is a program that is part of djb's daemontools that will prevent a program from losing itself in the background.
posted by jimw at 8:43 AM on December 9, 2005
posted by jimw at 8:43 AM on December 9, 2005
Response by poster: jimw: that works perfectly, at least for gvim so far--thank you!!
sfenders: I'd ran across that already, but it didn't appear to do what I wanted, even using that flag, calls to gvim still exited right away. I think that is probably because it's not "real" gvim as you'd find in X11, but simply a call to an OS X .app bundle. I still get a gvim window but I do not believe it's the same call process, so the '-f' flag ends up not helping any.
posted by cyrusdogstar at 9:02 AM on December 9, 2005
sfenders: I'd ran across that already, but it didn't appear to do what I wanted, even using that flag, calls to gvim still exited right away. I think that is probably because it's not "real" gvim as you'd find in X11, but simply a call to an OS X .app bundle. I still get a gvim window but I do not believe it's the same call process, so the '-f' flag ends up not helping any.
posted by cyrusdogstar at 9:02 AM on December 9, 2005
For lesser editors that don't have a command-line option for this like gvim does, the easy way is to use "strace -f". That's on linux, but there's an equivalent on most UNIX-like systems.
posted by sfenders at 9:04 AM on December 9, 2005
posted by sfenders at 9:04 AM on December 9, 2005
Well, you could also try "bash -c 'gvim -f ...'". If that doesn't work, something really weird is going on.
posted by sfenders at 9:07 AM on December 9, 2005
posted by sfenders at 9:07 AM on December 9, 2005
Response by poster: sfenders: actually, on closer examination of the homepage for the gvim OS X port, it's a known issue that the -f flag doesn't always work on that build for some reason...that's probably it.
Still, the fghack deal seems to work, so now I just have to get gvim configured to be as close to my "normal" vim as possible =)
posted by cyrusdogstar at 10:25 AM on December 9, 2005
Still, the fghack deal seems to work, so now I just have to get gvim configured to be as close to my "normal" vim as possible =)
posted by cyrusdogstar at 10:25 AM on December 9, 2005
This thread is closed to new comments.
if((result = fork()) == -1) /*bad fork*/
{
fprintf(stderr, "Error: %s", strerror(errno));
continue;
}
else if(result == 0) /*child process*/
{
if(execvp(list[i]->name, list[i]->argv)) /*something bad happened calling exec*/
cleanupProcess();
}
else /*parent process*/
{
list[i]->pid = result;
/*wait for each process to finish*/
wait(&status);
}
The key lines here are checking to see if result ==0 (chlid process), then you want to make an exec call. Otherwise, you'll want to wait.
Here's the man page for wait:
posted by creeront at 11:13 PM on December 8, 2005