web-dev-qa-db-fra.com

Puis-je envoyer du texte au STDIN d'un processus actif exécuté dans une session écran?

J'ai un processus serveur de longue durée dans une session d'écran sur mon serveur Linux. C'est un peu instable (et malheureusement pas mon logiciel donc je ne peux pas résoudre ce problème!), Je veux donc script un redémarrage nocturne du processus pour aider à la stabilité. La seule façon de le faire faire un arrêt gracieux est d'aller au processus d'écran, de basculer vers la fenêtre dans laquelle il s'exécute et d'entrer la chaîne "stop" sur sa console de contrôle.

Y a-t-il des contorsions de redirection intelligentes que je peux faire pour faire un cronjob envoyer cette commande d'arrêt à une heure fixe chaque jour?

74
Richard Gaywood

Cette réponse ne résout pas le problème, mais elle est laissée ici car plus de 30 personnes l'ont trouvée utile, sinon je l'aurais supprimée il y a longtemps.

Écrire à /proc/*pid of the program*/fd/0. Le sous-répertoire fd contient les descripteurs de tous les fichiers ouverts et le descripteur de fichier 0 est l'entrée standard (1 est stdout et 2 est stderr).

Vous pouvez l'utiliser pour générer des messages sur le tty sur lequel un programme s'exécute, bien qu'il ne vous permette pas d'écrire dans le programme lui-même.

Exemple

Terminal 1:

[ciupicri@hermes ~]$ cat
shows on the tty but bypasses cat

Terminal 2:

[ciupicri@hermes ~]$ pidof cat
7417
[ciupicri@hermes ~]$ echo "shows on the tty but bypasses cat" > /proc/7417/fd/0
88
Cristian Ciupitu

Solution basée sur écran

Démarrez le serveur comme ceci:

# screen -d -m -S ServerFault tr a-z A-Z # replace with your server

( écran démarre en mode détaché, donc si vous voulez voir ce qui se passe, lancez:

# screen -r ServerFault

Contrôlez le serveur comme ceci:

# screen -S ServerFault -p 0 -X stuff "stop^M"
# screen -S ServerFault -p 0 -X stuff "start^M"
# screen -S ServerFault -p 0 -X stuff "^D" # send EOF

(cette réponse est basée sur envoi de texte à un écran détaché depuis le Unix et Linux site frère)

Explication des paramètres:

-d -m
   Start screen in "detached" mode. This creates a new session but doesn't
   attach to it.  This is useful for system startup scripts.
-S sessionname
   When creating a new session, this option can be used to specify a meaningful
   name for the session.
-r [pid.tty.Host]
-r sessionowner/[pid.tty.Host]
   resumes a detached screen session.
-p number_or_name|-|=|+
   Preselect a window. This is useful when you want to reattach to a specific
   window or you want to send a command via the "-X" option to a specific
   window.
-X
   Send the specified command to a running screen session e.g. stuff.

stuff [chaîne]

   Stuff the string string in the input  buffer of the current window.
   This is like the "paste" command but with much less overhead.  Without
   a parameter, screen will Prompt for a string to stuff.

solution basée sur tmux

Démarrez le serveur comme ceci:

# tmux new-session -d -s ServerFault 'tr a-z A-Z' # replace with your server

tmux démarrera en mode détaché, donc si vous voulez voir ce qui se passe, lancez:

# tmux attach-session -t ServerFault

Contrôlez le serveur comme ceci:

# tmux send-keys -t ServerFault -l stop
# tmux send-keys -t ServerFault Enter
# tmux send-keys -t ServerFault -l start
# tmux send-keys -t ServerFault Enter
# tmux send-keys -t ServerFault C-d # send EOF

Explication des paramètres:

 new-session [-AdDP] [-c start-directory] [-F format] [-n window-name] [-s
         session-name] [-t target-session] [-x width] [-y height]
         [Shell-command]
         Create a new session with name session-name.

         The new session is attached to the current terminal unless -d is
         given.  window-name and Shell-command are the name of and Shell
         command to execute in the initial window.  If -d is used, -x and
         -y specify the size of the initial window (80 by 24 if not
         given).

 send-keys [-lR] [-t target-pane] key ...
               (alias: send)
         Send a key or keys to a window.  Each argument key is the name of
         the key (such as `C-a' or `npage' ) to send; if the string is not
         recognised as a key, it is sent as a series of characters.  The
         -l flag disables key name lookup and sends the keys literally.
40
Cristian Ciupitu

Essayez ceci pour commencer:

# screen
# cd /path/to/wd
# mkfifo cmd
# my_cmd <cmd
C-A d

Et cela pour tuer:

# cd /path/to/wd
# echo "stop" > cmd
# rm cmd
4
krissi

Il est possible d'envoyer du texte d'entrée à un processus en cours d'exécution sans exécuter l'utilitaire screen ou tout autre utilitaire sophistiqué. Et cela peut être fait en envoyant ce texte d'entrée au "fichier" d'entrée standard du processus /proc/PID#/fd/0.

Cependant, le texte d'entrée doit être envoyé d'une manière spéciale pour être lu par le processus. L'envoi du texte d'entrée via la méthode de fichier ordinaire write ne provoquera pas la réception du texte par le processus. En effet, cela ne s'ajoutera qu'à ce "fichier", mais ne déclenchera pas le processus de lecture des octets.

Pour déclencher le processus de lecture des octets, il est nécessaire d'effectuer une opération IOCTL de type TIOCSTI pour chaque octet à envoyer. Cela placera l'octet dans la file d'attente d'entrée standard du processus.

Ceci est discuté ici avec quelques exemples en C, Perl et Python:

https://unix.stackexchange.com/questions/48103/construct-a-command-by-putting-a-string-into-a-tty/48221

-

Donc, pour répondre à la question initiale posée il y a près de 9 ans, le travail cron devrait exécuter un petit script/programme utilitaire similaire aux exemples que les gens ont écrits pour cette autre question, qui enverrait la chaîne "stop\n" à ce processus serveur dans la question, en envoyant chacun des 5 octets via une opération IOCTL de type TIOCSTI.

Bien sûr, cela ne fonctionnera que sur les systèmes qui prennent en charge le type d'opération TIOCSTIIOCTL (comme Linux), et uniquement à partir du compte utilisateur root, car ces "fichiers" sous /proc/ appartiennent à root.

3
maratbn

Comme je ne peux pas commenter la réponse la plus acceptée de Cristian Ciupitu (de 2010), je dois mettre cela dans une réponse séparée:

Cette question a déjà été résolue dans ce fil: https://stackoverflow.com/questions/5374255/how-to-write-data-to-existing-processs-stdin-from-external-process

En bref:

Vous devez démarrer votre processus avec un canal pour stdin qui ne se bloque ni ne se ferme lors de l'écriture de l'entrée actuelle. Cela peut être mis en œuvre par une simple boucle sans fin qui sera dirigée vers le processus en question:

$ (while [ 1 ]; do sleep 1; done) | yourProgramToStart

Je peux confirmer que c'est différent de la manière de Krissi d'ouvrir un tuyau qui ne fonctionnait pas dans mon cas. La solution indiquée a plutôt fonctionné.

Vous pouvez ensuite écrire dans le fichier .../fd/0 du processus pour lui envoyer des instructions. Le seul inconvénient est que vous devez également terminer le processus bash qui exécute la boucle sans fin après l'arrêt du serveur.

1
user3471872