3

I use shell job control to kick longer running tasks in to the background so I can continue while they churn through their data.

I can see the jobs I've got running with jobs, for example,

jobs
[2]-  Running                 su - root -c "..." &  (wd: /backup/rsnapshot)
[3]+  Running                 sleep 60 &

and I can control any one of these using the % jobspec syntax, such as fg %su or kill %3.

If I use jobs -l I get the PIDs too:

jobs -l
[2]- 31736 Running                 su - root -c "..." &  (wd: /backup/rsnapshot)
[3]+  2269 Running                 sleep 60 &

Using bash I've got jobs -x, but this isn't POSIX. Is this the only way to translate these % jobspec values into PIDs, or is there a sensible (better) alternative approach? What about for other shells?

jobs -x echo %3
2269

My target use case is for the % jobspec to be expanded transparently on the command line into the corresponding PID, so that in a command such as this the %2 would be seen by the command as 31736

pidtree %2    # pidtree 31736

This can be handled as jobs -x pidtree %2 but that's not as elegant or convenient.

I'd like at least one answer targeting bash, but contributions for other shells with job control are welcome, particularly if you have a POSIX solution.

8
  • jobs -l or jobs -x can be piped to a bash action to get informations over the job like openned files & so on ; depending of your final objectives . for example cat /proc/25943/task/25943/statm and so on... Please edit the question with an use case.
    – francois P
    Aug 4 '20 at 11:07
  • tried out an example : cat /proc/$(jobs -l | sed 's/.*+ \(.*\) [A-Z].*/\1/; /[^0-9]/ d ')/statm answered 2451 1109 398 219 0 742 0 so sed substitution worked (not optimized at all to let you understand)
    – francois P
    Aug 4 '20 at 11:21
  • jobs -l or jobs -x is part of the Bourne Shell since before bash exists. Is your question about non-conforming shells?
    – schily
    Aug 4 '20 at 11:22
  • I suspect that roaima's next question will be what part of the SVID talks about jobs -x, because the SUS does not. (-:
    – JdeBP
    Aug 4 '20 at 12:06
  • 1
    @schily jobs -x wasn't recognised by dash and it's not POSIX
    – roaima
    Aug 4 '20 at 12:45
2

On bash you might get close to that by providing a custom $PROMPT_COMMAND setting variables on-fly from the current list of jobs.

Proof-of-concept:

$ PROMPT_COMMAND='unset ${!j*}; eval "$(jobs -l | awk '\''{gsub("[^[:digit:] ]", ""); printf "j%d=%d\n", $1, $2}'\'')"'

You would then do pidtree $j2 instead of pidtree %2, assuming there are no numbers in $IFS or else you have to quote the $j2 thus requiring two keystrokes more.

1

If you want this for a few commands only, then programmable completion would be an option. That is most probably not POSIX but at least available in several shells (and the underlying mechanism would not even have to be the same).

So you would type pidtree %2Tab and the shell would transform that into

pidtree 31736

I would consider that as elegant and convenient.

Disadvantage: Keeping existing completion configurations for those commands requires manual intervention (like: run your function first; if it does not match then make it call the original one).

_pidtree () {
    local job pid
    if [[ ${COMP_WORDS[COMP_CWORD]} =~ ^%[1-9][0-9]* ]]; then
        job="${COMP_WORDS[COMP_CWORD]:1}"
        pid="$(jobs -l | awk -v job="$job" '$1 ~ "^\\[" job "\\]" { print $2; }')"
        COMPREPLY=("$pid")
    fi
}

complete -F _pidtree pidtree

That works in bash. It could be done without awk, and it certainly can be done in a more compatible way.

Jobs which contain newlines could be a problem but as this is your interactive shell there seems not to be a risk that this could be exploited.

2
  • Are you saying this is already a thing, or that you're suggesting it as an unimplemented possibility? I like this
    – roaima
    Aug 8 '20 at 15:25
  • 1
    I did not search for something like that but doubt that it is well known available. I added some code to my answer. Aug 8 '20 at 15:54
0

Wouldn't it be easiest to just remember the PIDs when the backgroud jobs are created?

bash:

declare -a bgjobpids
[...]
do_some_thing &
pid=$!
index=${#bgjobpids[@]}
bgjobpids[index]=$pid
[...]
do_some_thing_else &
pid=$!
index=${#bgjobpids[@]}
bgjobpids[index]=$pid
1
  • Programmatically, yes sure. But my use case is the interactive shell
    – roaima
    Aug 8 '20 at 8:08

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.