[Bug 261200] Unable to pipe the output of jobs in sh

From: <bugzilla-noreply_at_freebsd.org>
Date: Tue, 18 Jan 2022 23:33:34 UTC

--- Comment #6 from Jilles Tjoelker <jilles@FreeBSD.org> ---
The reason that jobs cannot be piped is that an element of a pipeline (with
more than one element) is run in a subshell environment, and the subshell
environment has its own jobs. For example,

sh -c ':& { :& jobs; }|wc -l'

writes 1.

There are, however, some exceptions to this.

One such exception is that if a command substitution contains a single jobs
command, this jobs command returns information about the parent shell
environment. This exception is documented in the man page under "Command
Substitution". The command is otherwise still executed in a subshell
environment, so, for example, variable assignments in expansions do not
persist. Technically, this is implemented by executing certain command
substitutions in the same process; among other things, resetting the jobs table
is skipped and anything that would alter it does not follow this code path.

This exception is commonly available (like the one for `trap` which has an
Austin Group interpretation: https://www.austingroupbugs.net/view.php?id=53 ),
but is not always implemented the way FreeBSD sh implements it. Some other
shells instead implement it by making `jobs` (or `trap`) return the information
from just before the subshell environment was entered if no change had been
made yet, but in the case of `jobs` this is a bit unfortunate: either it
creates an observable difference between (non-special) builtins and external
programs, or it requires trickery to ensure a foreground job can be run without
disturbing the jobs table for display by `jobs`.

In bash (5.1.16(0)-release), `:& jobs | wc -l` and `:& J=jobs; $J | wc -l`
work, but `:& { jobs; } | wc -l` does not, so bash appears to use a similar
analysis like FreeBSD sh uses for command substitutions.

You are receiving this mail because:
You are the assignee for the bug.