Bash 子进程能否向父进程发送事件信号?

Bash 子进程能否向父进程发送事件信号?,bash,Bash,考虑一下这个场景,当我想要生成一个子进程,该子进程打算在后台运行,但需要一些时间来设置,比如启动git守护进程。如何通知调用脚本脚本脚本已准备好开始服务 调用(父)脚本: 启动git守护进程: #!/bin/bash repopath="$1" sudo dpkg -s git>/dev/null if [ $? -eq 0 ]; then echo "git already installed!" else sudo apt-get --yes install git

考虑一下这个场景,当我想要生成一个子进程,该子进程打算在后台运行,但需要一些时间来设置,比如
启动git守护进程
。如何通知调用脚本脚本脚本已准备好开始服务

调用(父)脚本:

启动git守护进程

#!/bin/bash
repopath="$1"

sudo dpkg -s git>/dev/null
if [ $? -eq 0 ]; then
    echo "git already installed!"
else
    sudo apt-get --yes install git
fi

signal-to-parent-that-we-are-ready-to-serve

git daemon --verbose --base-path="$repopath" --export-all --informative-errors --enable=receive-pack

我知道孩子总是可以触摸一些tmp文件,家长可以测试它的存在,但它看起来非常笨拙和低效。我希望bash中内置了某种进程间通信机制

您可以将命名管道用于此类目的

$ mknod testpipe p

$ ls -la
total 20
drwxr-xr-x  2 gp         users 4096 Oct 23 12:31 .
drwxr-xr-x 11 gp         users 4096 Oct 23 12:29 ..
prw-r--r--  1 gp         users    0 Oct 23 12:31 testpipe


$ ( read line <testpipe ; echo "We read this: $line"; ) &
[1] 17065

$ echo "This is a test" >testpipe

