如何在shell中的后台进程中回显每个提示消息前面的PID?

时间:2013-11-04 19:33:50

标签: bash shell

我有一个主shell文件main.sh,以及所有通过执行调用的后台子shell文件。这些文件为a.shb.shc.sh ...

我在主要调用这些子shell文件,如下所示:

#main.sh
./a.sh &
./b.sh &
./c.sh &

在每个后台子shell文件中,格式如下所示

#a.sh
echo "This is a process"

子单元几乎相同,输出消息对于我的任务是必需的,但很难识别哪些消息对应于哪个子shell进程。我正在考虑为它们分配一个PID,并将该PID添加到每个子shell的消息输出中。 这看起来如下:

[123]This is a process
[234]This is a process
...

谢谢!

编辑在main.sh中启用此功能会很棒,而不是修改子shell进程,因为我只想看一些它们进行调试。

5 个答案:

答案 0 :(得分:2)

变量$$包含当前PID。

echo "[$$]This is a process"

答案 1 :(得分:1)

为什么不像这样启动它们?

./a.sh | sed 's/^/[a] /' &
./b.sh | sed 's/^/[b] /' &
./c.sh | sed 's/^/[c] /' &

或者即使你真的想要包含PID:

./a.sh | sed "s/^/[$!] /" &
./b.sh | sed "s/^/[$!] /" &
./c.sh | sed "s/^/[$!] /" &

应该有用。

答案 2 :(得分:0)

如果它不需要是实际的进程ID,而只需要一个唯一的标识符,则可以设置一个已知的环境变量:

#main.sh
MY_ID=1 ./a.sh &
MY_ID=2 ./b.sh &
MY_ID=3 ./c.sh &

#a.sh
echo "[$MY_ID]This is a process"

bash 4或更高版本中,您可以使用$BASHPID访问shell的进程ID,以便您 启动每个后台进程时不需要指定MY_ID

#a.sh
echo "[$BASHPID]This is a process"

如果要使用标识符自动添加每行输出,则需要为echo定义包装器,而不是直接使用它:

my_echo () { echo "[$MY_ID]$*"; }
my_echo () { echo "[$BASHPID]$*"; }

答案 3 :(得分:0)

您可以创建一个名为“echo”的bash包装函数并将其导出,因此您的后台脚本使用此覆盖版本:

ubuntu@ubuntu:~$ cat bgscript
#!/bin/bash
for i in {1..3}; do echo "i=$i"; done

ubuntu@ubuntu:~$ function echo { builtin echo "[$$]$@"; }
ubuntu@ubuntu:~$ export -f echo
ubuntu@ubuntu:~$ ./bgscript &
[1] 7290
ubuntu@ubuntu:~$ [7290]i=1
[7290]i=2
[7290]i=3

[1]+  Done                    ./bgscript
ubuntu@ubuntu:~$ 

答案 4 :(得分:0)

你可以使用bash coprocesses来实现这样的目标(需要bash 4)。代码如下:

prepend_pid() {
    coproc "${@}"
    pid=${!}
    trap "kill ${pid}" EXIT
    sed -e "s:^:${pid} :" </dev/fd/${COPROC[0]}
}

prepend_pid ./a.sh &
prepend_pid ./b.sh &
prepend_pid ./c.sh &

这是因为你需要实现两个目标:

  1. 您需要首先分叉脚本以了解其PID,
  2. 您需要在分支之前重定向脚本输出。
  3. 协处理基本上是./a.sh &,但输入和输出重定向到匿名管道。管道fds放在${COPROC[@]}数组中。如果你没有足够新的bash,你可以使用命名管道。

    这里做了什么:

    1. 您在协同进程中启动脚本。它的输出排队到一个尚未使用的管道。
    2. 您从${!}获得分叉PID。
    3. 设置陷阱以在读取器终止时终止生成的脚本。
    4. 您启动一个新的sed进程,该进程从fd ${COPROC[0]}的管道读取脚本输出,并将pid添加到它。
    5. 请注意sed本身会阻止脚本,因此您也需要对其进行分叉。并且因为它需要访问管道,所以不能单独分叉。相反,我们分叉整个函数。

      陷阱确保在您终止衍生函数时生成的脚本将被终止。多亏了这一点,你可以做类似的事情:

      prepend_pid ./a.sh &
      spid=$!
      sleep 4
      kill ${spid}
      

      不用担心./a.sh会在没有输出的情况下继续在后台运行。