2012-11-03 17 views
22

我有一个全局的var foo =“some value”和一个后台进程back_func,我想后台进程访问$ foo并修改它的值,这可以在主进程中看到。这是类似以下内容:bash后台进程修改全局变量

#!/bin/bash 
foo=0 

function back_func { 
    foo=$(($foo+1)) 
    echo "back $foo" 
} 

(back_func) & 
echo "global $foo" 

上述脚本的结果是

global 0 
back 1 

我怎么能得到全球的结果和背部都是“1” ?,即回地面过程的修改可以返回到主流程。

+0

是“主进程“另一个bash脚本?它是否会定期重启? –

+0

使用环境变量的动机是什么?信息的传输可以通过一个非常简单的文件来完成。 –

+0

@ct_是主进程是另一个周期性运行的bash脚本。 – algosolo

回答

18

相约

如果你想有两个独立的过程,可以沟通,你有放置一个rendez-vo我们某处都可以到达。

这可能是一个简单的文件,fifo管道,unix套接字,TCP套接字或其他(Rexx端口)。

击不具有相当于REXX端口,所以有一点点样本,使用会合文件,这项工作(在我的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标志重读为了让你看看来自同一快照各个领域相约

$ 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

您可以通过使用:

wget http://f-hauri.ch/vrac/bash_ipc_demo 

source bash_ipc_demo 
back_func help 
Usage: bash [-q] [start|stop|restart|status|get|dump|help] 

back_func status 
Background loop function is not running. 

back_func start 

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_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 

或建立一个最后一分钟图:

back_func get uptime_useGraph vars;path="M0,0";x=0;for y in $vars;do 
    printf -v step "L%.2f,%.2f L%.2f %.2f " $((x++*3)) $y $[3*x] $y 
    path+=" $step" 
    done;path+=" L$((3*x)),0 z";echo "<svg width=\"180\" height=\"100\"> 
     <rect style=\"fill: #DDD;\" width=\"180\" height=\"100\"></rect> 
     <path style=\"fill: #08B;\" transform=\"matrix(1,0,0,-1,0,100)\" 
     d=\"$path\"></path></svg>" | 
    inkscape -z --export-png=lastMinute.png /dev/stdin;eog lastMinute.png 

** (inkscape:22147): WARNING **: Format autodetect failed. The file is being opened as SVG. 
Background RRGGBBAA: ffffff00 
Area 0:0:180:100 exported to 180 x 100 pixels (90 dpi) 
Bitmap saved as: lastMinute.png 

然后:

back_func stop 
back_func get backFunc_end 
2016-04-06 17:16:08 
+0

+1,不知道/ dev/shm /,相当有用 – etuardu

+0

为了好玩,有一个[***压缩bash源文件***](http://f-hauri.ch/ vrac/bash_ipc_demo.shz.txt) –

+0

已将[自己的网站](http://f-hauri.ch/vrac/bash_ipc_demo.txt)更新为***自动完成***和*'lastMinuteGraph' *作为分隔的功能。 –

8

根据该击手册here

如果一个命令由控制运算符“&”终止时,外壳以异步方式执行该命令在一个子shell。

而且由于在子shell中运行的进程不能修改父shell的环境,所以我猜你正在尝试做的只能通过临时文件/命名管道来实现。或者你可以重新思考你的方法。

2

如果主进程(我们称之为main.sh)是另一个周期性运行的bash脚本,那么您可以简单地将其他脚本(我们称之为other.sh)写入文件(我们称之为文件value.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