$ We read this: This is a test
[1]+  Done                    ( read line < testpipe; echo "We read this: $line" )
$mknod测试管道p
$ls-la
总数20
drwxr-xr-x 2 gp用户4096 10月23日12:31。
drwxr-xr-x 11 gp用户4096 10月23日12:29。。
prw-r--r--1 gp用户0 10月23日12:31测试管道
$(读线测试管)
$我们读到:这是一个测试
[1] +完成(读取行
因此,只要子级在命名管道中写入,父级就会满足“read”语句。(如果在循环中读取,则可以读取多行。)

如果你仔细想想,你会意识到孩子可以做的不仅仅是写任何东西。它可以将信息传递回家长,告诉家长事情进展顺利还是失败,等等。你不局限于一个孩子。家长可以创建一个命名管道,并产生多个孩子,每个孩子都使用同一个管道告诉家长当他们准备好的时候


请记住,通常情况下,您应该只有一个任务从管道中读取。如果有多个读取器,则无法预测哪个读取器将获得孩子们所写的行。

在一个终端中运行此脚本:

#! /bin/bash

sigusr1_received=false

catch_sigusr1 () { sigusr1_received=true ;}

trap catch_sigusr1 USR1

echo "My PID is $$"
echo "Waiting for SIGUSR1 ..."

while ! $sigusr1_received ; do sleep 1 ; done

echo "SIGUSR1 received."

exit 0

现在,
kill-USR1
在另一个终端中运行脚本,它将在第二个终端中检测信号接收。

这里是两种方法的公平比较

命名管道
parent.sh:

#!/bin/bash

#Spawn the child process
pipe=/tmp/mypipe
if [[ ! -p $pipe ]]; then
    mkfifo $pipe
fi
bash -x ./child.sh &
childpid=$!

sleep 10 #Do some work, we will need a child soon after it.

read ans <$pipe
if [[ "$ans" != "ready to serve" ]]; then
    echo "Unknown answer from child!"
    exit 1
fi

#Here we can do stuff that require readiness from the client

sleep 5

#Kill the child

kill $childpid
#!/bin/bash

if [ -n "$1" ]; then
    sleep 20 #Sometimes it takes long to start serving.
fi

pipe=/tmp/mypipe

if [[ ! -p $pipe ]]; then
    echo "Cannot find a parent process. This script is not intended to be run alone."
    exit 1
fi

echo "ready to serve" >$pipe

sleep 10000
#!/bin/bash

#Spawn the child process

sigusr1_received=false
catch_sigusr1 () { sigusr1_received=true ;}
trap catch_sigusr1 USR1
bash -x ./child.sh &
childpid=$!

sleep 10 #Do some work, we will need a child soon after it.

while ! $sigusr1_received ; do sleep 1 ; done

#Here we can do stuff that require readiness from the client

sleep 5

#Kill the child

kill $childpid
#!/bin/bash

if [ -n "$1" ]; then
    sleep 20 #Sometimes it takes long to start serving.
fi

kill -USR1 $PPID

sleep 10000
信号
parent.sh:

#!/bin/bash

#Spawn the child process
pipe=/tmp/mypipe
if [[ ! -p $pipe ]]; then
    mkfifo $pipe
fi
bash -x ./child.sh &
childpid=$!

sleep 10 #Do some work, we will need a child soon after it.

read ans <$pipe
if [[ "$ans" != "ready to serve" ]]; then
    echo "Unknown answer from child!"
    exit 1
fi

#Here we can do stuff that require readiness from the client

sleep 5

#Kill the child

kill $childpid
#!/bin/bash

if [ -n "$1" ]; then
    sleep 20 #Sometimes it takes long to start serving.
fi

pipe=/tmp/mypipe

if [[ ! -p $pipe ]]; then
    echo "Cannot find a parent process. This script is not intended to be run alone."
    exit 1
fi

echo "ready to serve" >$pipe

sleep 10000
#!/bin/bash

#Spawn the child process

sigusr1_received=false
catch_sigusr1 () { sigusr1_received=true ;}
trap catch_sigusr1 USR1
bash -x ./child.sh &
childpid=$!

sleep 10 #Do some work, we will need a child soon after it.

while ! $sigusr1_received ; do sleep 1 ; done

#Here we can do stuff that require readiness from the client

sleep 5

#Kill the child

kill $childpid
#!/bin/bash

if [ -n "$1" ]; then
    sleep 20 #Sometimes it takes long to start serving.
fi

kill -USR1 $PPID

sleep 10000
child.sh:

#!/bin/bash

#Spawn the child process
pipe=/tmp/mypipe
if [[ ! -p $pipe ]]; then
    mkfifo $pipe
fi
bash -x ./child.sh &
childpid=$!

sleep 10 #Do some work, we will need a child soon after it.

read ans <$pipe
if [[ "$ans" != "ready to serve" ]]; then
    echo "Unknown answer from child!"
    exit 1
fi

#Here we can do stuff that require readiness from the client

sleep 5

#Kill the child

kill $childpid
#!/bin/bash

if [ -n "$1" ]; then
    sleep 20 #Sometimes it takes long to start serving.
fi

pipe=/tmp/mypipe

if [[ ! -p $pipe ]]; then
    echo "Cannot find a parent process. This script is not intended to be run alone."
    exit 1
fi

echo "ready to serve" >$pipe

sleep 10000
#!/bin/bash

#Spawn the child process

sigusr1_received=false
catch_sigusr1 () { sigusr1_received=true ;}
trap catch_sigusr1 USR1
bash -x ./child.sh &
childpid=$!

sleep 10 #Do some work, we will need a child soon after it.

while ! $sigusr1_received ; do sleep 1 ; done

#Here we can do stuff that require readiness from the client

sleep 5

#Kill the child

kill $childpid
#!/bin/bash

if [ -n "$1" ]; then
    sleep 20 #Sometimes it takes long to start serving.
fi

kill -USR1 $PPID

sleep 10000

我将使用信号。命名管道以简洁和简单为代价提供了太多的灵活性。

使用
$PPID
变量?解决方案您需要向家长发出信号,表示孩子已经准备好了,对吗?因此,从孩子向家长发送一个信号,并将其困在家长中。
陷阱
并不等待,这是正确的,但你可以很容易地在一个小的休眠循环中等待陷阱设置一个变量,或者从陷阱处理程序中运行第二个脚本,然后退出,等等。在我看来,signals方法更简洁、更简单。回答很好。Foe me管道提供了一点太多的功能,代价是多了一点失败点和要键入的字母-这就是我接受它的原因信号版本。