Mam program, który generuje przydatne informacje, stdout
ale także czyta z stdin
. Chcę przekierować standardowe wyjście do pliku, nie udostępniając niczego na standardowym wejściu. Jak dotąd tak dobrze: mogę zrobić:
program > output
i nie rób nic w tty.
Problem polega jednak na tym, że chcę to zrobić w tle. Jeśli zrobię:
program > output &
program zostanie zawieszony („zawieszony (wejście tty)”).
Jeśli zrobię:
program < /dev/null > output &
program kończy się natychmiast, ponieważ osiąga EOF.
Wydaje się, że potrzebuję połączyć się z program
czymś, co nie robi niczego przez czas nieokreślony i nie czyta stdin
. Działa następujące podejście:
while true; do sleep 100; done | program > output &
mkfifo fifo && cat fifo | program > output &
tail -f /dev/null | program > output &
Wszystko to jest jednak bardzo brzydkie. Tam ma być elegancki sposób, przy użyciu standardowych narzędzi systemu Unix, aby „nie robić nic, na czas nieokreślony” (parafrazując man true
). Jak mogłem to osiągnąć? (Moje główne kryteria elegancji tutaj: brak plików tymczasowych; brak zajętych oczekiwań lub okresowych pobudek; brak egzotycznych narzędzi; możliwie najkrótszy.)
su -c 'program | output &' user
. Zaraz zadam podobne pytanie dotyczące tworzenia zadań w tle jako akceptowalnej metody obsługi „usługi / demona”. Zauważyłem również, że nie mogę przekierowaćSTDERR
bez przekierowaniaSTDOUT
. Rozwiązanie, w którym program A wysyłaSTDOUT
doSTDIN
programu B, a następnie przekierowujeSTDERR
do pliku dziennika:programA 2> /var/log/programA.log | programB 2> /var/log/programB.log 1> /dev/null
su -c 'while true; do true; done | cat > ~/output &' user
?1<&-
tego programu, wyjdziesz z programu?Odpowiedzi:
W powłokach, które je obsługują (ksh, zsh, bash4), możesz zacząć
program
jako koproces .ksh
:program > output |&
zsh
,bash
:coproc program > output
Który rozpoczyna
program
się w tle z jego wejście, które zostało przekształcone od Apipe
. Drugi koniec rury jest otwarty dla skorupy.Trzy zalety tego podejścia
program
umiera (użyj,wait
aby na niego poczekać)program
zakończy działanie (wejdzieeof
na standardowe wejście, jeśli powłoka wyjdzie).źródło
tail -f /dev/null
nie jest idealny, ponieważ dokonuje odczytu co sekundę/dev/null
(obecne wersje GNU tail w Linuksie używają tego, by wiedzieć, że w rzeczywistości jest błąd ).sleep inf
lub jego bardziej przenośnym odpowiednikiemsleep 2147483647
są lepsze podejścia do polecenia, które tam siedzi i nie robi nic IMO (uwagasleep
jest wbudowana w kilka powłok takich jakksh93
lubmksh
).Nie sądzę, że będziesz bardziej elegancki niż
które już zasugerowałeś (zakładając, że używa to wewnętrznie inotify, nie powinno być sondowania ani wybudzeń, więc poza dziwnym wyglądem powinno wystarczyć).
Potrzebujesz narzędzia, które będzie działać przez czas nieokreślony, utrzyma stdout otwarte, ale tak naprawdę nie napisze niczego na stdout i nie wyjdzie, gdy jego stdin jest zamknięte. Coś takiego
yes
faktycznie pisze na standardowe wyjście.cat
wyjdzie, gdy jego standardowe wejście zostanie zamknięte (lub zrobione zostanie cokolwiek, na co zostaniesz przekierowany). Myślę, żesleep 1000000000d
może działać, aletail
jest wyraźnie lepiej. Moje pudełko Debiana matailf
nieco skrócone polecenie.Biorąc pod uwagę inny sprzęt, co powiesz na uruchomienie programu
screen
?źródło
tail -f /dev/null
Najbardziej podoba mi się to podejście i uważam je za wystarczająco eleganckie, ponieważ użycie polecenia dość ściśle odpowiada zamierzonemu celowi.strace tail -f /dev/null
Wydaje się, żetail
używainotify
i wybudzeń występuje w głupich takich przypadkachsudo touch /dev/null
. To smutne, że wydaje się, że nie ma lepszego rozwiązania ... Zastanawiam się, który byłby odpowiedni system, aby użyć lepszego rozwiązania.pause
, ale nie jest narażony bezpośrednio na interfejs powłoki.screen
, ale ma to na celu uruchomienie wielu wystąpień programu ze skryptu powłoki do celów testowych, więc używaniescreen
jest nieco przesadne.sleep infinity
to najczystsze znane mi rozwiązanie.Możesz użyć,
infinity
ponieważsleep
akceptuje liczbę zmiennoprzecinkową * , która może być dziesiętna , szesnastkowa , nieskończoności lub NaN , zgodnie zman strtod
.* To nie jest część standardu POSIX, więc nie jest tak przenośna jak
tail -f /dev/null
. Jest jednak obsługiwany w jądrach GNU (Linux) i BSD (używany na Macu) (najwyraźniej nie jest obsługiwany w nowszych wersjach Maca - patrz komentarze).źródło
sleep infinity
również na BSD i Mac .sleep infinity
czeka maksymalnie 24 dni; kto ma rację?sleep
Narzędzie jest nie ograniczone do 24 dni ; jest to tylko pierwszy system, który śpi przez 24 dni, a potem wykona więcej takich połączeń. Zobacz mój komentarz tutaj: stackoverflow.com/questions/2935183/…Tak,
2^31-1
jest liczbą skończoną i nie będzie trwać wiecznie , ale dam ci 1000 $, kiedy sen wreszcie się skończy. (Wskazówka: do tego czasu jedno z nas nie żyje).źródło
sleep 2147483647d
...Możesz utworzyć plik binarny, który robi to samo za pomocą:
źródło
Oto kolejna sugestia użycia standardowych narzędzi uniksowych, aby „nic nie robić w nieskończoność” .
Spowoduje to uruchomienie powłoki, która jest natychmiast wysyłana
SIGSTOP
, co powoduje zawieszenie procesu. Jest to używane jako „dane wejściowe” do programu. UzupełnieniemSIGSTOP
jestSIGCONT
, tzn. Jeśli wiesz, że powłoka ma PID 12345, możeszkill -CONT 12345
ją kontynuować.źródło
W systemie Linux możesz wykonać:
W Linuksie, otwarcie / dev / fd / x, gdzie x jest deskryptorem pliku do końca zapisu potoku, daje ci koniec odczytu potoku, więc tutaj to samo, co na standardowym programie. Zasadniczo więc
read
nigdy nie powróci, ponieważ jedyną rzeczą, która może napisać do tego potoku, jest sama iread
niczego nie wyświetla.Będzie również działał na FreeBSD lub Solaris, ale z innego powodu. Tam otwarcie / dev / fd / 1 daje ci taki sam zasób jak open na fd 1, tak jak można się spodziewać i jak większość systemów z wyjątkiem Linuksa, więc koniec pisania potoku. Jednak w FreeBSD i Solaris potoki są dwukierunkowe. Tak długo, jak
program
nie pisze do standardowego wejścia (żadna aplikacja tego nie robi), nieread
będzie nic czytać z tego kierunku potoku.W systemach, w których potoki nie są dwukierunkowe,
read
prawdopodobnie wystąpi błąd przy próbie odczytu z deskryptora pliku tylko do zapisu. Należy również pamiętać, że nie wszystkie systemy mają/dev/fd/x
.źródło
x
bash; dalej z zsh możesz po prostu zrobićread
i to działa (choć nie rozumiem dlaczego!). Czy ta sztuczka jest specyficzna dla Linuksa, czy działa na wszystkich systemach * nix?read
sam, odczyta ze standardowego wejścia. Więc jeśli jest to terminal, będzie czytał to, co piszesz, dopóki nie naciśniesz enter.read
i to działa ?read | program > output
i działa tak samo, jak zasugerowałeś. (I nie rozumiem dlaczego.)Stephane Chazelas'
read
rozwiązanie działa na Mac OS X, a także czy fd odczyt zostanie otwarty/dev/fd/1
.Aby móc zabijać
tail -f /dev/null
w skrypcie (na przykład za pomocą SIGINT), konieczne jest tłotail
polecenia iwait
.źródło
Przekieruj
/dev/zero
jako standardowe wejście!źródło