88

Most shells provide functions like && and ; to chain the execution of commands in certain ways. But what if a command is already running, can I still somehow add another command to be executed depending on the result of the first one?

Say I ran

$ /bin/myprog
some output...

but I really wanted /bin/myprog && /usr/bin/mycleanup. I can't kill myprog and restart everything because too much time would be lost. I can Ctrl+Z it and fg/bg if necessary. Does this allow me to chain in another command?

I'm mostly interested in bash, but answers for all common shells are welcome!

4 Answers 4

118

You should be able to do this in the same shell you're in with the wait command:

$ sleep 30 &
[1] 17440

$ wait 17440 && echo hi

...30 seconds later...
[1]+  Done                    sleep 30
hi

excerpt from Bash man page

wait [n ...]
     Wait for each specified process and return its termination status. Each n 
     may be a process ID or a job specification; if a job spec is given,  all 
     processes  in that job's pipeline are waited for.  If n is not given, all 
     currently active child processes are waited for, and the return status is 
     zero.  If n specifies a non-existent process or job, the return status is 
     127.  Otherwise, the return status is the exit status of the last process 
     or job waited for.
5
  • Waiting on the command should do the job.
    – BillThor
    Nov 13, 2013 at 0:41
  • There are a number of short forms for entering the PID of the backgrounded process such as %, %1 and $!. It is important to supply the PID or the second command will always run.
    – BillThor
    Nov 13, 2013 at 1:06
  • @BillThor - are you just qualifying the answer or telling me this?
    – slm
    Nov 13, 2013 at 1:07
  • I am qualifying the answer. A plain wait will fail to provide the desired result. It is common to use the short forms as they are less prone to typos.
    – BillThor
    Nov 13, 2013 at 1:18
  • 2
    Let me be the first to congratulate you on your shiny new badge :)
    – terdon
    Jul 2, 2014 at 18:00
63

fg returns with the exit code from the program it resumes. You can therefore suspend your program with ^Z and then use fg && ... to resume it.

$ /bin/myprog
some output...
^Z
[1]+ Stopped              /bin/myprog
$ fg && /usr/bin/mycleanup
2
  • if you suspend again before it ends and do the same thing with a different command, does the initial chaining of mycleanup get replaced?
    – Burhan Ali
    Dec 8, 2013 at 10:44
  • 3
    @BurhanAli Suspending myprog for the second time causes fg to terminate with the exit code 20 -- which is non-zero, so the chained mycleanup command isn't executed.
    – n.st
    Jan 4, 2014 at 4:00
1

Not sure if what you're asking for is possible, but if you still have the shell you started the program from, you can always check $? for the last process' exit status:

$ /bin/myprog
some output...
$ if [ $? -ne 0 ];then echo "non-zero exit status";else echo "0 exit status";fi
3
  • 1
    This will work, but he'll have to run this manually afterwards, he want to run this automatically when the command finishes.
    – slm
    Nov 11, 2013 at 19:16
  • @slm Agreed. I don't have a solution for that exact problem.
    – Joseph R.
    Nov 11, 2013 at 19:18
  • 3
    Check out wait command in Bash.
    – slm
    Nov 11, 2013 at 19:31
1

If the job is in the foreground, either of these commands would have the same behavior as you expect.

[ $? -eq 0 ] && prog2
(( $? )) || prog2

NOTE: $? will contain the return status of the running program when it exits.

This is explicitly stating what the shell would do if you had originally entered the command.

prog1 && prog2

If the first command is not reading from stdin and is running in the foreground, the new command can be entered while the first command is running. The shell will read and execute it when the first command executes. If the command will run in the background, it is unlikely it is reading stdin.

EDIT: Putting the job in the background and using the WAIT command could also be used. This must be done with care if other jobs have also been run in the background. A job specification is required to have the WAIT command return the status of the job waited on.

11
  • This will work, but he'll have to run this manually afterwards, he want to run this automatically when the command finishes.
    – slm
    Nov 11, 2013 at 19:17
  • 4
    @slm As long as the command is not reading stdin, the new command can be entered while the first command is running. The shell will read it as soon as the first command is done.
    – BillThor
    Nov 11, 2013 at 19:19
  • If he does anything in the shell after it's been backgrounded it's likely hosed. At least according to the prelim. testing I've been doing thus far!
    – slm
    Nov 11, 2013 at 19:22
  • 2
    @BillThor I think you should add that comment to your answer.
    – Joseph R.
    Nov 11, 2013 at 19:25
  • 2
    Yes, using wait isn't ideal either. The advantage, IMO, is that it gives us a clearer API that we're dealing with. Typing more commands on the command line after something is running seemed a little hacky to me. wait still suffers from not getting a direct link to the running PID, wrt the return status. This seems to be an issue more w/ how Bash implements things though: stackoverflow.com/questions/356100/…. So this might be as good as it gets.
    – slm
    Nov 11, 2013 at 19:43

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .