考虑这种情况,当我想生成一个打算在后台运行的子进程时,但需要花一点时间进行设置,比如launch-git-daemon
。如何通知调用脚本脚本已准备好开始服务?
调用(父)脚本:
#!/bin/bash
./launch-git-daemon /srv/git-repos &
pid=$!
wait-until-launch-git-daemon-notifies-us
#do stuff that involves access to the git server
launch-git-daemon
:
#!/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中建立某种进程间通信机制!
答案 0 :(得分:2)
您可以将命名管道用于此类目的。
$ 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" )
因此,只要孩子在命名管道中写入,父母就会得到满意的“读取”语句。 (如果你在循环中读取,你可以读取多行。)
如果你想一想,你可以意识到孩子可以做的不仅仅是写任何东西。它可以将信息传递给父母,告诉它事情进展顺利,或失败等等。而且你不仅限于一个孩子。父节点可以创建一个命名管道,并生成多个子节点,每个子节点使用相同的管道告诉父节点何时准备好。
请记住,通常您应该只从管道中读取一个任务。如果有多个读者,则无法预测哪个读者会得到孩子所写的行。
答案 1 :(得分:1)
在一个终端中运行此脚本:
#! /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
另一个终端中正在运行的脚本,它会在第二个终端中检测到信号接收。
答案 2 :(得分:1)
这是两种方法的公平比较。
<强> 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
<强> child.sh:
强>
#!/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
<强> parent.sh:
强>
#!/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
<强> child.sh:
强>
#!/bin/bash
if [ -n "$1" ]; then
sleep 20 #Sometimes it takes long to start serving.
fi
kill -USR1 $PPID
sleep 10000
我会选择信号。命名管道为简洁和简单的成本提供了太多的灵活性。