Comment créer un script shell qui envoie une sortie à un processus

11

J'exécute actuellement un programme de console de serveur dans un écran parce que je dois à la fois le lire et parfois envoyer des commandes.

Je voudrais exécuter l'application en tant que démon en arrière-plan (démarrer / arrêter avec init).

Je pourrais tail -fle journal, mais cela ne me laissera pas envoyer d'entrée au processus.

Existe-t-il un moyen de configurer cela afin que je puisse à la fois lire et envoyer des entrées, mais que je puisse toujours les exécuter en arrière-plan?

J'aimerais également pouvoir envoyer des entrées au démon à partir de différents processus (un script shell qui pourrait envoyer une commande "Stop \ n", par exemple).

Bill K
la source
Juste un commentaire à quiconque vient lire ceci - la réponse ici est fantastique. Si vous ne connaissez pas les pipes nommées, je vous recommande fortement de les essayer au moins. En utilisant cela, je pourrais exécuter Minecraft en tant que service et interagir avec la console à partir d'autres scripts en écrivant dans le canal nommé - il devient donc possible d'écrire des scripts pour arrêter le serveur, envoyer des messages aux utilisateurs, etc. tout en analysant le journal de sortie rechercher des lignes clés (telles que l'envoi de messages de chat adressés à un utilisateur sous forme de textes)
Bill K

Réponses:

9

Lire à partir d'un tuyau, écrire dans un fichier

Si vous voulez que le démon lise les entrées produites par un processus arbitraire, vous devez connecter ce processus à un canal. Ici, le processus arbitraire consiste à faire écho à des commandes, et cela va s'exécuter dans un contexte différent. Créez donc un canal nommé (souvent appelé fifo dans les contextes unix).

mkfifo /var/run/daemon.fifo
</var/run/daemon.fifo /path/to/daemond --option >daemon.log

Et écrivez simplement des commandes dans le tuyau:

echo 'FORWARD 10' >/var/run/daemon.fifo
echo 'LEFT 72' >/var/run/daemon.fifo

Cependant, il est peu probable que cela fonctionne: il y a de fortes chances que le démon se termine lorsqu'il voit une fin de fichier sur son entrée standard, ce qui se produit dès la fin du premier processus d'écriture dans le canal. Vous pouvez utiliser tail -fpour éviter ce problème.

</var/run/daemon.fifo tail -c +1 -f | {
  echo $$ >/var/run/daemon.pid
  exec /path/to/daemond --option >daemon.log
}

Avec certaines tailimplémentations, vous pouvez être mordu par mise en mémoire tampon: le tailprocessus attendra jusqu'à ce qu'il ait amassé suffisamment d'octets pour émettre une sortie. Je ne pense pas que ce soit résoluble dans la boîte à outils POSIX; si c'est un problème, utilisez un programme trivial C ou Perl ou Python. Pour autant que je sache, le tailGNU coreutils (que l'on trouve sur Linux et ailleurs) est sûr à cet égard.

Lorsque vous arrêtez le démon, echo >/var/run/daemon.fifole tailprocessus sera arrêté .


Démarrage du programme à l'intérieur de l'écran

Au lieu d'invoquer le démon directement à partir de votre gestionnaire de services (utilisez-vous vraiment juste SysV init, ou quelque chose de plus comme des scripts wrapper ou Upstart?), Invoquez

screen -c daemon.screenrc -L -d -m -S daemon_name /path/to/daemond --option

Étant donné que le démon ne sera pas un processus enfant du gestionnaire de services, vous devez vous assurer d'envoyer un signal au bon processus. Comment faire cela dépend exactement de la façon dont le démon est démarré et par quoi.

Il est techniquement possible d'attacher un processus en cours d'exécution à un terminal, mais il y a un risque que vous plantiez le programme, c'est donc définitivement un système de production.

L' -Loption permet à l'écran d'écrire tout ce qui apparaît dans sa fenêtre dans un fichier. Le nom du fichier est donné daemon.screenrcavec la logfiledirective.

Gilles 'SO- arrête d'être méchant'
la source
En fait, j'aimerais vraiment pouvoir envoyer des messages à son stdin à partir d'un script - c'est peut-être la question que j'aurais dû poser. Actuellement, je suis en train d'exécuter le serveur à partir d'un script et je peux y taper dans un terminal, mais il semble juste qu'il devrait fonctionner en tant que service ...
Bill K
@Bill: Ok, je vois. Ensuite, la première chose qui me vient à l'esprit est une pipe nommée.
Gilles 'SO- arrête d'être méchant'
Je pense que c'est exactement ce que je veux @Gilles! Mais je dois mieux le comprendre. Je vais passer un peu de temps à trier les pages de manuel pour le comprendre - honnêtement, j'en reçois très peu (je comprends la plupart de ce que vous faites et presque rien de la façon dont vous l'avez fait - et je pensais que j'avais en quelque sorte un indice avec ce genre de choses.) Ma théorie n'était pas de se connecter directement au processus, mais de créer un autre script qui a joint son entrée / sortie aux démons o / i pour donner l'impression que la console d'origine fonctionne, mais avec la capacité pour faire l'écho 'FORWARD 10' d'un autre script en même temps.
Bill K
Je pense que j'en reçois beaucoup. Si je le décompose, je comprends maintenant "mkfifo pipe" et "tail -f pipe | command> output", les ai testés et ils fonctionnent. Je pense que la plupart des autres choses que vous aviez étaient des astuces pour le faire fonctionner sur une seule ligne - est-ce que je manque quelque chose de critique?
Bill K
@Bill: Vous pouvez écrire sur le terminal à l'intérieur de l'écran depuis l'extérieur (en utilisant la stuffcommande de l'écran ). Mais vous n'avez pas besoin des frais généraux (traitement, mais surtout cognitifs) d'un terminal ici, un canal est presque suffisant (c'est suffisant avec un petit processus de relais ignorant la fin de fichier). Vous voudrez peut-être expérimenter un peu avec <fifo catou <fifo tail -f | catdans un terminal et echo >fifo; echo >fifodans un autre terminal; Je pense que tout ira bien.
Gilles 'SO- arrête d'être méchant'