I have a jobscount() function:

jobscount() {
   local stopped='$(jobs -s | wc -l | tr -d " ")'
   local running='$(jobs -r | wc -l | tr -d " ")'
   echo -n "${running}r/${stopped}s"

I use this function in my $PS1:

PS1=" \w $(jobscount) \$ "

The only problem is if there is no background process running or there is no stopped jobs, this function uselessly occupies $PS1 space. What I want is if either of the stopped or running value is more than 0, only then it shows up.

  • 1
    Related question.
    – jw013
    Mar 20 '13 at 15:40
  • 2
    Is the tr -d ' ' necessary?
    – jw013
    Mar 20 '13 at 15:44
  • @jw013 It was for me, perhaps gnu wc is different, but on OS X each output column is separated by 7 spaces - including before the first.
    – OJFord
    May 17 '16 at 0:02
  • Another related question, on SO. Oct 6 '16 at 3:23

First of all, I suggest to fix your quoting. You current function does not output useful data when run stand-alone from the command prompt.

Then add a condition, using the OR list separator, before the echo:

jobscount() {
  local stopped=$(jobs -sp | wc -l)
  local running=$(jobs -rp | wc -l)
  ((running+stopped)) && echo -n "${running}r/${stopped}s "

PS1=' \w $(jobscount)\$ '

I also suggest to add -p to the jobs calls so they output only process PIDs. Otherwise a yes $'foo\nbar' & command, listed on 2 lines, would be counted twice.

  • Here is what happens. 1. When I remove the quotes around them, the function don't work (there is always 0r/0s). 2. After adding ((running+stopped)) &&, I get bash: ((: $(jobs -rp | wc -l): syntax error: operand expected (error token is "$(jobs -rp | wc -l)") as error when opening a new terminal. Mar 20 '13 at 15:58
  • Works for me: pastebin.com/vQtW9qJC . Have you noticed that I changed both the function (removed single quotes) and the PS1 (changed double quotes to single ones)?
    – manatwork
    Mar 20 '13 at 16:09
  • Your solution works correct if I start bash with --norc and paste the function online. The result is total different if I put that in my .bashrc file. Mar 20 '13 at 16:39
  • I tried it both directly from the command line and from my .bashrc. I had no issues. By the way, I put it at the very end of my .bashrc to make sure nothing alters the prompt after it. Do you have other PS1 assignments there? If yes, post them so we can suggest a way to make all your prompt features compatible.
    – manatwork
    Mar 20 '13 at 16:46

You guys are making this way too complicated. Just check if the output from jobs is non-empty and then add \j to your PS1 string.

if [ -n "$(jobs -p)" ]; then echo "\j"; fi

Here's a snippet from my prompt:

#Show number of jobs if at least one job
export PS1+='`if [ -n "$(jobs -p)" ]; then echo "(\j)"; fi`'

Since you're running this at every prompt, it's worth saving a few external calls.

To show the count only if there are background jobs, check the numbers and don't print anything if they're all 0.

Run jobs -p to get just the process IDs, it's easier to parse reliably.

jobscount() {
  set -- $(jobs -rp)
  set $# $(jobs -sp)
  set $1 $(($#-1))
  if [ $1 -ne 0 ] || [ $2 -ne 0 ]; then echo "${1}r/${2}s"; fi
PS1=' \w $(jobscount) \$ '

By the way, note the quotes around the right-hand side when assigning to PS1. With double quotes, the function is called when you set the variable. You need to use single quotes, so that the value of PS1 contains the text $(jobscount) and the function is called each time the prompt is displayed.

You can save one fork by using PROMPT_COMMAND to set a variable instead of using a function's output.

set_jobscount () {
  set $(jobs -rp)
  set $# $(jobs -sp)
  set $1 $(($#-1))
  if [ $1 -ne 0 ] || [ $2 -ne 0 ]; then
PS1=' \w ${jobscount} \$ '

As usual it's simpler (if cryptic-looking) in zsh.

precmd () {
  if [[ $jobscount == r0/s0 ]]; then jobscount=; fi
setopt prompt_subst
PS1='… ${jobscount} …'

Here jobstates is Zsh provided variable from zsh/parameter module. #running and #suspended separates output to include only either running or suspended jobs. (M) flag and %% are from parameter expansion. (M) flag removes the non-matched elements and %% deletes anything after : from the output of $jobstates

  • set $(jobs -rp) produces the same verbose output as set if there are no running jobs.
    – Tom Hale
    Jul 8 '18 at 13:49

I'm using a variant of this to show the exit code only if it's non-zero:

PS1=' \w $(running=$(jobscount); [ "${running:-0}" -eq 0 ] || printf %s "$running") \$ '

The code inside will run every time the prompt is displayed.


how about $() in PS1, like:

export PS1='\w $(if test "\j" -ne "0"; then echo -e "\033[32m\j "; fi )\[\033[01;35m\]\$\[\033[00m\] '

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.