Project55.Run Background Jobs


Project 55. Run Background Jobs

"How do I regain control of the shell session after launching a command such as xterm, which opens its own window?"

This project takes advantage of Bash's job-control features, placing jobs in the background and swapping jobs in and out of the foreground. It gives some hints on how to manage background jobs, covering the commands fg, bg, and jobs. The Tcsh shell also supports job control and works in a more-or-less identical manner to Bash. This project is good for both Bash and Tcsh.

Start a Background Job

Most modern shells, including Bash and the Tcsh shell, implement job control. Essentially, what this means is that a command can be launched and then detached from Terminal. When a process becomes detached, the job is said to be a background job. A background job continues executing as though it were in the foreground, but with the exception that it will be suspended if it tries to read input from the keyboard.

Putting a job into the background releases its hold on Terminal, and the shell becomes the foreground job. This lets the current shell session continue, and you are free to issue more commands at the prompt while the background job continues to execute.

We would use a background job for a command that either takes a long time to complete and does not perform input or starts its own window, like the xterm command that comes as part of X11.

We'll illustrate background jobs by launching the top command. We tell top to report on running processes every 60 seconds (option -s60) and make 120 reports in total (option -l120). Such a command will take 2 hours to complete and does not require any input. Therefore, it's a good candidate to be backgrounded, with one caveat: It writes to the Terminal screen. This is not a problem, however, as we can redirect the command's output to a file for viewing later.

Type the following command line, noting the ampersand (&) character at the end of the line. Ampersand says to launch the command and run it in the background.

$ top -s60 -l120 > top.log & [1] 22885


You'll notice two things. First, we regain the prompt immediately. The top command is still executing, but in the background.

Second, the line [1] 22885 is displayed. [1] is the job number and can be passed to the fg command to bring the job back into the foreground (which we do later). 22885 is the PID (process ID) of the running task, as would be reported by the ps command.

$ ps axc | grep top 22885  p0  S      0:05.20 top


To confirm that top is running, check the size or contents of the output file top.log, or watch it growing by using the tail command.

$ tail -f top.log


To display a list of all background jobs, and their job numbers and PIDs, use the jobs command.

$ jobs -l [1]+ 22885 Running        top -s60 -l120 >top.log &


Note that each instance of Bash launches and controls its own list of jobs. Typing jobs -l in another Terminal window will not show the job with PID 22885. It might show another job number [1], but that will be a different job, which was launched by the other Bash session and will have a different PID.

Control Background Jobs

We can bring a background job into the foreground by using the fg command, passing the job number preceded by %. It's also possible to specify a PID by omitting the %.

$ fg %1 top -s60 -l120 >top.log


You'll see that Bash reflects the command we originally issued, but without the & to indicate that it's now a foreground job. You'll also notice the lack of a prompt.

Learn More

Project 39 explores the top and ps commands, and Project 6 covers redirection.


How would we send the job back into the background, given that we cannot type in Terminal? Simpleissue an interrupt, which is sent directly to the running job. Control-c tells the job to abort, and Control-z tells it to stop and suspend. Let's suspend the job.

^Z [1]+ Stopped              top -s60 -l120 >top.log


Tip

Press Control-y instead of Control-z to stop the foreground job only after it next tries to read input from Terminal.


The job is now stopped. It's not aborted, but suspended. We have the Terminal prompt back and can continue issuing commands.

To put job [1] into the background, simply type

$ bg %1 [1]+ top -s60 -l120 >top.log &


The job is now running in the background, as signified by the & symbol at the end of the echoed command line and by the fact that we are immediately presented with the Bash shell prompt.

Use the same technique of issuing Control-z and then bg if you launch a command you intended to run in the background but accidentally left off the trailing & (by typing xterm instead of xterm &, for example).

Note

It's perfectly OK to put a job that writes to the Terminal screen into the background. Its output will be interspersed with the regular output from your shell session, and eventually, it'll irritate you.


Supply Input to a Background Job

Scripts that require input usually aren't good candidates for background jobs, but once in a while it makes sense to run one in the background. On those rare occasions, you can use some redirection tricks to send a background job the input it needs.

Here's a simple script that reads a single line of input and echoes a response.

$ cat script #!/bin/bash read -p "Name: " name echo You claim to be $name.


Let's construct an input file to be read by the script.

$ echo "Adrian" > in


Now make the script executable, and run it, redirecting both input and output.

$ chmod +x script $ ./script <in >out & [1] 23014


To prove that it worked, examine file out.

$ cat out You claim to be Adrian. [1]+ Done              ./script <in >&out


Tip

Bash notifies you of any change in the status of a background job not immediately, but when the next prompt is issued, to prevent the notification from being lost among regular output. To change this so that notifications are displayed immediately, type

$ set -o notify


Specify option +o instead of -o to switch off notify.


You may also supply Terminal input to a background job that has stopped, awaiting input. In the following example, we launch the same script with no redirection. When the script requires input, it tries to read from Terminal but gets suspended.

$ ./script & [1] 23016 $ Name:


Let's assume that the script requires input at some time in the future, rather than immediately. When it eventually stops, we'll see this line printed before the prompt.

[1]+ Stopped          ./script


To find out why the job has stopped, type

$ jobs -l [1]+ 23016 Stopped (tty input)   ./script


The expression (tty input) confirms that the script requires input from Terminal. To enter input, we bring the job into the foreground and supply the necessary input.

$ fg %1 ./script Adrian  <<we type our input here You claim to be Adrian.


At this point, the script completes, but if it were to continue, you might want to put it back into the background, as we did in the top example above.

Tip

Kill a background process by giving its PID to the kill command.

$ kill -KILL 22885



Avoid Orphaned Jobs

If a shell exits while background jobs that it controls are still running, those jobs become orphaned. They can be stopped only by issuing a force-kill command like

$ kill -KILL <PID>


To prevent a shell script from creating orphaned jobs in the first place, use the wait command. Issuing wait prevents the shell from exiting until all background jobs under its control have completed.

To be more selective about which jobs we wait for, type

$ wait %n


to wait only for job number n. You may specify a PID instead of a job number if you omit the preceding %.




Mac OS X UNIX 101 Byte-Sized Projects
Mac OS X Unix 101 Byte-Sized Projects
ISBN: 0321374118
EAN: 2147483647
Year: 2003
Pages: 153
Authors: Adrian Mayo

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net