W jaki sposób programy wyprowadzają dane do innego miejsca niż STDOUT / STDERR? Jak tego uniknąć?

15

Najwyraźniej nie znam wszystkich docelowych miejsc docelowych, które są dostępne do użycia. Wiem o stdout( &1) i stderr( &2). Jednak po przekierowanie zarówno deskryptory, czasami jeszcze trochę wyjście w moim konsoli!

Najprostszym przykładem, jaki mogę wymyślić, jest GNU Parallel; Za każdym razem, gdy go używam, widzę zawiadomienie o cytowaniu. Nawet gdy to robię &2>1 > file, nadal widzę to powiadomienie.

To samo dotyczy emerge: kiedy uruchamiam się i pojawiają się pewne problemy, niektóre informacje nie są drukowane stdoutani stdin, ponieważ przekierowuję je, a one nadal przechodzą.

Najczęściej rozwiązuję te problemy za pomocą script, ale wciąż zastanawiam się, co jest przyczyną tego problemu.

MatthewRock
źródło
1
Podaj pełny przykład.
Kusalananda
8
Nie dostaniesz ich wszystkich . Skrypt zawsze może pisać /dev/tty.
Satō Katsura
1
Co do GNU parallel: mkdir ~/.parallel; touch ~/.parallel/will-citewyłączy irytującą wiadomość. Alternatywnie, rozejrzyj się za innymi implementacjami parallel.
Satō Katsura
2
@OleTange Ponieważ to nie jest problem - pytam, dlaczego coś się dzieje i używam paralleljako przykładu.
MatthewRock

Odpowiedzi:

40

Użyta składnia jest nieprawidłowa.

cmd &2>1 >file

zostanie podzielony jako

cmd &
2>1 >file

Spowoduje to:

  1. Uruchom cmdjako zadanie w tle bez przekierowań
  2. W osobnym procesie (bez polecenia!) Nastąpi przekierowanie stderrdo pliku dosłownie wywołanego 1i przekierowanie stdoutdofile

Żądana składnia to:

cmd >file 2>&1

Kolejność operacji jest ważna. Spowoduje to:

  1. Przekieruj stdoutdofile
  2. Przekieruj stderrdo &1- tzn. Ten sam uchwyt pliku, costdout

Powoduje to, że zarówno stderri stdoutzostanie przekierowany file.

W bashprostsza niestandardowa (i dlatego nie polecam, ze względu na przenośność) składnia cmd &> filerobi to samo.

Stephen Harris
źródło
Fajnie dzięki. Innym problemem może być /dev/tty, ale mam nadzieję, że nie zdarza się to zbyt często (jeśli w ogóle).
MatthewRock
5
Jeśli masz atpolecenie na swoim komputerze i masz uprawnienia do korzystania z niego, możesz je uruchomić za pośrednictwem at now. Szczegółowe informacje można znaleźć na stronie podręcznika. Spowoduje to uruchomienie polecenia za pomocą mechanizmu procesu wsadowego, a proces nigdy nie będzie miał tty do zapisu. Ale generalnie nie martwiłbym się tym przypadkiem. Zazwyczaj wykorzystywane są tylko procesy wymagające interakcji i umyślne wyświetlanie informacji użytkownikom, mimo przekierowania /dev/tty.
Stephen Harris
byłem tam, zrobiłem to
davidbak
10

Istnieją dwa problemy.

Pierwszym jest to, że kolejność ma znaczenie, drugim jest /dev/tty.

Użyjmy tego skryptu jako przykładowego skryptu, z którego chcemy przechwycić dane wyjściowe:

test.sh:

#!/bin/bash

echo dada
echo edada 1>&2
echo ttdada >/dev/tty

Zobaczmy teraz wyniki poleceń:

./testmyscript.sh 2>&1 >/dev/null:

edada
ttdada

Ponieważ kolejność obliczeń jest od lewej do prawej, najpierw otrzymujemy „przekierowanie stderrdo dowolnego miejsca stdoutwyjściowego (czyli wyjścia konsoli)”. Następnie otrzymujemy „przekierowanie stdoutdo /dev/null. Sytuacja wygląda następująco:

stdout-> /dev/null stderr-> konsola

Więc dobrze to rozumiemy:

./testmyscript.sh >/dev/null 2>&1

I otrzymujemy:

ttdada.

Teraz wykonujemy „Przekieruj stdoutdo /dev/null”, a następnie „Przekieruj stderr do miejsca, w którym wskazuje stdout” (więc, /dev/null). Hurra!

Nadal jednak mamy problem; program drukuje do /dev/tty. Teraz nie wiem, jak naprawić tego rodzaju zachowanie, więc najprawdopodobniej będziesz go potrzebować script, ale mam nadzieję, że takie zachowanie nie zdarzy się zbyt często.

MatthewRock
źródło