Od stdout manuálová stránka:
Stream stderr je bez vyrovnávací paměti. Stream stdout je ukládán do vyrovnávací paměti,když ukazuje na terminál .Částečné řádky se neobjeví, dokud nebude zavoláno fflush(3) nebo exit(3) nebo dokud nebude vytištěn nový řádek.
Sečteno a podtrženo:Pokud výstupem není terminál, váš program bude mít standardně standardní výstup v plně vyrovnávací paměti. To v podstatě znamená, že bude vypisovat data ve velkých blocích, nikoli po řádcích, natož po znaku.
Způsoby, jak to obejít:
-
Opravte svůj program:Pokud potřebujete výstup v reálném čase, musíte svůj program opravit. V C můžete použít
fflush(stdout)za každým výstupním příkazem nebosetvbuf()pro změnu režimu ukládání do vyrovnávací paměti standardního výstupu. Pro Python existujesys.stdout.flush()dokonce i některé návrhy zde. -
Použijte nástroj, který umí nahrávat z PTY, spíše než přímo přesměrování stdout. GNU Screen to může udělat za vás:
screen -d -m -L python test.pybyl by začátek. Tím se zaznamená výstup vašeho programu do souboru s názvem
screenlog.0(nebo podobně) ve vašem aktuálním adresáři s výchozím zpožděním 10 sekund a můžete použítscreenpro připojení k relaci, kde běží váš příkaz, za účelem poskytnutí vstupu nebo jeho ukončení. Zpoždění a název souboru protokolu lze změnit v konfiguračním souboru nebo ručně, jakmile se připojíte k relaci na pozadí.
EDIT:
Na většině systémů Linux existuje třetí řešení:Můžete použít LD_PRELOAD proměnná a předinstalovaná knihovna k přepsání vybraných funkcí knihovny C a jejich použití k nastavení stdout režim ukládání do vyrovnávací paměti, když jsou tyto funkce volány vaším programem. Tato metoda může fungovat, ale má řadu nevýhod:
-
Na statických spustitelných souborech to nebude vůbec fungovat
-
Je křehký a spíše ošklivý.
-
Se spustitelnými soubory SUID to nebude fungovat vůbec - dynamický zavaděč odmítne číst
LD_PRELOADpři načítání takových spustitelných souborů z bezpečnostních důvodů. -
Je křehký a spíše ošklivý.
-
Vyžaduje, abyste našli a přepsali funkci knihovny, která je volána vaším programem po zpočátku nastaví
stdoutrežim ukládání do vyrovnávací paměti a nejlépe před jakýkoli výstup.getenv()je dobrou volbou pro mnoho programů, ale ne pro všechny. Možná budete muset přepsat běžné I/O funkce, jako jeprintf()nebofwrite()- pokud push přijde na shove, možná budete muset přepsat všechny funkce, které řídí režim ukládání do vyrovnávací paměti a zavést speciální podmínku prostdout. -
Je křehký a spíše ošklivý.
-
Je těžké zajistit, aby nedošlo k nežádoucím vedlejším účinkům. Chcete-li toto právo provést, musíte zajistit, aby pouze
stdoutje ovlivněna a že vaše přepsání nezhroutí zbytek programu, pokud např.stdoutje zavřeno. -
Zmínil jsem se, že je křehký a spíše ošklivý?
To znamená, že proces je relativně jednoduchý. Vložíte soubor C, např. linebufferedstdout.c náhradní funkce:
#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
#include <dlfcn.h>
char *getenv(const char *s) {
static char *(*getenv_real)(const char *s) = NULL;
if (getenv_real == NULL) {
getenv_real = dlsym(RTLD_NEXT, "getenv");
setlinebuf(stdout);
}
return getenv_real(s);
}
Potom tento soubor zkompilujete jako sdílený objekt:
gcc -O2 -o linebufferedstdout.so -fpic -shared linebufferedstdout.c -ldl -lc
Poté nastavte LD_PRELOAD proměnnou, která ji načte spolu s vaším programem:
$ LD_PRELOAD=./linebufferedstdout.so python test.py | tee -a test.out
0
1000
2000
3000
4000
Pokud budete mít štěstí, váš problém bude vyřešen bez neštěstí vedlejší účinky.
Můžete nastavit LD_PRELOAD knihovnu v shellu, je-li to nutné, nebo dokonce specifikujte tuto knihovnu v celém systému (rozhodně NE doporučeno) v /etc/ld.so.preload .
Uvažovali jste o tom, že budete hrát odpaliště?
./program | tee a.txt
Nicméně ani tee nebude fungovat, pokud "program" nezapíše nic do stdout, dokud to není hotovo. Účinnost tedy hodně závisí na tom, jak se váš program chová.
Pokud se pokoušíte upravit chování existujícího programu, zkuste stdbuf (součást coreutils počínaje verzí 7.5 zřejmě).
Toto ukládá stdout až do řádku:
stdbuf -oL command > output
Toto zcela zakáže ukládání do vyrovnávací paměti stdout:
stdbuf -o0 command > output