113 votes

Puis-je envoyer du texte sur le STDIN d'un processus actif en cours d'exécution dans une session écran ?

J'ai un processus serveur qui tourne depuis longtemps dans une session écran sur mon serveur Linux. Il est un peu instable (et malheureusement pas mon logiciel, donc je ne peux pas réparer cela !), donc je veux script un redémarrage nocturne du processus pour aider la stabilité. La seule façon de lui faire faire un arrêt gracieux est d'aller sur le processus d'écran, de passer à la fenêtre dans laquelle il s'exécute et de saisir la chaîne "stop" sur sa console de contrôle.

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

110voto

Tim Howland Points 5705

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é depuis longtemps.

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

Vous pouvez l'utiliser pour afficher des messages sur le tty où un programme est en cours d'exécution, mais cela ne vous permet 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

56voto

Tim Howland Points 5705

Solution basée sur l'écran

Démarrez le serveur comme ceci :

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

écran démarrera en mode détaché, donc si vous voulez voir ce qui se passe, exécutez :

# 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 d'une saisie de texte sur un écran détaché de la Unix et Linux site de la fratrie)

Explication des paramètres :

-d -m
  Écran de démarrage en détaché mode. Cela crée une nouvelle session mais ne s'y attache pas. Ceci est utile pour les scripts de démarrage du système.

-S nom de la session
  Définissez le nom de la nouvelle session à nom de la session .

-r [ pid.tty.host ]
-r propriétaire de la session /[ pid.tty.host ]
  Reprendre une session d'écran détachée.

-p numéro_ou_nom |-|=|+
  Présélectionner une fenêtre. Ceci est utile lorsque vous voulez vous rattacher à une fenêtre spécifique ou que vous voulez envoyer une commande via la fonction -X à une fenêtre spécifique.

-X
  Envoyer la commande spécifiée à une session d'écran en cours, par exemple stuff.

stuff [ chaîne de caractères ]
  Remplir la corde chaîne de caractères dans le tampon d'entrée de la fenêtre actuelle. C'est comme le paste mais avec beaucoup moins de frais généraux. Sans paramètre, screen demandera une chaîne à remplir. Vous ne pouvez pas coller de grands tampons avec la commande stuff commandement.

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, exécutez :

# 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 [ -AdDEPX ] [ -c répertoire de départ ] [ -e environnement ] [ -f drapeaux ] [ -F format ] [ -n nom de la fenêtre ] [ -s nom de la session ] [ -t nom-groupe ] [ -x largeur ] [ -y hauteur ] [ Shell-commande ]
(alias : new )
  Créer une nouvelle session avec le nom nom de la session .
  La nouvelle session est attachée au terminal courant sauf si -d est donné. nom de la fenêtre et Shell-commande sont le nom et la commande Shell à exécuter dans la fenêtre initiale.

send-keys [ -FHlMRX ] [ -N nombre de répétitions] [ -t volet cible ] clé
(alias : send )
  Envoyer une ou plusieurs touches à une fenêtre. Chaque argument clé est le nom de la clé (telle que 'C-a' ou 'NPage') à envoyer ; si la chaîne n'est pas reconnue comme une clé, elle est envoyée comme une série de caractères. Tous les arguments sont envoyés séquentiellement, du premier au dernier.
  Le site -l désactive la recherche de noms de clés et traite les clés comme des caractères UTF-8 littéraux. L'option -H s'attend à ce que chaque touche soit un nombre hexadécimal pour un caractère ASCII.

23voto

maratbn Points 171

Il est possible d'envoyer du texte d'entrée à un processus en cours d'exécution sans exécuter la fonction screen ou tout autre utilitaire fantaisiste. 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. Envoi du texte d'entrée via le fichier normal write ne fera pas en sorte que le processus reçoive le texte. En effet, cette méthode ne fera qu'ajouter du texte à ce "fichier", mais ne déclenchera pas la lecture des octets par le processus.

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

Cette question est abordée 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 originale posée il y a presque 9 ans, la tâche cron devrait exécuter un petit utilitaire script / programme similaire aux exemples que les gens ont écrit pour cette autre question, qui enverrait la chaîne "stop". \n "à ce processus de serveur dans la question, en envoyant chacun des 5 octets par l'intermédiaire d'un message IOCTL opération de type TIOCSTI .

Bien sûr, cela ne fonctionnera que sur les systèmes qui supportent l'option TIOCSTI IOCTL type d'opération (comme Linux), et seulement à partir de l'option root car ces "fichiers" sous /proc/ sont "possédés" par root .

9voto

sicvolo Points 51

Il existe une solution plus élégante qui permet d'éviter l'utilisation des éléments suivants tail -f et les boucles éternelles qui gaspillent les ressources du système.

  • Tout d'abord, créez un tube nommé pour acheminer STDIN : mkfifo /data/in .

  • Puis bloquez-le pour l'écriture, afin qu'il ne soit pas fermé lorsque votre processus lira tout le contenu actuel : sleep infinity > /data/in & . Dormir pour toujours est mieux que tailf -f /dev/null parce que tailf utilise les ressources inotify et sera déclenché à chaque fois qu'une application envoie des données vers /dev/null. Vous pouvez voir cela en exécutant strace sur elle. Il est également meilleur que cat > /dev/null & parce que cat sera lui-même déconnecté de STDIN, qui à son tour fermera /data/in .

  • Démarrez votre processus en arrière-plan avec la fonction /data/in fournissant STDIN : application < /data/in & . Cela fonctionne mieux que d'utiliser la tuyauterie de la queue tail -f /data/in | application & car le pipe ne sera terminé que si la queue s'arrête, mais si votre application se plante, le pipe continuera de fonctionner.

  • Arrêtez-vous en attendant que l'application se termine. wait $(pidof application) . Cela n'utilise aucune ressource et si l'application se plante, votre code après l'attente sera exécuté. Vous pouvez ajouter une boucle de redémarrage de l'application autour d'elle si vous le souhaitez.

  • Pour mettre fin à l'application de manière gracieuse, piéger et relayer les signaux du système avec trap 'kill -SIGTERM $(pidof app)' SIGTERM

4voto

Sheila Points 61

Essayez ceci pour commencer :

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

Et ça, pour tuer :

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

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X