2012-11-03 46 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