2012-01-31 10 views
15

Chcę przechwytywać dane wyjściowe z dwóch współbieżnych programów (ogony na logach) do jednego strumienia wyjściowego w bashu.Połącz dane wyjściowe dwóch współbieżnych programów z bashem

Kiedyś ten przykładowy program do testowania:

function foo { for i in $(seq 1 10); do echo "program $*"; sleep 1; done } 

Teraz następujących prac drobnych

(foo bar & foo baz &) | tee /tmp/output 

ale gdy dodaję dodatkową rurę w miksie to już nie działa:

(foo bar | grep bar & foo baz &) | tee /tmp/output # does't work 

Dane wyjściowe stają się sekwencyjne. Mógłbym stworzyć osobny program, który zawiera grep, ale chciałbym się dowiedzieć, czy istnieje sposób obejścia tego.

Jeśli ktoś może wyjaśnić, dlaczego to nie działa, byłbym bardzo szczęśliwy.

Odpowiedz

7

Świetne pytanie! Ten mnie trochę mnie zaskoczył, ale myślę, że wiem, co się dzieje. Co się dzieje, to to, że grep buforuje wyjście. Tak więc, jeśli pozwolisz mu działać, zobaczysz na koniec całą powódź. Jeśli zdarzy ci się być za pomocą GNU grep spróbować przechodząc opcję --line buforowane:

(foo bar | grep --line-buffered bar & foo baz &) | tee /tmp/output 

Aby zaryzykować, i pamiętajcie, który jest w zasadzie to, co jest, powiedziałbym, że grep jest buforowanie wyjścia, ponieważ więcej isatty(1) oznacza, że ​​jest to , a nie zapisywanie na TTY (nawet jeśli oglądasz wyjście na TTY przez tee). Buforowanie większej ilości danych powoduje mniejszą liczbę połączeń write() i jest bardziej wydajne. Znane zachowanie podczas uruchamiania i obserwowania wyjścia w terminalu jest buforowane liniowo - linie pojawiają się tak, jak zostały znalezione. Ta opcja wymusza działanie w tym trybie w trybie grep.

Należy pamiętać, że jak ostrzega strona man, może to mieć wpływ na wydajność w przypadku grep.

+0

"mimo że jest, z powodu tee". grep to * nie * zapisywanie do tty. grep pisze do fajki, a tee pisze do tty. –

+0

Masz absolutną rację. Złe sformułowanie z mojej strony - będę edytować mój post, aby wyjaśnić. – FatalError

1

powodu użycia rury pomiędzy foo bar i grep robicie grep czekać na wyjściu komendy foo bar i dlatego wszystkie linie z bar przyjść od razu po liniach Baz. Jeśli naprawdę chcesz grep coś z polecenia następnie zdefiniować inną funkcję tak:

function foo1 { for i in {1..3}; do echo "program $*" | grep "$*"; sleep 1; done } 

a następnie wykonać:

(foo1 bar & foo baz &) | tee /tmp/output 

Teraz można zauważyć, że wyjście wygląda następująco:

program baz 
program bar 
program baz 
program bar 
program baz 
program bar 
... 
... 
Powiązane problemy