bash后台进程修改全局变量 [英] bash background process modify global variable

查看:24
本文介绍了bash后台进程修改全局变量的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个全局的 var foo="some value" 和一个后台进程 back_func,我想让后台进程访问 $foo 并修改它的值,这可以被主进程看到.它类似于以下内容:

#!/bin/bash富=0功能 back_func {foo=$(($foo+1))回声返回$ foo"}(back_func) &回声全球$ foo"

上面脚本的结果是

全局 0返回 1

如何得到global和back都是'1'的结果?即后台进程的修改可以返回到主进程.

解决方案

升级2019

使用 bash_ipc_demo 添加完成和图形生成器.

会合

如果你想有两个可以通信的独立进程,你必须在两个进程都可以到达的地方放置一个 rendez-vous.

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

和其他

Bash 没有与 rexx 端口等效的端口,因此有一个使用会合文件的小示例(在我的 Linux 上).

我正在使用共享内存 /dev/shm,以减少磁盘负载.

简单的计数器示例

$ back_func() {而:;做echo $(($(/dev/shm/foo;睡觉 .3;完毕;}

让我们玩

$ echo 1 >/dev/shm/foo$ back_func &$ 回声 $(

比现在停止:

$ fgback_func^C

$ kill $!$[1]+ 终止的 back_func

多个变量

对于有很多变量,可以通过一种很好的方式:

$ back_func() {声明 -A MYGLOBAL本地变量尽管 :;做((MYGLOBAL["counter"]++))IFS=/读取 -a vars <<<<$(/dev/shm/foo睡觉 1完毕}

然后

$ back_func &[1] 27429$ ./dev/shm/foo$ 回声 ${MYGLOBAL['counter']}5$ 回声 ${MYGLOBAL['lpid']}27432

从那里开始,为什么不呢:

$dumpMyGlobal() {./dev/shm/fooprintf "%8s " ${!MYGLOBAL[@]}回声printf "%8s " ${MYGLOBAL[@]}回声}$dumpMyGloball15m 正常运行时间 crt procs lpid active rand idle l05m柜台 l01m0.42 13815568.06 95 554 649 1 31135 21437004.950.38 73 0.50$dumpMyGloball15m 正常运行时间 crt procs lpid active rand idle l05m柜台 l01m0.41 13815593.29 120 553 727 2 3849 21437046.410.35 98 0.33

$dumpMyGlobal() {./dev/shm/foo排序 <(粘贴 <(printf "%-12s
" ${!MYGLOBAL[@]}) <(printf "%s
" ${MYGLOBAL[@]}))}$dumpMyGlobal活跃 1柜台 297337闲置21435798.86l01m 0.40l05m 0.44l15m 0.45脂30418过程 553兰特 7328正常运行时间 13814820.80

通过快照获取变量

最后是 getMyGlobalVar 函数

$ declare -A MYGLOBALLOCK # 快照变量$getMyGlobalVar () {本地同步=假[$1"==--同步"] &&班次&&同步=真如果 [ -z "${MYGLOBALLOCK[*]}" ] ||$同步;然后./dev/shm/foo对于我在 ${!MYGLOBAL[@]}做MYGLOBALLOCK[$i]=${MYGLOBAL[$i]}完毕菲回声 ${MYGLOBALLOCK[$1]}}

将需要 --sync 标志来重新读取 rendez-vous 以便让您从同一个快照中查看每个字段.

$ getMyGlobalVar --sync idle362084.12$ getMyGlobalVar 空闲362084.12$ getMyGlobalVar 兰特1533$ getMyGlobalVar 兰特1533$ getMyGlobalVar --sync rand43256$ getMyGlobalVar 空闲362127.63

完整可用的演示:

有一个完整的示例:

(注意: 命令最初被命名为 lastMinuteGraph,因为它的第一个版本只存储了 60 个值,现在这个使用 uptime_graph_val 用于存储值的数量.由于我使用了 -g 3600 参数,因此此命令可以命名为 lastHourGraph).

那么:

back_func 停止back_func 获取 backFunc_end2019-01-02 16:35:00

I have a global var foo="some value" and a background process back_func, I want to the background process to access $foo and modify its value, which can be seen by the main process. It's something like the following:

#!/bin/bash
foo=0

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

(back_func) &
echo "global $foo"

The result of the above script is

global 0
back 1

How could I get the result of global and back are both '1'?, i.e. the back ground process's modification can return back to the main process.

解决方案

Upgrade 2019

Playing with bash_ipc_demo adding completion and a graph generator.

Rendez-vous

If you wanna have two independant process which could communicate, you have to place a rendez-vous somewhere both process can reach.

This could be a simple file, a fifo pipe, a unix socket, a TCP socket or maybe else (Rexx port).

and other

Bash don't have a equivalent to rexx port, so there is a little sample, using a rendez-vous file, that work (on my Linux).

I'm using shared memory /dev/shm, to reduce disk load.

Simple counter sample

$ back_func() {
    while :;do
        echo $(($(</dev/shm/foo)+1)) >/dev/shm/foo;
        sleep .3;
      done;
}

Let play

$ echo 1 >/dev/shm/foo
$ back_func &

$ echo $(</dev/shm/foo)
4

$ echo $(</dev/shm/foo)
21

Than stop now:

$ fg
back_func
^C

or

$ kill $!
$
[1]+  Terminated              back_func

More than one variables

For having many vars, there could by a nice manner:

$ 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
}

Then

$ back_func &
[1] 27429
$ . /dev/shm/foo
$ echo ${MYGLOBAL['counter']}
5
$ echo ${MYGLOBAL['lpid']}
27432

and from there, why not:

$ 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 

or

$ dumpMyGlobal() {
    . /dev/shm/foo
    sort <(
        paste <(
            printf "%-12s
" ${!MYGLOBAL[@]}
          ) <(printf "%s
" ${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

Get variable with snapshot

and finally getMyGlobalVar function

$ 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]}
}

will require --sync flag for re-reading rendez-vous in order to let you look about each fields from the same snapshot.

$ getMyGlobalVar --sync idle
362084.12

$ getMyGlobalVar idle
362084.12

$ getMyGlobalVar rand
1533

$ getMyGlobalVar rand
1533

$ getMyGlobalVar --sync rand
43256

$ getMyGlobalVar idle
362127.63

Full useable demo:

There is a full sample: bash_ipc_demo or bash_ipc_demo.shz

You could use by:

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.

From there, if you source bash_ipc_demo in another terminal, you could do the list into them.

You could even close the first terminal.

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 

Then, you could get one value

back_func get backFunc_pid newVar
echo $newVar 
19939

or build a quick cpu graph:

lastMinuteGraph -p -o /tmp/lastMinuteGraph.png -W 640 -H 220

This will render a 640x220 PNG graphic, with uptime_graph_val values. In this case, as back_func start was invoked with -g 3600 from more than one hour, graphic show 3600 peek on 640 columns and 0-100% on 220 lines:

(Nota: Command was originaly named lastMinuteGraph as 1st version of this just stored 60 values, now this use uptime_graph_val for number of values to store. As I've used -g 3600 argument, this command could by named lastHourGraph).

Then:

back_func stop  
back_func get backFunc_end
2019-01-02 16:35:00

这篇关于bash后台进程修改全局变量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