[comp.unix.questions] exit value

stadt@cs.utwente.nl (Richard van de Stadt) (11/12/90)

 
How do I get the return value of a shell script or program that was 
started (from a shell script) in the background?

--
R.R. van de Stadt (Richard)
Email: stadt@cs.utwente.nl

weimer@ssd.kodak.com (Gary Weimer) (11/14/90)

In article <1990Nov12.110248@cs.utwente.nl> stadt@cs.utwente.nl (Richard van de Stadt) writes:
>
> 
>How do I get the return value of a shell script or program that was 
>started (from a shell script) in the background?

First the example:

------------------------- CUT HERE ----------------------
#!/bin/csh -fb        #should also work with /bin/sh

rm not_a_real_file_to_get_error  >& /dev/null  # redirection necessary for
                                               # background processes
#this must be the very next statement
echo "status of rm was $status"  > /dev/tty    # could be redirected to
                                               # any file
------------------------- CUT HERE ----------------------

rm is just the command I chose (sp?), could be any program or script.

redirection necessary because background processes die if they try to
    access stdin or stdout.

$status is the important thing here. It contains the return value (exit
    status) of the last command executed.

you didn't specify how you wanted to "get" this value. Redirecting the
    echo to /dev/tty will print it to the console. Usually $status is
    used (at least I used it..) in a conditional statement (if, switch,
    etc.)

Hope this answers your (vague) question.

Gary Weimer

dberg@informix.com (David I. Berg) (11/14/90)

>In article <1990Nov12.110248@cs.utwente.nl> stadt@cs.utwente.nl (Richard van de Stadt) writes:
>>
>> 
>>How do I get the return value of a shell script or program that was 
>>started (from a shell script) in the background?
>
>#!/bin/csh -fb        #should also work with /bin/sh
>
>rm not_a_real_file_to_get_error  >& /dev/null  # redirection necessary for
>                                               # background processes
>#this must be the very next statement
>echo "status of rm was $status"  > /dev/tty    # could be redirected to
>                                               # any file

There are two possibilities here; one, you merely want to retrieve the
exit status of a spawned processes, or two, you want to return a value
generated by the spawned process, or both)

The above illustrated example does the former, assuming the spawned process 
exits with a status (eg. exit n, where n is the status value). The following 
example does both:

In the foreground script:
#
set answer = `create_answer`
if ($status > 0) then
	echo "Message about create_answer if status > 0"
	exit
end if
echo $answer

In the script create answer:
#
set xyz = some value or algorithm
set exitcode = some value to indicate success or failure (or anything else)
			   of this script. (0 usually means normal execution; > 0 otherwise)
echo $xyz
exit $exitcode

stadt@cs.utwente.nl (Richard van de Stadt) (11/14/90)

With this posting I want to explain with an example why I want to know
the exit value of a process that was started in background. From reactions
of some of you (thank you very much) I understand that the question was a
bit vague.

First of all I'm not a newcomer to UNIX (know it since 1983). 
I didn't ask how to get an exit value of a process, because I already 
know that's in $?. I also know that the process id of the last process
started in background is in $!.

When I worked at Philips Telecomunication and Data Systems, one of my
tasks was system management of some Philips P9000 computers.

For a 'normal' user it was rather complicated to format a floppy disk,
so I wanted to write a shell script to automate the various actions.

In order to get a floppy formatted the following had to be done:

For floppies that were previously formatted it was straightforward:
One had to insert a floppy disk and then type the commands
'attent /dev/dk1' to let the system get the name of the floppy,
'dvstat /dev/dk1' to see what the name of the floppy was,
'dkformat /vol/<name_of_floppy>' to start the format process.
(Once tape and disknames are known to the system, they are called volumes, 
 and their names used as references). 

So all commands could be started after each other in foreground. From the
output of dkformat one could see if the process had ended successful. Also
$? contained a value not equal to zero if something went wrong.

The trouble comes when you want to format a new ('maiden') floppy.

After inserting a new floppy, the format command had to be entered first,
since 'attent /dev/dk1' does not work for floppies that have no name yet:
'dkformat -m /vol/<new_name>' (m for maiden).
The format command then waits for the 'attent /dev/dk1' command to be entered,
after which the format process is really starting.

If you have only one terminal, where only one command shell can be active, 
you have to start dkformat in the background, to be able to enter 
'attent /dev/dk1'.

If you build a script around this you want to know if the process has
finished correctly. Started by hand, one could see if the format process
had ended correctly by looking at the output messages given. 

I wanted to write a script that tells a user to insert a floppy, press
return after doing so. Then starting up the format process (in background)
and exit, so the user can go on doing other things. After the format process
is ready a message is shown on the screen whether the floppy has been 
formatted successfully or unsuccessfully.

