将 shell 作业号映射到 PID

将 shell 作业号映射到 PID

我使用 shell 作业控制将较长时间运行的任务踢到后台,这样我就可以在它们搅动数据时继续运行。

我可以看到我正在运行的作业jobs,例如,

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

我可以使用以下命令控制其中任何一个% 工作规范语法,例如fg %suor kill %3

如果我使用的话,jobs -l我也会得到 PID:

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

使用bash我有jobs -x,但是这个不是 POSIX。这是翻译这些的唯一方法吗% 工作规范值到 PID 中,或者是否有明智的(更好)替代方法?那么其他的贝壳呢?

jobs -x echo %3
2269

我的目标用例是% 工作规范待扩大透明地在命令行上输入相应的 PID,这样在这样的命令中 就会%2被命令视为31736

pidtree %2    # pidtree 31736

这可以被处理,jobs -x pidtree %2但不是那么优雅或方便。

我想要至少一个答案 Targeting bash,但欢迎为具有作业控制的其他 shell 做出贡献,特别是如果您有 POSIX 解决方案。

答案1

您可以通过从当前作业列表中动态bash提供自定义设置变量来接近这一点。$PROMPT_COMMAND

概念验证:

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

然后,您将pidtree $j2代替pidtree %2,假设 中 没有数字,$IFS否则您必须引用 ,$j2因此需要多敲两次键。

答案2

如果您只想对几个命令执行此操作,那么可编程完成将是一个选项。这很可能不是 POSIX,但至少可以在多个 shell 中使用(并且底层机制甚至不必相同)。

所以你可以输入pidtree %2Tab,shell 会将其转换为

pidtree 31736

我认为这是优雅和方便的。

缺点:保留这些命令的现有完成配置需要手动干预(例如:首先运行您的函数;如果不匹配,则使其调用原始函数)。

_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

这适用于bash.它可以在没有 的情况下完成awk,并且当然可以以更兼容的方式完成。

包含换行符的作业可能会出现问题,但由于这是您的交互式 shell,因此似乎不存在被利用的风险。

答案3

创建后台作业时只记住 PID 不是最简单的吗?

bash:

declare -a bgjobpids
[...]
do_some_thing &
pid=$!
index=${#bgjobpids[@]}
bgjobpids[index]=$pid
[...]
do_some_thing_else &
pid=$!
index=${#bgjobpids[@]}
bgjobpids[index]=$pid

相关内容