bash bash后台进程修改全局变量
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 
原文地址: http://stackoverflow.com/questions/13207292/
Warning: these are provided under cc-by-sa 4.0 license.  You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
bash background process modify global variable
提问by algosolo
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:
我有一个全局变量 foo="some value" 和一个后台进程 back_func,我想让后台进程访问 $foo 并修改它的值,这可以被主进程看到。它类似于以下内容:
#!/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.
怎么才能得到global和back都是'1'的结果,即后台进程的修改可以返回到主进程。
采纳答案by F. Hauri
Upgrade 2019
升级 2019
Playing with bash_ipc_demoadding completion and a graph generator.
玩bash_ipc_demo添加完成和图形生成器。
Rendez-vous
会合
If you wanna have two independant process which could communicate, you have to place a rendez-voussomewhere both process can reach.
如果您想拥有两个可以通信的独立进程,则必须在两个进程都可以到达的地方放置一个集合点。
This could be a simple file, a fifo pipe, a unix socket, a TCP socket or maybe else (Rexx port).
这可能是一个简单的文件、fifo 管道、unix 套接字、TCP 套接字或其他(Rexx 端口)。
bashand other shell
bash和其他shell
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).
Bash 没有与 rexx 端口等效的端口,因此有一个使用集合点文件的小示例(在我的 Linux 上)。
I'm using shared memory/dev/shm, to reduce disk load.
我正在使用共享内存/dev/shm,以减少磁盘负载。
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\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
Get variable with snapshot
使用快照获取变量
and finally getMyGlobalVarfunction
最后getMyGlobalVar运行
$ declare -A MYGLOBALLOCK   # snapshot variable
$ getMyGlobalVar () { 
    local i sync=false
    [ "" == "--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[]}
}
will require --syncflag for re-reading rendez-vousin order to let you look about each fields from the same snapshot.
将需要--sync重新读取集合点的标志,以便让您查看同一快照中的每个字段。
$ 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_demoor bash_ipc_demo.shz
有一个完整的示例:bash_ipc_demo或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_demoin another terminal, you could do the list into them.
从那里,如果您source bash_ipc_demo在另一个终端中,您可以将列表放入其中。
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 cpugraph:
或者构建一个快速的 CPU图表:
lastMinuteGraph -p -o /tmp/lastMinuteGraph.png -W 640 -H 220
This will render a 640x220 PNG graphic, with uptime_graph_valvalues.
In this case, as back_func startwas invoked with -g 3600from more
than one hour, graphic show 3600 peek on 640 columns and 0-100% on 220 lines:
这将渲染一个带有uptime_graph_val值的 640x220 PNG 图形。在这种情况下,正如back_func start在-g 3600一个多小时内调用的那样,图形显示 640 列上的 3600 peek 和 220 行上的 0-100%:
(Nota:Command was originaly named lastMinuteGraphas 1st version of this just stored 60 values, now this use uptime_graph_valfor number of values to store. As I've used -g 3600argument, this command could by named lastHourGraph).
(注意:Command 最初被命名lastMinuteGraph为它的第一个版本,它只存储了 60 个值,现在它uptime_graph_val用于存储值的数量。正如我使用的-g 3600参数,这个命令可以命名为lastHourGraph)。
Then:
然后:
back_func stop  
back_func get backFunc_end
2019-01-02 16:35:00
回答by doubleDown
According to the Bash manual here,
根据此处的 Bash 手册,
If a command is terminated by the control operator ‘&', the shell executes the command asynchronously in a subshell.
如果命令由控制运算符“&”终止,则外壳在子外壳中异步执行命令。
And since a process run in a subshell cannot modify the environment of the parent shell, I guess what you are trying to do is only possible via temp files / named pipes. Or you could rethink your approach.
而且由于在子 shell 中运行的进程无法修改父 shell 的环境,我猜你正在尝试做的事情只能通过临时文件/命名管道来实现。或者你可以重新考虑你的方法。
回答by ct_
If the main process (let's call it main.sh) is another periodically running bash script then you could simply have the the other script (let's call it other.sh) write the value to a file (let's call this file value.sh).
如果主进程(我们称之为 main.sh)是另一个定期运行的 bash 脚本,那么您可以简单地让另一个脚本(我们称之为 other.sh)将值写入一个文件(我们称之为该文件 value.sh) .
other.sh
其他.sh
#! /bin/bash  
echo "SOME_VAR=42" > /tmp/value.sh
main.sh
主文件
#! /bin/bash  
. /tmp/value.sh  
# Now you can use SOME_VAR