So what I wanted was something like:
-------------------------------------------------------------------------
#! /bin/sh
#name of script: floppyformat

doit () {   # a function
attent /dev/dk1    #find out if -m option must be used (new floppy)
  case $? in
    0) # not a new floppy
       dkformat /vol/name_of_floppy >/dev/null 2>&1  #no output on screen
       exitval=$?
       break ;;
    *) # a new floppy
       dkformat -m /vol/new_name >/dev/null 2>&1 &   #no output on screen
       sleep 10 # be sure process is started
                # actually done by looping on pid
       attent /dev/dk1   # give what dkformat is waiting for
       wait     # wait for format process to have finished
       exitval='exit_value_of_last_process_started_in_background' ;;
  esac
case $exitval in
   0) echo "Floppy was formatted successfully" ;;
   *) echo "<beep>Format process failed. Try other floppy"
esac
}           # end of function
echo -n "Insert floppy and press return "
read return
doit & #start format process in background and exit immediately
------------------------------------------------------------------------

I went around the problem by redirecting the output of dkformat to a 
temporary file and later searching this file for some specific string
that indicated that the format process had been successful. 
The script above is not the original, since it's been a bit too long
to remember all the details. It's the idea what it't about.

Hope things are a bit clearer now

Richard

--
R.R. van de Stadt (Richard)
Email: stadt@cs.utwente.nl

casper@fwi.uva.nl (Casper H.S. Dik) (11/14/90)

stadt@cs.utwente.nl (Richard van de Stadt) writes:

>With this posting I want to explain with an example why I want to know
>the exit value of a process that was started in background. From reactions
>of some of you (thank you very much) I understand that the question was a
>bit vague.

>First of all I'm not a newcomer to UNIX (know it since 1983). 
>I didn't ask how to get an exit value of a process, because I already 
>know that's in $?. I also know that the process id of the last process
>started in background is in $!.

In that case you know enough:

     wait [ n ]     Wait for the background process whose process
                    ID  is  n  and report its termination status.
                    If n is omitted, all  the  shell's  currently
                    active  background  processes  are waited for
                    and the return code will be zero.

The solution would be:
	job &
	proc=$!
	rest ...
	wait $proc
	if [ $? = 1 ]; then ... job failed ... ; fi

Or in your script:
------------------------------------------------------------------------
#! /bin/sh
#name of script: floppyformat

doit () {   # a function
attent /dev/dk1    #find out if -m option must be used (new floppy)
  case $? in
    0) # not a new floppy
       dkformat /vol/name_of_floppy >/dev/null 2>&1  #no output on screen
       exitval=$?
       break ;;
    *) # a new floppy
       dkformat -m /vol/new_name >/dev/null 2>&1 &   #no output on screen
	proc=$!
       sleep 10 # be sure process is started
                # actually done by looping on pid
       attent /dev/dk1   # give what dkformat is waiting for
#      wait     # wait for format process to have finished
        wait $proc     # wait for format process to have finished
	
#      exitval='exit_value_of_last_process_started_in_background' ;;
	exitval="$?" ;;
  esac
case $exitval in
   0) echo "Floppy was formatted successfully" ;;
   *) echo "<beep>Format process failed. Try other floppy"
esac
}           # end of function
echo -n "Insert floppy and press return "
read return
doit & #start format process in background and exit immediately
------------------------------------------------------------------------
--
Casper H.S. Dik, casper@fwi.uva.nl,	NIC: !cd151

mark@hsi86.hsi.com (Mark Sicignano) (11/15/90)

In article <1990Nov14.100834@cs.utwente.nl> stadt@cs.utwente.nl (Richard van de Stadt) writes:
...
>       break ;;
>    *) # a new floppy
>       dkformat -m /vol/new_name >/dev/null 2>&1 &   #no output on screen
>       sleep 10 # be sure process is started
>                # actually done by looping on pid
>       attent /dev/dk1   # give what dkformat is waiting for
>       wait     # wait for format process to have finished
>       exitval='exit_value_of_last_process_started_in_background' ;;
>  esac
...

read the man page on sh(1)... particularly the "wait" command.
Wouldn't this work?

dkformat -m /vol/new_name > /dev/null 2>&1 &
sleep 10
attent /dev/dk1
wait $!
exitval=$?

wait will wait for a particular process id, if one is given,
and will return the exit status of the process id.  $! is the 
pid of the last command ran in the background.  

In other words, the wait will wait for your dkformat to exit
and will return the status, which you can get from $?.

You had all of the pieces to the puzzle yourself, just didn't
put them together right.  Have fun!

-mark
-- 
Mark Sicignano                                  ...!uunet!hsi!mark
3M Health Information Systems                   mark@hsi.com