View Issue Details

IDProjectCategoryView StatusLast Update
00019661003.1(2024)/Issue8Shell and Utilitiespublic2026-02-06 09:11
Reporterstephane Assigned To 
PrioritynormalSeverityObjectionTypeClarification Requested
Status Interpretation RequiredResolutionAccepted As Marked 
NameStephane Chazelas
Organization
User Reference
Sectioncurrent/previous job in basedefs, jobs, fg, bg utilities
Page Number(page or range of pages)
Line Number(Line or range of lines)
Interp StatusPending
Final Accepted Text0001966:0007371
Summary0001966: Current/previous job definition scattered and ambiguous
DescriptionPOSIX defines the "current job" as:

> In the context of job control, the job that will be used as
> the default for the fg or bg utilities.

(https://pubs.opengroup.org/onlinepubs/9799919799.2024edition/basedefs/V1_chap03.html#tag_03_93).

With the fg utility specification stating:

> no job_id operand is given, the job_id for the job that was
> most recently suspended, placed in the background, or run as a
> background job shall be used.

(https://pubs.opengroup.org/onlinepubs/9799919799.2024edition/utilities/fg.html)

Previous job is defined as:

> In the context of job control, the job that will be used as
> the default for the fg or bg utilities if the current job
> exits.

(https://pubs.opengroup.org/onlinepubs/9699919799.2018edition/basedefs/V1_chap03.html#tag_03_286)

We however need to refer to the "jobs" utility specification to
make some sense out of that:

> The character '+' identifies the job that would be used as a
> default for the fg or bg utilities; this job can also be
> specified using the job_id %+ or "%%". The character '-'
> identifies the job that would become the default if the
> current default job were to exit; this job can also be
> specified using the job_id %-. For other jobs, this field is a
> <space>. At most one job can be identified with '+' and at
> most one job can be identified with '-'. If there is any
> suspended job, then the current job shall be a suspended job.
> If there are at least two suspended jobs, then the previous
> job also shall be a suspended job.

(https://pubs.opengroup.org/onlinepubs/9799919799.2024edition/utilities/jobs.html)

That suggests "the job_id for the job that was most recently
suspended, placed in the background, or run as a background job
shall be used" from the "current job" definition is to be
interpreted as:
1. the most recently suspend job if there are suspended jobs
2. if not, the job most recently "placed in the background"
(whatever that means) if there are some.
3. if not the job most recently started in background.

As far I know, the only ways to "place" a job in the background
are to suspend them whilst they are in foreground or start them
in background in the first place, so there are several ways to
interpret that "2" above:

a) 3 is redundant but it's to emphasis that it's the time of
last suspend (whilst in foreground, or not, to be clarified)
that's important for those jobs that have been suspended.
b) it's to say that jobs that have ever been suspended (have
ever been in foreground before) take precedence over jobs that
were started in background in the first place and were never
suspended.
c) maybe "resumed in background" (by way of bg or any other way
SIGCONT is delivered) was intended instead of "placed in
background".

The Rationale there also has:

> The job control features provided by bg, fg, and jobs are
> based on the KornShell. The standard developers examined the
> characteristics of the C shell versions of these utilities and
> found that differences exist. Despite widespread use of the C
> shell, the KornShell versions were selected for this volume of
> POSIX.1-2024 to maintain a degree of uniformity with the rest
> of the KornShell features selected (such as the very popular
> command line editing features).

However, testing ksh88 from Solaris 11.4's /usr/xpg4/bin/sh and
ksh93u+m/1.0.8 2024-01-01, those are clearly not compliant, as

$ sleep 1001
^Z[1] + Stopped sleep 1001
$ sleep 1002 &
[2] 20308
$ jobs
[2] + Running sleep 1002 &
[1] - Stopped sleep 1001

The suspended job is not made the current job, whilst that's the
part that is clearly unambiguous in the spec in the description
of the jobs utility.

In practice, I see a lot of variation between implementations,
and I don't think I've come across one that fully implements any
of the interpretations listed above.
Desired ActionChange the definition of "current job" to:

