J'ai un programme qui produit des informations utiles sur stdout
mais lit également stdin
. Je veux rediriger sa sortie standard vers un fichier sans rien fournir en entrée standard. Jusqu'ici, tout va bien: je peux faire:
program > output
et ne fais rien dans le tty.
Cependant, le problème est que je veux le faire en arrière-plan. Si je fais:
program > output &
le programme sera suspendu ("suspendu (entrée tty)").
Si je fais:
program < /dev/null > output &
le programme se termine immédiatement car il atteint EOF.
Il me semble que ce dont j'ai besoin, c'est de pénétrer dans program
quelque chose qui ne fait rien pendant une durée indéterminée et qui ne lit pas stdin
. Les approches suivantes fonctionnent:
while true; do sleep 100; done | program > output &
mkfifo fifo && cat fifo | program > output &
tail -f /dev/null | program > output &
Cependant, tout cela est très moche. Il doit y avoir un moyen élégant, en utilisant les utilitaires Unix standard, de "ne rien faire, indéfiniment" (pour paraphraser man true
). Comment pourrais-je y parvenir? (Mes principaux critères d'élégance sont les suivants: pas de fichiers temporaires, pas de files d'attente trop fréquentes ni de réveils périodiques; pas de services publics exotiques; aussi court que possible.)
su -c 'program | output &' user
. Je suis sur le point de poser une question similaire avec la création de tâches en arrière-plan en tant que méthode acceptable pour gérer un "service / démon". J'ai aussi remarqué que je ne pouvais pas redirigerSTDERR
sans rediriger égalementSTDOUT
. La solution où programmeA envoieSTDOUT
à programmeBSTDIN
, puis redirigeSTDERR
vers un fichier journal:programA 2> /var/log/programA.log | programB 2> /var/log/programB.log 1> /dev/null
su -c 'while true; do true; done | cat > ~/output &' user
?1<&-
il va quitter votre programme?Réponses:
Dans les shells qui les prennent en charge (ksh, zsh, bash4), vous pouvez commencer en
program
tant que co-processus .ksh
:program > output |&
zsh
,bash
:coproc program > output
Cela commence
program
en arrière-plan avec son entrée redirigée depuis un fichierpipe
. L'autre extrémité du tuyau est ouverte à la coque.Trois avantages de cette approche
program
meurt (utilisez-lewait
pour l'attendre)program
se terminera (obtiendrezeof
son stdin si le shell se ferme).la source
tail -f /dev/null
n'est pas idéal car il lit toutes les secondes/dev/null
(les versions actuelles de GNU tail sur Linux utilisant inotify il y a en fait un bogue ).sleep inf
ou son équivalent plus portablesleep 2147483647
sont de meilleures approches pour une commande qui reste là sans rien faire d’IMO (note quisleep
est construite dans quelques shells commeksh93
oumksh
).Je ne pense pas que vous allez devenir plus élégant que le
que vous avez déjà suggéré (en supposant que cela utilise inotify en interne, il ne devrait pas y avoir d’interrogation ni de réveil, de sorte qu’autre chose qu’elle soit étrange, elle devrait être suffisante).
Vous avez besoin d'un utilitaire qui s'exécutera indéfiniment, gardera son stdout ouvert, mais n'écrira rien sur stdout et ne se fermera pas lorsque son stdin sera fermé. Quelque chose comme
yes
écrit en fait sur stdout.cat
quittera quand son stdin sera fermé (ou ce que vous redirigerez dedans est fait). Je pense que celasleep 1000000000d
pourrait marcher, maistail
c'est nettement mieux. Ma boîte Debian a unetailf
commande qui raccourcit légèrement.Sous un angle différent, que diriez-vous de lancer le programme
screen
?la source
tail -f /dev/null
mieux l' approche et la trouve suffisamment élégante, car l'utilisation de la commande correspond assez bien à l'objectif recherché.strace tail -f /dev/null
il semble quetail
utiliseinotify
et que redémarrages se produisent dans des cas comme stupidessudo touch /dev/null
. Il est regrettable qu'il ne semble pas y avoir de meilleure solution ... Je me demande quel serait le bon système à utiliser pour mettre en œuvre une meilleure solution.pause
, mais il n'est pas exposé directement à une interface shell.screen
, mais il s'agit d'exécuter plusieurs occurrences du programme à partir d'un script shell à des fins de test. L'utilisationscreen
est donc un peu excessive.sleep infinity
est la solution la plus claire que je connaisse.Vous pouvez utiliser
infinity
carsleep
accepte un nombre à virgule flottante * , qui peut être décimal , hexadécimal , infini ou NaN , selonman strtod
.* Cela ne fait pas partie de la norme POSIX et n’est donc pas aussi portable
tail -f /dev/null
. Cependant, il est supporté par GNU coreutils (Linux) et BSD (utilisé sur Mac) (apparemment pas supporté par les versions plus récentes de Mac - voir les commentaires).la source
sleep infinity
également fonctionner sur BSD et Mac .sleep infinity
attend 24 jours au maximum; qui a raisonsleep
utilitaire n'est pas limité à 24 jours ; ce n'est que le premier appel système qui dort pendant 24 jours, et il en fera plus par la suite. Voir mon commentaire ici: stackoverflow.com/questions/2935183/…Oui,
2^31-1
c'est un nombre fini, et il ne fonctionnera pas éternellement , mais je vous donnerai 1 000 $ lorsque le sommeil aura finalement expiré. (Indice: l'un de nous sera mort d'ici là.)la source
sleep 2147483647d
...Vous pouvez créer un binaire qui fait exactement cela avec:
la source
Voici une autre suggestion utilisant les utilitaires Unix standard, pour "ne rien faire, indéfiniment" .
Cela déclenche un shell qui est immédiatement envoyé
SIGSTOP
, ce qui suspend le processus. Ceci est utilisé comme "entrée" dans votre programme. Le complément deSIGSTOP
isSIGCONT
, c’est-à-dire que si vous savez que le shell a le PID 12345, vous pouvezkill -CONT 12345
le faire continuer.la source
Sous Linux, vous pouvez faire:
Sous Linux, l’ouverture de / dev / fd / x, où x est un descripteur de fichier situé à la fin de l’écriture d’un pipe, vous donne la fin de la lecture du tuyau, donc la même chose que sur le stdin du programme. Donc, fondamentalement,
read
ne reviendra jamais, car la seule chose qui peut écrire dans ce canal est elle-même etread
ne génère rien.Cela fonctionnera également sur FreeBSD ou Solaris, mais pour une autre raison. Là, en ouvrant / dev / fd / 1, vous obtenez la même ressource que celle que vous attendez sur fd 1 et comme le font la plupart des systèmes, à l’exception de Linux, donc en fin d’écriture. Cependant, sous FreeBSD et Solaris, les tuyaux sont bidirectionnels. Donc tant qu’il
program
n’écrit pas dans son stdin (aucune application ne le fait),read
rien n’est lu de cette direction du tuyau.Sur les systèmes où les canaux ne sont pas bidirectionnels, il y
read
aura probablement une erreur lors de la tentative de lecture à partir d'un descripteur de fichier en écriture seule. Notez également que tous les systèmes ne l’ont pas/dev/fd/x
.la source
x
bash; plus loin avec zsh vous pouvez simplement faireread
et ça marche (bien que je ne comprenne pas pourquoi!). Cette astuce est-elle spécifique à Linux ou fonctionne-t-il sur tous les systèmes * nix?read
seul, il lira de stdin. Donc, si c'est le terminal, il lira ce que vous tapez jusqu'à ce que vous appuyiez sur Entrée.read
et cela fonctionne ?read | program > output
et cela fonctionne de la même manière que ce que vous avez suggéré. (Et je ne comprends pas pourquoi.)La
read
solution de Stéphane Chazelas fonctionne également sur Mac OS X si un fichier de lecture est ouvert/dev/fd/1
.Pour pouvoir tuer
tail -f /dev/null
dans un script (avec SIGINT, par exemple), il est nécessaire de mettre en arrière-plan latail
commande etwait
.la source
Rediriger en
/dev/zero
tant qu'entrée standard!la source