web-dev-qa-db-ja.com

bashバックグラウンドプロセスはグローバル変数を変更します

グローバル変数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」の結果を取得するにはどうすればよいですか?つまり、バックグラウンドプロセスの変更をメインプロセスに戻すことができます。

28
algosolo

2019をアップグレード

_bash_ipc_demo_で遊んで、補完とグラフジェネレーターを追加します。

ランデブー

通信できる2つの独立したプロセスが必要な場合は、両方のプロセスが到達できる場所にrendez-vousを配置する必要があります。

これは、単純なファイル、FIFOパイプ、UNIXソケット、TCPソケット、またはその他(Rexxポート)の場合があります。

bash およびその他 シェル

Bashには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]}
}
_

同じsnapshotから各フィールドを確認できるようにするには、再読み取りに_--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 
_

次に、1つの値を取得できます

_back_func get backFunc_pid newVar
echo $newVar 
19939
_

またはquick cpグラフを作成します:

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

これにより、_uptime_graph_val_値を持つ640x220PNGグラフィックがレンダリングされます。この場合、_back_func start_が_-g 3600_で1時間以上呼び出されたため、グラフィックは640列で3600ピーク、220行で0-100%を示しています。

LastHourGraph

Nota:コマンドは元々lastMinuteGraphという名前でした。これは60個の値を格納したばかりの最初のバージョンでしたが、現在は_uptime_graph_val_の値の数をstore。_-g 3600_引数を使用したので、このコマンドはlastHourGraph)という名前にすることができます。

次に:

_back_func stop  
back_func get backFunc_end
2019-01-02 16:35:00
_
21
F. Hauri

Bashのマニュアルによると ここ

コマンドが制御演算子「&」によって終了した場合、シェルはサブシェルでコマンドを非同期的に実行します。

また、サブシェルで実行されるプロセスは親シェルの環境を変更できないため、実行しようとしていることは一時ファイル/名前付きパイプを介してのみ可能であると思います。または、アプローチを再考することもできます。

10
doubleDown

メインプロセス(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
3
ct_