it-swarm-eu.dev

Jak elegantně neudělat nic navždy?

Mám program, který vytváří užitečné informace o stdout, ale také čte z stdin. Chci přesměrovat svůj standardní výstup do souboru, aniž bych na standardním vstupu poskytoval cokoli. Dosud, tak dobře: Dokážu:

program > output

a nedělejte nic do tty.

Problém je však v tom, že to chci udělat na pozadí. Pokud ano:

program > output &

program bude pozastaven („pozastaven (vstup tty)“).

Pokud ano:

program < /dev/null > output &

program se okamžitě ukončí, protože dosáhne EOF.

Zdá se, že to, co potřebuji, je vložit do program něco, co nedělá nic na neurčitou dobu a nečte stdin. Následující přístupy fungují:

while true; do sleep 100; done | program > output &
mkfifo fifo && cat fifo | program > output &
tail -f /dev/null | program > output &

To je však všechno ošklivé. musí být elegantní způsob, pomocí standardních unixových utilit, "nedělat nic, neurčitě" (parafrázovat man true). Jak toho mohu dosáhnout? (Moje hlavní kritéria pro eleganci zde: žádné dočasné soubory; žádné rušné čekání nebo pravidelné probuzení; žádné exotické nástroje; co nejkratší.)

87
a3nm

Ve skořápkách, které je podporují (ksh, zsh, bash4), můžete spustit program jako co-process .

  • ksh: program > output |&
  • zsh, bash: coproc program > output

To začíná program na pozadí vstupem přesměrovaným z pipe. Druhý konec potrubí je otevřen pro Shell.

Tři výhody tohoto přístupu

  • žádný další proces
  • můžete skript ukončit, když program umře (použijte wait k jeho čekání)
  • program bude ukončeno (get eof na jeho stdin, pokud Shell skončí).
17

Nemyslím si, že se stanete elegantnější než

tail -f /dev/null

že jste již navrhli (za předpokladu, že toto použití interně inotifikuje, nemělo by dojít k žádnému dotazování nebo probuzení, takže by mělo stačit jiné než neobvyklé vypadání).

Potřebujete nástroj, který bude běžet neomezeně dlouho, bude udržovat jeho stdout otevřený, ale ve skutečnosti nebude nic psát do stdout a nebude ukončen, když bude jeho stdin uzavřen. Něco jako yes ve skutečnosti píše do stdout. cat ukončí, když je jeho stdin zavřený (nebo cokoli, na co přesměrujete, je hotovo). Myslím sleep 1000000000d by mohlo fungovat, ale tail je jasně lepší. Moje debian pole má tailf, který mírně zkracuje příkaz.

Pokud jde o jiné řešení, co takhle spustit program pod screen?

81
P.T.

sleep infinity je nejjasnější řešení, které znám.

Můžete použít infinity, protože sleep přijímá číslo s pohyblivou řádovou čárkou *, což může být desetinné, hexadecimální , nekonečno nebo NaN podle man strtod.

* Toto není součástí standardu POSIX, takže není tak přenosný jako tail -f /dev/null. Je však podporován v GNU coreutils (Linux) a BSD (používá se na Mac)) (zjevně není podporován na novějších verzích Mac - viz komentáře).

50
Zaz
sleep 2147483647 | program > output &

Ano, 2^31-1 je konečné číslo, a to se nespustí navždy, ale dám ti 1000 $, když konečně vyprší čas spánku. (Tip: do té doby bude jeden z nás mrtvý.)

  • žádné dočasné soubory; šek.
  • žádné rušné čekání nebo pravidelné probuzení; šek
  • žádné exotické nástroje; šek.
  • co nejkratší. Dobře, mohlo by to být kratší.
19
Rob

Binární soubor, který to dělá, můžete vytvořit pomocí:

$ echo 'int main(){ pause(); }' > pause.c; make pause
10
PSkocik

Zde je další návrh pomocí standardních unixových utilit, „nedělat nic, donekonečna“.

sh -c 'kill -STOP $$' | program > output

Tím se spustí prostředí, které je okamžitě odesláno SIGSTOP, což proces pozastaví. Používá se jako „vstup“ do vašeho programu. Doplněk SIGSTOP je SIGCONT, tj. Pokud víte, že Shell má PID 12345, můžete kill -CONT 12345, aby to pokračovalo.

5
roaima

V systému Linux můžete:

read x < /dev/fd/1 | program > output

V Linuxu, otevření/dev/fd/x, kde x je deskriptor souboru na konec psaní kanálu, se dostanete na konec čtení kanálu, takže zde je to stejné jako na stdin programu. V zásadě se read nikdy nevrátí, protože jediná věc, která může zapisovat do tohoto kanálu, je sama o sobě a read nevytváří nic.

Bude také fungovat na FreeBSD nebo Solaris, ale z jiného důvodu. Tam, otevření/dev/fd/1, vám poskytne stejný zdroj jako otevřený na fd 1, jak byste očekávali, a jako většina systémů kromě Linuxu, takže konec roury se zapisuje. U FreeBSD a Solaris jsou však potrubí obousměrné. Dokud program nezapisuje do svého stdin (žádná aplikace ano), read nedostane nic, co by bylo možné číst z tohoto směru potrubí.

V systémech, kde kanály nejsou obousměrné, read pravděpodobně selže s chybou při pokusu o čtení z popisovače souboru jen pro zápis. Také si všimněte, že ne všechny systémy mají /dev/fd/x.

2

Stéphane Chazelas 'readsolution funguje také na Mac OS X, pokud se čtení _ otevře na /dev/fd/1.

# using bash on Mac OS X
# -bash: /dev/fd/1: Permission denied
read x </dev/fd/1 | cat >/dev/null
echo ${PIPESTATUS[*]}   #  1 0

exec 3<&- 3</dev/fd/1
read x 0<&3 | cat >/dev/null
echo ${PIPESTATUS[*]}   #  0 0

Být schopen zabít tail -f /dev/null ve skriptu (například s SIGINT) je nutné pozadí příkazu tail a wait.

#!/bin/bash
# ctrl-c will kill tail and exit script
trap 'trap - INT; kill "$!"; exit' INT
exec tail -f /dev/null & wait $!
0
user6915