J'ai un script qui appelle deux commandes:
long_running_command | print_progress
Les long_running_command
empreintes sont un progrès, mais je ne suis pas satisfait. J'utilise print_progress
pour le rendre plus agréable (à savoir, j'imprime la progression en une seule ligne).
Le problème: La connexion d’un tuyau à stdout active également un tampon 4K, le programme d’impression n’obtenant rien… rien… rien… beaucoup … :)
Comment puis-je désactiver le tampon 4K pour le long_running_command
(non, je n'ai pas la source)?
Réponses:
Vous pouvez utiliser la
unbuffer
commande (qui fait partie duexpect
paquet), par exempleunbuffer
se connecte àlong_running_command
via un pseudoterminal (pty), ce qui fait que le système le traite comme un processus interactif; par conséquent, n'utilisez pas la mise en mémoire tampon de 4 kio dans le pipeline qui est la cause probable du retard.Pour les pipelines plus longs, vous devrez peut-être débuffer chaque commande (sauf la dernière), par exemple
la source
expect_unbuffer
et se trouve dans leexpect-dev
paquet, pas dans leexpect
paquetexpect-dev
fournit les deuxunbuffer
etexpect_unbuffer
(le premier est un lien symbolique vers le second). Les liens sont disponibles depuisexpect 5.44.1.14-1
(2009).Une autre façon de peauner ce chat est d'utiliser le
stdbuf
programme, qui fait partie de GNU Coreutils (FreeBSD en possède également un).Cela désactive complètement la mise en mémoire tampon pour les entrées, les sorties et les erreurs. Pour certaines applications, la mise en mémoire tampon des lignes peut être plus appropriée pour des raisons de performances:
Notez que cela ne fonctionne que pour la
stdio
mise en mémoire tampon (printf()
,fputs()
...) pour les applications liées dynamiquement, et uniquement si cette application ne règle pas la mise en mémoire tampon de ses flux standard par elle-même, bien que cela devrait couvrir la plupart des applications.la source
sudo stdbuff … command
œuvres bienstdbuff … sudo command
que non.stdbuf
ne fonctionne pas avectee
, cartee
écrase les valeurs par défaut définies parstdbuf
. Voir la page de manuel destdbuf
.stdbuf
utilise unLD_PRELOAD
mécanisme pour insérer sa propre bibliothèque chargée dynamiquementlibstdbuf.so
. Cela signifie qu'il ne fonctionnera pas avec les types de fichiers exécutables suivants: avec setuid ou les capacités de fichier définies, liées statiquement, sans utiliser la bibliothèque standard. Dans ces cas, il est préférable d'utiliser les solutions avecunbuffer
/script
/socat
. Voir aussi stdbuf avec setuid / capacités .Une autre façon d'activer le mode de sortie avec mise en mémoire tampon de lignes
long_running_command
consiste à utiliser lascript
commande qui exécute votrelong_running_command
pseudo-terminal (pty).la source
script
s'agit d'une commande si ancienne, elle devrait être disponible sur toutes les plates-formes de type Unix.-q
sous Linux:script -q -c 'long_running_command' /dev/null | print_progress
stdin
, ce qui rend impossible l’exécution d’une telle tâchelong_running_command
en arrière-plan, du moins lorsqu’il est lancé depuis un terminal interactif. Pour contourner le problème, j'ai pu rediriger stdin/dev/null
, car monlong_running_command
ne l'utilise passtdin
.Pour
grep
,sed
etawk
vous pouvez forcer la sortie à la ligne tamponne. Vous pouvez utiliser:Force la sortie à être mise en mémoire tampon. Par défaut, la sortie est mise en mémoire tampon de ligne lorsque la sortie standard est un terminal et la mise en mémoire tampon de bloc autrement.
Rendre la ligne de sortie en mémoire tampon.
Voir cette page pour plus d'informations: http://www.perkin.org.uk/posts/how-to-fix-stdio-buffering.html
la source
S'il y a un problème avec la libc qui modifie sa mise en tampon / vidage lorsque la sortie ne va pas à un terminal, vous devriez essayer socat . Vous pouvez créer un flux bidirectionnel entre presque n'importe quel type de mécanisme d'E / S. Un de ceux-ci est un programme forké qui parle à un pseudo tty.
Ce qu'il fait est
Si cela vous donne le même résultat que
long_running_command
, alors vous pouvez continuer avec un tuyau.Edit: Wow Vous n'avez pas vu la réponse du tampon! Eh bien, socat est de toute façon un excellent outil, je pourrais donc laisser cette réponse
la source
socat -u exec:long_running_command,pty,end-close -
iciVous pouvez utiliser
Le problème est que libc mettra le tampon de ligne lorsque stdout à l'écran et le tampon complet lorsque stdout dans un fichier. Mais pas de tampon pour stderr.
Je ne pense pas que ce soit le problème avec le tampon de pipe, tout repose sur la politique de tampon de libc.
la source
zsh
(d’où|&
vient de adapté de csh) etbash
, lorsque vous le faitescmd1 >&2 |& cmd2
, les deux fd 1 et 2 sont connectés à la sortie externe. Cela empêche donc la mise en mémoire tampon lorsque cette sortie externe est un terminal, mais uniquement parce que la sortie ne passe pas par le canal (elleprint_progress
n'imprime donc rien). Donc, c'est la même chose quelong_running_command & print_progress
(sauf que print_progress stdin est un tuyau qui n'a pas d'écrivain). Vous pouvez vérifier avecls -l /proc/self/fd >&2 |& cat
comparé àls -l /proc/self/fd |& cat
.|&
c'est court2>&1 |
, littéralement. Ainsi l'cmd1 |& cmd2
estcmd1 1>&2 2>&1 | cmd2
. Ainsi, les deux signaux 1 et 2 finissent par être connectés au stderr d'origine, et rien ne reste à écrire sur le tuyau. (s/outer stdout/outer stderr/g
dans mon commentaire précédent).Auparavant, et probablement encore, lorsque la sortie standard est écrite dans un terminal, la ligne est mise en mémoire tampon par défaut. Lorsqu'une nouvelle ligne est écrite, la ligne est écrite dans le terminal. Lorsque la sortie standard est envoyée à un canal, celle-ci est entièrement mise en mémoire tampon. Ainsi, les données ne sont envoyées qu'au processus suivant du pipeline lorsque le tampon d'E / S standard est rempli.
C'est la source du problème. Je ne sais pas si vous pouvez faire grand chose pour résoudre ce problème sans modifier le programme écrit dans le tuyau. Vous pouvez utiliser la
setvbuf()
fonction avec l'_IOLBF
indicateur pour passer inconditionnellementstdout
en mode de mise en tampon de ligne. Mais je ne vois pas de moyen facile d'appliquer cela à un programme. Ou bien le programme peut le fairefflush()
aux moments appropriés (après chaque ligne de sortie), mais le même commentaire s’applique.Je suppose que si vous remplaciez le canal par un pseudo-terminal, la bibliothèque d'E / S standard penserait que la sortie est un terminal (car il s'agit d'un type de terminal) et alignera automatiquement le tampon en ligne. C'est une façon complexe de traiter les choses, cependant.
la source
Je sais que c’est une vieille question et que de nombreuses réponses ont déjà été apportées, mais si vous souhaitez éviter le problème de la mémoire tampon, essayez quelque chose du genre:
Cela affichera les journaux en temps réel, les enregistrera également dans le
logs.txt
fichier et le tampon n’affectera plus latail -f
commande.la source
NOTE: If COMMAND adjusts the buffering of its standard streams ('tee' does for example) then that will override corresponding changes by 'stdbuf'.
Je ne pense pas que le problème est avec le tuyau. Il semble que votre processus de longue durée ne vide pas suffisamment son propre tampon. Changer la taille de la mémoire tampon du tuyau serait un hack pour le contourner, mais je ne pense pas que ce soit possible sans reconstruire le noyau - ce que vous ne voudriez pas faire comme un hack, car il affectera probablement beaucoup d'autres processus.
la source
Selon ce post , vous pouvez essayer de réduire le tuyau ulimit à un seul bloc de 512 octets. Cela ne désactivera certainement pas la mise en mémoire tampon, mais bon, 512 octets est bien moins que 4K: 3
la source
Dans la même veine que la réponse de chad , vous pouvez écrire un petit script comme celui-ci:
Ensuite, utilisez cette
scriptee
commande en remplacement detee
.Hélas, je n'arrive pas à faire en sorte qu'une telle version fonctionne parfaitement sous Linux. Cela semble donc être limité aux Unix de type BSD.
Sous Linux, c'est proche, mais vous ne recevez pas votre invite quand elle se termine (jusqu'à ce que vous appuyiez sur entrée, etc.) ...
la source
script
émule un terminal, alors oui, je pense qu'il désactive la mise en mémoire tampon. Il renvoie également chaque caractère qui luicat
est envoyé - c’est pourquoi il est envoyé/dev/null
dans l’exemple. En ce qui concerne le programme en cours d'exécutionscript
, il s'agit d'une session interactive. Je crois que cela ressemble àexpect
cet égard, mais faitscript
probablement partie de votre système de base.tee
est d'envoyer une copie du flux dans un fichier. Où le fichier est-il spécifiéscriptee
?cat
commande partee myfile.txt
et obtenir l’effet souhaité.J'ai trouvé cette solution intelligente:
(echo -e "cmd 1\ncmd 2" && cat) | ./shell_executable
Cela fait l'affaire.
cat
lira des entrées supplémentaires (jusqu’à EOF) et les transmettra au tube après que leecho
a placé ses arguments dans le flux d’entrée deshell_executable
.la source
cat
ne voit pas la sortie de laecho
; vous exécutez simplement deux commandes dans un sous-shell et la sortie des deux est envoyée dans le canal. La deuxième commande du sous-shell ('cat') lit à partir du parent / stdin externe, c’est pourquoi cela fonctionne.Selon cela, la taille de la mémoire tampon du tube semble être définie dans le noyau et vous obligerait à recompiler votre noyau pour le modifier.
la source