4

I'd like to have the current jobs status displayed in the title of my terminal. In Bash, I can use PROMPT_COMMAND for that. Korn Shell (ksh93) doesn't have that.

Other answers suggest using command substitution inside $PS1, which works fine in the general case, but not for the jobs command. The problem here is that jobs is concerned about the jobs of the current shell, but command substitution (i.e. PS1='...$(jobs)...') is performed in a subshell, so there are no jobs.

The only mechanism I'm aware of is trap '... jobs ...' DEBUG, but that would execute way too often. Do you know a way how to run commands in the context of the current shell, once on each prompt, or is this not possible in Korn shell?!

3

By default if you just set PS1="...." then the stuff inside the quotes is evaluated at the time you set it.

However if you enclose it inside ' instead then it's evaluated at display time. And it doesn't cause a subshell for $(jobs).

e.g.

$ PS1='
> $(jobs)
> $ '


$ sleep 1000 &
[1] 7541

[1] +  Running                 sleep 1000 &
$ sleep 1000 &
[2] 7543

[2] +  Running                 sleep 1000 &
[1] -  Running                 sleep 1000 &
$ kill %1
[1] - Terminated               sleep 1000 &

[2] +  Running                 sleep 1000 &
$ kill %2
[2] + Terminated               sleep 1000 &


$ 

(This test done on Debian Jessie with ksh93 but should work on all ksh93 variants; I don't have any ksh88 to test with.)

  • I was aware of the differences in evaluation, that wasn't the issue. But I was able to find my actual problem, once your answer confirmed that this should work without a subshell. Thanks! – Ingo Karkat Jul 8 '16 at 15:25
1

My actual problem was that (in contrast to the simplified example in my question), I actually massaged the jobs output in a function, separating running from stopped jobs.

This is my code for Bash:

typeset runningJobs=$(jobs -r | wc -l)
typeset stoppedJobs=$(jobs -s | wc -l)

which I ported to Korn shell in this way:

typeset runningJobs=$(jobs | grep -c ' Running ')
typeset stoppedJobs=$(jobs | grep -c ' Stopped ')

The pipeline inside the $(...) command substitution actually was causing jobs to be executed in a subshell (and therefore always yielded no output). By capturing the output in a variable, this can be prevented. The following rewrite works as expected:

typeset jobOutput=$(jobs)
typeset runningJobs=$(printf '%s\n' "$jobOutput" | grep -c ' Running ')
typeset stoppedJobs=$(printf '%s\n' "$jobOutput" | grep -c ' Stopped ')

Thanks to @StephenHarris for his answer, which helped me understanding the actual issue!

  • Beware oversimplification :-) – Stephen Harris Jul 8 '16 at 15:28
  • @StephenHarris: You don't want to see my huge (but critically important to me) mess of init scripts I've been building over 15+ years, starting first on HP-UX and various other Unixes :-) – Ingo Karkat Jul 8 '16 at 15:48
  • 1
    I can't find the reference at the moment, but I think there's a special exception in the standard that says that if you run just a simple jobs command in a subshell, it will list the jobs in the parent shell. – Mark Plotnick Jul 8 '16 at 17:30

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.