Either make (carry on making) ksh non-compliant with:

> If there are any suspended job, the most recently suspended
> job. If not, one of the jobs running in background. It's
> unspecified whether that's the most recently started, most
> recently suspended (in the past) or most recently resumed or
> combination thereof.

Or to also account for ksh (mksh is yet different from ksh88/ksh93)
with:

> If there are any suspended job, then the current job shall
> be the most recently suspended job as long as it's still in
> a suspended state and no other job was started since it was
> last suspended. Otherwise, it is unspecified which job shall
> be the current job.

Adding a:

> users may refer to the output of the jobs utility to know
> which is the current and previous job

With a reference to the jobs utility specification could be
useful.

Maybe clarify the definition of "previous job" to something
like:

> what the current job would be in the absence of whichever job
> is currently appointed as the current job.

Then update the "jobs" / "fg" / "bg" specification to refer to
those definitions.

And either remove the jobs utility rationale section about the
specification being based on the Korn shell rather than C shell
or clarify which of the C / Korn shell behaviours were selected
in the POSIX specification.
Tagstc1-2024

Activities

geoffclare

2026-02-05 17:20

manager   bugnote:0007371

Interpretation response
------------------------
The standard is unclear on this issue, and no conformance distinction can be made between alternative implementations based on this. This is being
referred to the sponsor.

Rationale:
-------------
There is a conflict between the description of <current> in the STDOUT section of the jobs utility and the description of the job_id operand for the fg and bg utilities.

Notes to the Editor (not part of this interpretation):
-------------------------------------------------------

On page 2666 line 87729 section bg, change:
If no job_id operand is given, the most recently suspended job shall be used.

to:
If no job_id operand is given, the job_id for the job that was most recently suspended, placed in the background, or run as a background job shall be used, except that if there is any suspended job:

  • If the most recently suspended job is still in a suspended state and no other job was started since it was last suspended, that job shall be used.

  • Otherwise, it is unspecified which job shall be used.



On page 2928 line 97725 section fg, change:
If no job_id operand is given, the job_id for the job that was most recently suspended, placed in the background, or run as a background job shall be used.

to:
If no job_id operand is given, the job_id for the job that was most recently suspended, placed in the background, or run as a background job shall be used, except that if there is any suspended job:

  • If the most recently suspended job is still in a suspended state and no other job was started since it was last suspended, that job shall be used.

  • Otherwise, it is unspecified which job shall be used.


    
 On page 3022 line 101144 section jobs, delete:
If there is any suspended job, then the current job shall be a suspended job. If there are at least two suspended jobs, then the previous job also shall be a suspended job.

stephane

2026-02-06 09:11

reporter   bugnote:0007372

Re: 0001959:0007370

> the job that was most recently suspended, placed in the
> background, or run as a background job

We may want to clarify what "placed in the background" means.
AFAIK, the only ways (as already noted in the bug description)
to "place" a job in the background are to "run it as a
background job" and suspend them whilst they are in foreground,
which here would seem to make that "placed in background"
redundant.

The "bg" utility is to "resume, still in background" (send
SIGCONT to the process group), while "fg" puts a job in
foreground, resumes it if suspended and waits for one of the
processes in the job to terminate or be suspended again.

I've tried to check whether any shell was compliant to this new
specification and among mksh, yash, bash, zsh, dash, ksh93, only
ksh93 seems to be as it's the only one that seems to maintain
the job table in terms of priority for that "current job" (and
diverges from all other shells and by not always priotising
suspended jobs).

dash (and presumably other ash-based shells) also does that
ordering, but since it prioritises suspended jobs, as was the
spirit of job control as originally implemented on BSDs, (and
if not makes "bg" alone less useful for instance), once resumed
in background, that background job remains the current job:

$ dash
$ sleep 1h &
$ sleep 2h
^Z[2] + Stopped sleep 2h
$ sleep 3h &
$ jobs
[2] + Stopped sleep 2h
[3] - Running sleep 3h
[1] Running sleep 1h

