bash processus d'arrière-plan de modifier une variable globale
j'ai un mondial var foo="valeur" et d'un processus d'arrière-plan back_func, je veux le processus d'arrière-plan d'accès $foo et modifier sa valeur, qui peut être vu par le processus principal. C'est quelque chose comme ceci:
#!/bin/bash
foo=0
function back_func {
foo=$(($foo+1))
echo "back $foo"
}
(back_func) &
echo "global $foo"
le résultat du script ci-dessus est
global 0
back 1
Comment pourrais-je obtenir le résultat de global et back sont tous les deux '1'?, c'est-à-dire que la modification du processus de fond peut revenir au processus principal.
3 réponses
Rendez-vous
si vous voulez avoir deux processus indépendants qui pourraient communiquer, vous devez placer un rendez-vous quelque part les deux processus peuvent atteindre.
cela pourrait être un simple fichier, un tube fifo, une socket unix, une socket TCP ou peut-être autre (port Rexx).
bash et autres coquille
Bash n'a pas l'équivalent du port rexx, donc il y a un petit échantillon, en utilisant un fichier de rendez-vous, qui fonctionne (sur mon Linux).
j'utilise mémoire partagée /dev/shm
, pour réduire la charge du disque.
Simple compteur de l'échantillon
$ back_func() {
while :;do
echo $(($(</dev/shm/foo)+1)) >/dev/shm/foo;
sleep .3;
done;
}
Laisser jouer
$ echo 1 >/dev/shm/foo
$ back_func &
$ echo $(</dev/shm/foo)
4
$ echo $(</dev/shm/foo)
21
Que de s'arrêter maintenant:
$ fg
back_func
^C
ou
$ kill $!
$
[1]+ Terminated back_func
plus d'une variable
pour avoir beaucoup de Var, il pourrait par une manière agréable:
$ 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
}
puis
$ back_func &
[1] 27429
$ . /dev/shm/foo
$ echo ${MYGLOBAL['counter']}
5
$ echo ${MYGLOBAL['lpid']}
27432
et de là, pourquoi pas:
$ 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
ou
$ 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 avec le snapshot
et enfin getMyGlobalVar
fonction
$ 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[]}
}
nécessite un drapeau --sync
pour relire rendez-vous afin de vous permettre de regarder autour de chaque champ du même snapshot .
$ getMyGlobalVar --sync idle
362084.12
$ getMyGlobalVar idle
362084.12
$ getMyGlobalVar rand
1533
$ getMyGlobalVar rand
1533
$ getMyGlobalVar --sync rand
43256
$ getMyGlobalVar idle
362127.63
Pleinement utilisable, exemple:
il y a un échantillon complet: bash_ipc_demo
vous pouvez utiliser par:
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.
de là, si vous source bash_ipc_demo
dans un autre terminal, vous pouvez faire la liste dans eux.
vous pourriez même fermer le premier 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_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
Alors, vous pourriez obtenir une valeur
back_func get backFunc_pid newVar
echo $newVar
19939
ou construire un dernière minute graphe:
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
puis:
back_func stop
back_func get backFunc_end
2016-04-06 17:16:08
selon le manuel de Bash ici ,
si une commande est terminée par l'opérateur de contrôle ‘&’, le shell exécute la commande de manière asynchrone dans une sous-cellule.
et comme un processus exécuté dans un sous-puits ne peut pas modifier l'environnement du shell parent, je suppose que ce que vous essayez de faire n'est possible que via des fichiers temp / pipes nommées. Ou tu pourrais revoir ton approche.
Si le processus principal (appelons-la main.sh) est un autre périodiquement l'exécution de script bash, alors vous pourriez tout simplement avoir l'autre script (appelons-la other.sh) écrire la valeur dans un fichier (appelons ce fichier 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