J'ai besoin de faire une fonction dans un script ZSH Shell, appelé par substitution de commande, communiquer à l'état des appels ultérieurs à la même substitution de commandement.
Quelque chose comme les variables statiques de C dans des fonctions (très grossièrement parlant).
Pour ce faire, j'ai essayé 2 approches - une utilisation des coprocesseurs et une utilisation des tuyaux nommés. L'approche de Tipes nommée, je ne peux pas me rendre au travail - ce qui est frustrant parce que je pense que cela résoudra le seul problème que j'ai avec des coprocesseurs - c'est-à-dire si j'entre dans une nouvelle coquille ZSH du terminal, je ne semble pas être capable de voir la coproc de la session ZSH parent.
J'ai créé des scripts simplifiés pour illustrer le problème ci-dessous - si vous êtes curieux de savoir ce que j'essaie de faire - il s'agit d'une nouvelle composante d'état au thème Bullet-train ZSH, qui sera appelé par la commande substituée build_promppt ( ) fonctionne ici: https://github.com/caiogondim/bullet-train.zsh/blob/d60f62c34b3D9253292EB8BE81FB46FA65D8F048/BulleT-Train.zsh-theme#L692
Script 1 - Coprocesseurs
#!/usr/bin/env zsh
coproc cat
disown
print 'Hello World!' >&p
call_me_from_cmd_subst() {
read get_contents <&p
print "Retrieved: $get_contents"
print 'Hello Response!' >&p
print 'Response Sent!'
}
# Run this first
call_me_from_cmd_subst
# Then comment out the above call
# And run this instead
#print "$(call_me_from_cmd_subst)"
# Hello Response!
read finally <&p
echo $finally
Script 2 - Tuyaux nommés
#!/usr/bin/env zsh
rm -rf /tmp/foo.bar
mkfifo /tmp/foo.bar
print 'Hello World!' > /tmp/foo.bar &
call_me_from_cmd_subst() {
get_contents=$(cat /tmp/foo.bar)
print "Retrieved: $get_contents"
print 'Hello Response!' > /tmp/foo.bar &!
print 'Response Sent!'
}
# Run this first
call_me_from_cmd_subst
# Then comment out the above call
# And run this instead
#print "$(call_me_from_cmd_subst)"
# Hello Response!
cat /tmp/foo.bar
Dans leurs formes initiales, ils produisent tous deux exactement la même sortie:
$ ./named-pipe.zsh
Retrieved: Hello World!
Response Sent!
Hello Response!
$ ./coproc.zsh
Retrieved: Hello World!
Response Sent!
Hello Response!
Maintenant, si j'allume le script Coproc pour appeler à l'aide de la substitution de commande, rien ne change:
# Run this first
#call_me_from_cmd_subst
# Then comment out the above call
# And run this instead
print "$(call_me_from_cmd_subst)"
C'est la lecture et l'écriture à la coprocession de la sous-processus créée par la substitution de commandement ne provoque aucun problème. J'étais un peu surpris par cela - mais c'est une bonne nouvelle!
Mais si je fais le même changement dans les exemples de pipi nommés, les blocs de script - sans sortie. Essayer de jauger pourquoi je l'ai couru avec zsh -x
, donnant:
+named-pipe.zsh:3> rm -rf /tmp/foo.bar
+named-pipe.zsh:4> mkfifo /tmp/foo.bar
+named-pipe.zsh:15> call_me_from_cmd_subst
+call_me_from_cmd_subst:1> get_contents=+call_me_from_cmd_subst:1> cat /tmp/foo.bar
+named-pipe.zsh:5> print 'Hello World!'
+call_me_from_cmd_subst:1> get_contents='Hello World!'
+call_me_from_cmd_subst:2> print 'Retrieved: Hello World!'
+call_me_from_cmd_subst:4> print 'Response Sent!'
Il me semble que le sous-processus créé par la substitution de commande ne se termine pas tandis que la ligne suivante ne s'est pas terminée (j'ai joué avec l'utilisation de &
, &!
, et disown
ici sans changement de résultat).
print 'Hello Response!' > /tmp/foo.bar &!
Pour démontrer cela, je peux tirer manuellement un chat pour lire la réponse:
$ cat /tmp/foo.bar
Hello Response!
Le script attend maintenant la commande finale du chat car il n'y a rien dans le tuyau à lire.
Mes questions sont:
zsh
) dans la console, je ne peux plus y accéder (en fait, je peux créer Un nouveau Coproc qui fonctionnera indépendamment de son parent et de sa sortie et continuez à utiliser les parents!).Expliquer ce que je veux dire dans 2 et 3:
$ coproc cat
[1] 24516
$ print -p test
$ read -ep
test
$ print -p test_parent
$ zsh
$ print -p test_child
print: -p: no coprocess
$ coproc cat
[1] 28424
$ disown
$ print -p test_child
$ read -ep
test_child
$ exit
$ read -ep
test_parent
Je ne peux pas voir la coprocession de l'intérieur de l'enfant ZSH, mais je peux le voir à l'intérieur d'une sous-processus de substitution de commandement?
Enfin, j'utilise Ubuntu 18.04:
$ zsh --version
zsh 5.4.2 (x86_64-ubuntu-linux-gnu)
Une très légère modification de votre code fonctionne comme prévu:
#!/usr/bin/env zsh
rm -rf /tmp/foo.bar
mkfifo /tmp/foo.bar
print 'Hello World!' > /tmp/foo.bar &
call_me_from_cmd_subst() {
get_contents=$(cat /tmp/foo.bar)
print "Retrieved: $get_contents"
(print 'Hello Response!' > /tmp/foo.bar &!) >/dev/null
print 'Response Sent!'
}
# Run this first
#call_me_from_cmd_subst
# Then comment out the above call
# And run this instead
print "$(call_me_from_cmd_subst)"
# Hello Response!
cat /tmp/foo.bar
Exécution de ces rendements attendus:
Retrieved: Hello World!
Response Sent!
Hello Response!
Je ne suis pas tout à fait sûr pourquoi ceci est - il apparaît comme si ZSH croit que l'impression à la FIFO pourrait entraîner une sorte de sortie sur stdout?