我有一个全局var foo =“some value”和一个后台进程back_func,我想让后台进程访问$ foo并修改它的值,这可以通过主进程看到。它类似于以下内容:
#!/bin/bash
foo=0
function back_func {
foo=$(($foo+1))
echo "back $foo"
}
(back_func) &
echo "global $foo"
上述脚本的结果是
global 0
back 1
我怎么能得到全局和后退的结果都是'1'?,即后台进程的修改可以返回到主进程。
答案 0 :(得分:21)
使用bash_ipc_demo
添加完成和图表生成器。
如果您想要两个可以进行通信的独立进程,则必须在两个进程都可以到达的位置放置 rendez-vous 。
这可能是一个简单的文件,一个fifo管道,一个unix套接字,一个TCP套接字或者其他(Rexx端口)。
Bash没有等效的rexx端口,因此有一些使用rendez-vous文件的示例(在我的Linux上)。
我正在使用共享内存 /dev/shm
,以减少磁盘负载。
$ back_func() {
while :;do
echo $(($(</dev/shm/foo)+1)) >/dev/shm/foo;
sleep .3;
done;
}
让我们玩
$ echo 1 >/dev/shm/foo
$ back_func &
$ echo $(</dev/shm/foo)
4
$ echo $(</dev/shm/foo)
21
现在停止:
$ fg
back_func
^C
或
$ kill $!
$
[1]+ Terminated back_func
因为有很多变种,所以可以采取一种很好的方式:
$ back_func() {
declare -A MYGLOBAL
local vars
while :; do
((MYGLOBAL["counter"]++))
IFS=\ / read -a vars <<< "$(</proc/uptime) $(</proc/loadavg)"
MYGLOBAL["uptime"]=$vars
MYGLOBAL["idle"]=${vars[1]}
MYGLOBAL["l01m"]=${vars[2]}
MYGLOBAL["l05m"]=${vars[3]}
MYGLOBAL["l15m"]=${vars[4]}
MYGLOBAL["active"]=${vars[5]}
MYGLOBAL["procs"]=${vars[6]}
MYGLOBAL["lpid"]=${vars[7]}
MYGLOBAL["rand"]=$RANDOM
MYGLOBAL["crt"]=$SECONDS
declare -p MYGLOBAL > /dev/shm/foo
sleep 1
done
}
然后
$ back_func &
[1] 27429
$ . /dev/shm/foo
$ echo ${MYGLOBAL['counter']}
5
$ echo ${MYGLOBAL['lpid']}
27432
从那里,为什么不呢:
$ dumpMyGlobal() {
. /dev/shm/foo
printf "%8s " ${!MYGLOBAL[@]}
echo
printf "%8s " ${MYGLOBAL[@]}
echo
}
$ dumpMyGlobal
l15m uptime crt procs lpid active rand idle l05m
counter l01m
0.42 13815568.06 95 554 649 1 31135 21437004.95
0.38 73 0.50
$ dumpMyGlobal
l15m uptime crt procs lpid active rand idle l05m
counter l01m
0.41 13815593.29 120 553 727 2 3849 21437046.41
0.35 98 0.33
或
$ dumpMyGlobal() {
. /dev/shm/foo
sort <(
paste <(
printf "%-12s\n" ${!MYGLOBAL[@]}
) <(printf "%s\n" ${MYGLOBAL[@]})
)
}
$ dumpMyGlobal
active 1
counter 297
crt 337
idle 21435798.86
l01m 0.40
l05m 0.44
l15m 0.45
lpid 30418
procs 553
rand 7328
uptime 13814820.80
最后getMyGlobalVar
函数
$ declare -A MYGLOBALLOCK # snapshot variable
$ getMyGlobalVar () {
local i sync=false
[ "$1" == "--sync" ] && shift && sync=true
if [ -z "${MYGLOBALLOCK[*]}" ] || $sync; then
. /dev/shm/foo
for i in ${!MYGLOBAL[@]}
do
MYGLOBALLOCK[$i]=${MYGLOBAL[$i]}
done
fi
echo ${MYGLOBALLOCK[$1]}
}
需要--sync
标记才能重新读取 rendez-vous ,以便让您查看来自同一快照的每个字段。
$ getMyGlobalVar --sync idle
362084.12
$ getMyGlobalVar idle
362084.12
$ getMyGlobalVar rand
1533
$ getMyGlobalVar rand
1533
$ getMyGlobalVar --sync rand
43256
$ getMyGlobalVar idle
362127.63
有一个完整的示例:bash_ipc_demo或bash_ipc_demo.shz
您可以使用:
wget http://f-hauri.ch/vrac/bash_ipc_demo
source bash_ipc_demo
back_func help
Usage: back_func [-q] [start [-g N]|stop|restart|status|get|dump|help]
-q Quiet
-g N Start daemon, setting uptime_useGraph to N values
back_func status
Background loop function is not running.
back_func start -g 3600
back_func status
Background loop function (19939) is running.
从那里,如果您在另一个终端中source bash_ipc_demo
,您可以将列表添加到其中。
你甚至可以关闭第一个终端。
back_func dump
backFunc_count 13
backFunc_now 2016-04-06 17:03:19
backFunc_pid 19939
backFunc_running yes
backFunc_start 2016-04-06 17:03:07
cpu_numcores 2
loadavg_15min 0.44
loadavg_1min 0.66
loadavg_5min 0.54
loadavg_active 1
loadavg_last_pid 20005
loadavg_process 650
random 3714432
uptime_graph_val 3600
uptime_idle 425499.43
uptime_up 495423.53
uptime_usage1sec 9.90
uptime_usage 57.06
uptime_useGraph 57.06 8.91 7.50 6.93 12.00 9.41 7.84 9.90 7.50 11.88 7.92 9.31
9.90
然后,您可以获得一个值
back_func get backFunc_pid newVar
echo $newVar
19939
或构建 quick cpu 图表:
lastMinuteGraph -p -o /tmp/lastMinuteGraph.png -W 640 -H 220
这将呈现640x220 PNG图形,其值为uptime_graph_val
。
在这种情况下,back_func start
从-g 3600
调用了更多
超过一小时,图形显示在640列上查看3600,在220行上显示0-100%:
( Nota:命令最初命名为lastMinuteGraph
,因为它只存储了60个值的第一个版本,现在使用 uptime_graph_val
要存储的值。因为我使用了-g 3600
参数,所以此命令可以命名为lastHourGraph
)。
然后:
back_func stop
back_func get backFunc_end
2019-01-02 16:35:00
答案 1 :(得分:10)
根据Bash手册here,
如果命令由控制操作符'&amp;'终止,则shell在子shell中异步执行命令。
由于在子shell中运行的进程无法修改父shell的环境,我想你想要做的只能通过临时文件/命名管道来实现。或者你可以重新考虑你的方法。
答案 2 :(得分:3)
如果主进程(让我们称之为main.sh)是另一个周期性运行的bash脚本,那么你可以简单地让另一个脚本(让我们称之为other.sh)将值写入文件(让我们调用这个文件值) .SH)。
other.sh
#! /bin/bash
echo "SOME_VAR=42" > /tmp/value.sh
<强> main.sh 强>
#! /bin/bash
. /tmp/value.sh
# Now you can use SOME_VAR