Stopped job is current as allowed (previously required) by the
proposed text.

$ bg
[2] sleep 2h
$ jobs
[2] + Running sleep 2h
[3] - Running sleep 3h
[1] Running sleep 1h

%2 still current job which sounds like is not compliant to the
new text unless the:

> the job that was most recently suspended, placed in the
> background, or run as a background job shall be used.

Is to be understood as:

1. most recently suspended job if any of the jobs have ever
been suspended.
2. If not: most recently "placed in background" if any of the
jobs have even been "placed in background".
3. If not: most recently run as a background job.

(In which case ksh93 would not be compliant) as otherwise %3
would need to be the current job as it was "placed in the
background" (or "run as a background job") after %2 was
suspended.

In any case, bash, zsh, mksh, yash are not compliant (because
they don't order that list or some other reasons).

In other words, I suggested two resolutions, one that would
(AFAICT) make all shells but ksh compliant and was more in the
spirit of the current specification and another one that would
make all shells compliant, but instead, the currently proposed
resolution makes all shells but ksh non-compliant, ksh being the
one that goes against the fundamental principle that suspended
jobs should be prioritised for the current/previous job
appointment.

IMO, that's not OK, because it doesn't help.

First, IMO, POSIX specifying interactive use behaviour has
little benefit. It's invaluable to standardise the shell
language to write portable scripts, but trying to tightly
specify user interaction is more likely to hinder progress than
anything.

One could argue that specifying interactive use experience means
users from one system/shell can expect not to be disoriented
when jumping to another system/shell, but in this instance, the
resolution makes an important point unspecified and on the other
hand mandates things that are less important and in practice
vary between implementations.

If there's a suspended job, people expect that to be the current
job as that's what most shells do and even what POSIX currently
requires. ksh breaks that expectation.

On the other end, what rules determine which job will become the
current job once the current and previous jobs have terminated
or all jobs have been resumed matters less, as nobody will
manage to remember those rules and compute them mentally so
would need to refer to the "jobs" output to know which it is or
would refer to jobs by their number or search string instead.

About the "previous job" definition:

> In the context of job control, the job that will be used as
>the default for the fg or bg utilities if the current job exits

A process can "exit", by way of the exit() function for
instance, but what does it mean for a "job" to exit?

For instance,

(sleep 60 & sleep 1)

Starts a foreground job with a process running sleep 60, one
running sleep 1 and possibly a shell one waiting for sleep 1,

After one second, the one running sleep 1 (and the shell one
waiting for it if any) exit()s, while the one running sleep 60
is still running. However, as far as the interactive shell that
started that job is concerned, that job is gone as there's only
one process in that job it's waiting for (the one that runs the
subshell if any and possibly subsequently sleep 1 or waited for
that sleep 1 in those shells that implement subshells as child
processes and don't optimise out the fork for sleep 1).

My:

> what the current job would be in the absence of whichever job
> is currently appointed as the current job.

Was attempting to clarify it, and avoids having to define what
it means for a job to "exit" though still leaves it unclear what
makes a job "absent" or "present".

Note that even "running job" or "suspended job" are potentially ambiguous as some
processes in the job could be suspended and some running, but
maybe that's for another bug.

Issue History

Date Modified Username Field Change
2025-12-21 11:17 stephane New Issue
2026-01-06 10:04 geoffclare Project 1003.1(2013)/Issue7+TC1 => 1003.1(2024)/Issue8
2026-02-05 17:20 geoffclare Note Added: 0007371
2026-02-05 17:21 geoffclare Status New => Interpretation Required
2026-02-05 17:21 geoffclare Resolution Open => Accepted As Marked
2026-02-05 17:21 geoffclare Interp Status => Pending
2026-02-05 17:21 geoffclare Final Accepted Text => 0001966:0007371
2026-02-05 17:21 geoffclare Tag Attached: tc1-2024
2026-02-06 09:11 stephane Note Added: 0007372