web-dev-qa-db-fra.com

Forcer la mise en mémoire tampon de la sortie standard lors de la tuyauterie au tee

Habituellement, stdout est mis en ligne. En d'autres termes, tant que votre argument printf se termine par une nouvelle ligne, vous pouvez vous attendre à ce qu'elle soit imprimée instantanément. Cela ne semble pas tenir quand on utilise un tube pour rediriger vers tee.

J'ai un programme C++, a, qui génère des chaînes, toujours \n - terminé, à stdout.

Lorsqu'il est exécuté par lui-même (./a), Tout s'imprime correctement et au bon moment, comme prévu. Cependant, si je le redirige vers tee (./a | tee output.txt), Il n’affiche rien jusqu’à sa fermeture, ce qui annule le but d’utiliser tee.

Je sais que je pourrais résoudre ce problème en ajoutant un fflush(stdout) après chaque opération d'impression dans le programme C++. Mais existe-t-il un moyen plus propre et plus propre? Y a-t-il une commande que je peux exécuter, par exemple, qui forcerait stdout à être tamponné, même en utilisant un tube?

100
houbysoft

Essayez unbuffer qui fait partie du package expect . Vous l'avez peut-être déjà sur votre système.

Dans votre cas, vous l'utiliseriez comme ceci:

./a | unbuffer -p tee output.txt

(-p est pour le mode pipeline où le tampon de lecture lit à partir de stdin et le passe à la commande dans le reste des arguments)

50
Dennis Williamson

vous pouvez essayer stdbuf

$ stdbuf -o 0 ./a | tee output.txt

(grande) partie de la page de manuel:

  -i, --input=MODE   adjust standard input stream buffering
  -o, --output=MODE  adjust standard output stream buffering
  -e, --error=MODE   adjust standard error stream buffering

If MODE is 'L' the corresponding stream will be line buffered.
This option is invalid with standard input.

If MODE is '0' the corresponding stream will be unbuffered.

Otherwise MODE is a number which may be followed by one of the following:
KB 1000, K 1024, MB 1000*1000, M 1024*1024, and so on for G, T, P, E, Z, Y.
In this case the corresponding stream will be fully buffered with the buffer
size set to MODE bytes.

gardez cela à l'esprit, cependant:

NOTE: If COMMAND adjusts the buffering of its standard streams ('tee' does
for e.g.) then that will override corresponding settings changed by 'stdbuf'.
Also some filters (like 'dd' and 'cat' etc.) dont use streams for I/O,
and are thus unaffected by 'stdbuf' settings.

vous n’exécutez pas stdbuf sur tee, mais sur a; elle ne devrait donc pas vous affecter, sauf si vous définissez la mise en mémoire tampon des flux de a dans la source de a.

De plus, stdbuf est pas POSIX, mais fait partie de GNU-coreutils.

113
c00kiemon5ter

Vous pouvez également essayer d'exécuter votre commande dans un pseudo-terminal à l'aide de la commande script (qui devrait appliquer la sortie en tampon de ligne au canal)!

script -q /dev/null ./a | tee output.txt     # Mac OS X, FreeBSD
script -c "./a" /dev/null | tee output.txt   # Linux

Sachez que la commande script ne renvoie pas le statut de sortie de la commande encapsulée.

26
jon

Vous pouvez utiliser setlinebuf à partir de stdio.h.

setlinebuf(stdout);

Cela devrait changer la mise en mémoire tampon en "ligne mise en mémoire tampon".

Si vous avez besoin de plus de flexibilité, vous pouvez utiliser setvbuf.

18

Si vous utilisez plutôt les classes de flux C++, chaque std::endlest un vidage implicite. En utilisant l’impression de style C, je pense que la méthode que vous avez suggérée (fflush()) est le seul moyen.

2
Kevin Grant