GNU/Linux >> Znalost Linux >  >> Linux

on-the-fly výstup přesměrování, vidět výstup přesměrování souboru, zatímco program stále běží

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 nebo setvbuf() pro změnu režimu ukládání do vyrovnávací paměti standardního výstupu. Pro Python existuje sys.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.py
    

    byl 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žít screen pro 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_PRELOAD př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í stdout rež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 je printf() nebo fwrite() - 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 pro stdout .

  • 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 stdout je ovlivněna a že vaše přepsání nezhroutí zbytek programu, pokud např. stdout je 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


Linux
  1. Čtěte a zapisujte data odkudkoli s přesměrováním v terminálu Linux

  2. Jak přesměrovat výstup programu do souboru ZIP?

  3. Výstup do Stdout a zároveň Grep do souboru?

  1. Příkaz pro výstup obsahu souboru do Stdout?

  2. Zavření standardního výstupu (>&-)?

  3. Io Redirection and the Head Command?

  1. Naučte se základy toho, jak funguje přesměrování I/O (vstup/výstup) v systému Linux

  2. Jak připojit výstup do souboru?

  3. Jak přesměrovat výstup system() do souboru?