These two processes:

cat /dev/tty > /dev/null &
cat /dev/zero > /dev/null &

have to run in the background but i am having trouble bringing the second job to the foreground.

  • 2
    And whats the trouble you are having? – heemayl Nov 6 '16 at 3:36

Have you tried the fg command?

fg %2


While $! contains the process ID of the top-most process of the most recently started job in background, it's surprisingly hard to get its job ID in a fool-proof way.

It's not necessarily the greatest job id as job ids are reused. It's not necessarily the job you may refer to by %% or %+ (or that fg without argument would act upon) as suspended jobs take precedence (like in your case where the first job is likely to be suspended as it will try to read from the tty while not in foreground) or the most recently started job may have died already (in which case %+ would refer to the next job in the list).

So you'd need to run jobs first to know what the job number is for the job you want to fg (use use fg %thatnumber), or if there's no other job with zero in their name, run:

fg %\?zero

With zsh, you could use:

fg_most_recent() {
  local job=${(k)jobstates[(R)*:$!=*]}
  ((job)) && fg %$job

That is, get the key of the $jobstates associative array whose value matches the *:$!=* pattern ($jobstates look like running:+:20162=running:20163=running giving the status of all the processes in the job that zsh has started directly).


If this was two ordinary jobs, then a a plain fg would bring the second job into the foreground if that was the most recently suspended background job, or the most recently started background jobs (with no other jobs being suspended).

However, by the nature of the first job (reading from /dev/tty), it will get stopped as soon as it tries to read from the TTY. fg will thus put it back in the foreground.

The solution here is to either use %- or %2, given that there are no other jobs.

When a job is put into the background, either by starting the job with a trailing &, or by suspending a foreground job with Ctrl+Z and then giving the command bg, the job is given a "job ID" or "job spec". This job ID is usually denoted by %N where N is some decimal number.

You may use the job ID with several commands, such as wait, kill, fg and bg. The kill command, for example, may be used to send a signal to a background job using its job ID.

The fg command, by default, works on "the current job". The job ID of the current job is available as %+ or %%. The current job is the most recently started background job, or, if there are jobs suspended, the most recently suspended job.

To move an arbitrary background job into the foreground, use its job ID:

$ sleep 1000 &
[1] 37327
$ sleep 500 &
[2] 83532
$ jobs
[1]-  Running                 sleep 1000 &
[2]+  Running                 sleep 500 &
$ fg %1
sleep 1000

The + in the output of jobs denotes the "current job" (which is what would be switched to with a plain invocation of fg).

POSIX standard special job IDs:

  • %%, the current job.
  • %+, same as above.
  • %-, the previous job.
  • %N, job number N.
  • %string, the job whose command starts with string.
  • %?string, the job whose command contains string.
  • Note that the OP's first job being cat /dev/tty > /dev/null &, it will likely be suspended (by a SIGTTIN), so fg will resume that one instead of the second one. – Stéphane Chazelas Sep 21 '17 at 10:31
  • It's not stopped as soon as there is input on the tty, but as soon as it attempts to read from that tty (regardless of whether there's anything to read or not), so basically very shortly after it starts. – Stéphane Chazelas Sep 21 '17 at 11:29

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.