łącz wyjście z dwóch poleceń w bash

81

Czy można połączyć dane wyjściowe z tych dwóch poleceń?

node ~/projects/trunk/index.js 
python ~/projects/trunk/run.py run

Żadne polecenie nie kończy się, więc nie jestem pewien, jak to zrobić.

chovy
źródło
3
Jeśli programy się nie kończą, prawdopodobnie zapisują dane wyjściowe w sposób ciągły? Co chcesz zrobić z ich produkcją? Linie przeplotu, ...? Dlaczego chcesz to zrobić?
vonbrand
2
Polecenie node nie wyświetla zbyt wiele, ale nadal musi zostać uruchomione. Python wysyła wszystkie żądania, chcę uchwycić oba i oglądać je oba w tym samym oknie powłoki.
chovy

Odpowiedzi:

108

Możesz połączyć dwa polecenia, grupując je za pomocą { }:

{ command1 & command2; }

do tej pory, można przekierować grupę do pliku (ostatni ;przed }jest obowiązkowe):

{ command1 & command2; } > new_file

jeśli chcesz oddzielić STDOUTi STDERRdwa pliki:

{ command1 & command2; } > STDOUT_file 2> STDERR_file
Gilles Quenot
źródło
3
Nie ma znaczenia, że ​​ich programy się nie kończą. „tail -f” też nie „kończy”, ale nadal działa i łączy wyniki obu programów. Działa również dla więcej niż dwóch poleceń. ^ c, aby wyjść zabija tylko jedno z pogrupowanych poleceń. Musisz jednak zabić drugiego przeciwnika ręcznie.
SuperMagic
5
Wygląda na to brakuje ci ostatni ;przed }, to jest obowiązkowe!
Gilles Quenot,
2
Uwaga: to nie zachowuje całych linii! Otrzymasz niewiarygodne wyniki, gdy linie zostaną częściowo podzielone i zmieszane między sobą. Możesz spróbować tego, dzięki { yes {1..20} & yes {1..20}; } | grep -v '^1 2 3'czemu idealnie nic nie wydrukujesz, jeśli linie nie zostaną złamane.
antak
8
Wolałbym użyć &&zamiast &! command1 & command2- to uruchamia polecenie 1 w tle i natychmiast uruchamia polecenie 2, tym samym uruchamiając oba polecenia równolegle i psując dane wyjściowe. command1 && command2- uruchamia to polecenie 1 (na pierwszym planie), a następnie, jeśli polecenie 1 się powiedzie, uruchamia polecenie 2.
DUzun,
1
@DUzun OP powiedział, że żadne polecenie nie kończy się, więc przy twoim rozwiązaniu drugie polecenie nigdy się nie uruchomi
Zoey Hewll
50

Mówiąc bardziej ogólnie, można użyć grupowania podpowłoki lub grupowania poleceń i przekierować dane wyjściowe całej grupy naraz.

Kod:

( command1 ; command2 ; command3 ) | cat

{ command1 ; command2 ; command3 ; } > outfile.txt

Główna różnica między nimi polega na tym, że pierwszy dzieli proces potomny, podczas gdy drugi działa w kontekście głównej powłoki. Może to mieć konsekwencje w zakresie ustawiania i używania zmiennych i innych ustawień środowiska, a także wydajności.

Nie zapominaj, że nawias zamykający w grupowaniu poleceń (i funkcjach) musi być oddzielony od treści średnikiem lub znakiem nowej linii. Wynika to z faktu, że "}"tak naprawdę jest to samo polecenie (słowo kluczowe) i musi być traktowane jak jedno.

j9s
źródło
2
Przekierowanie z ( )działa również dobrze.
muru
2
}wcale nie jest poleceniem. To zastrzeżone słowo. To samo dotyczy {. I zazwyczaj pisać takie listy tak: { command1;command2;} > outfile.txt. Możesz dodać spacje po średnikach, ale nie jest to konieczne. Konieczne { jest jednak miejsce po .
Wildcard
1
Uwaga: to nie zachowuje całych linii! Otrzymasz niewiarygodne wyniki, gdy linie zostaną częściowo podzielone i zmieszane między sobą. Możesz spróbować tego, dzięki ( yes {1..20} & yes {1..20}; ) | grep -v '^1 2 3'czemu idealnie nic nie wydrukujesz, jeśli linie nie zostaną złamane. (H / t do @antak).
Ole Tange
3
Czasami chcesz uruchomić polecenie 2 tylko wtedy, gdy polecenie 1 ( command1 && command2 && command3 ) | cat
powiodło się
Wolę okrągłe nawiasy, ()jak w nawiasach klamrowych, {}które działają jako postęp w tle, a następnie musisz poradzić sobie z tym. Również potok do kota `| cat` jest lepszą alternatywą niż `> / dev / stdout`
DarkMukke,
2

Skończyło się na tym, inne sugestie nie zadziałały, ponieważ 2. polecenie zostało zabite lub nigdy nie zostało wykonane.

alias app () {
    nohup python ~/projects/trunk/run.py run 1>/tmp/log 2>&1 &
    echo $! > /tmp/api.pid
    nohup node ~/projects/trunk/index.js 1>/tmp/log 2>&1 &
    echo $! > /tmp/client.pid
    tail -f /tmp/log
}
chovy
źródło
1
Uwaga: może to powodować błędy we / wy, jeśli dwa procesy spróbują zapisać do pliku „w tym samym czasie”.
Djizeus
2
mogę określić 2 różne pliki dziennika i zrobić, tail -f *.logchociaż nigdy nie widziałem tego jako problemu z 2 różnymi procesami zapisującymi do tego samego pliku dziennika.
chovy
@chovy: czy możesz napisać swój problem jako pytanie tutaj ... jest to przydatne
Abdennour TOUMI
1
Uwaga: to nie zachowuje całych linii! Otrzymasz niewiarygodne wyniki, gdy linie zostaną częściowo podzielone i zmieszane między sobą. Możesz tego spróbować za pomocą polecenia1 = yes {1..20}polecenie2 = yes {1..20}i potokować połączone wyjście, przez | grep -v '^1 2 3'które idealnie nic nie wydrukujemy, jeśli linie nie zostaną podzielone. (H / t do @antak).
Ole Tange,
Ponadto dysk może być zapełniony, jeśli ilość danych jest duża.
Ole Tange
2

Spróbuj tego:

paste $(node ~/projects/trunk/index.js) $(python ~/projects/trunk/run.py run) > outputfile
frogstarr78
źródło
1
co robi „wklej”?
chovy
@chovy, patrz tutaj: techrepublic.com/article/… Nie jestem pewien, czy to zadziała w tym kontekście.
FixMaker
Nie sądzę, aby wklejanie było tutaj właściwe, ponieważ ma to na celu umieszczenie kolumn obok siebie
Bernhard
@Bernhard rzeczywiście. Ale nie zostało to określone w wymaganiach
frogstarr78
@ frogstarr78 Myślę, że jest bardzo mało prawdopodobne, że tego właśnie chce, ale masz rację, nie jest to określone.
Bernhard
1

Większość dotychczasowych rozwiązań źle radzi sobie z problemem częściowej linii. Załóżmy przez chwilę, że programami są:

cmd1() {
    perl -e 'while(1) { print "a"x3000_000,"\n"}'
}
export -f cmd1
cmd2() {
    perl -e 'while(1) { print "b"x3000_000,"\n"}'
}
export -f cmd2

Podczas uruchamiania tych równolegle chcesz, aby wynik zawierał pełne linie as, po których następują pełne linie bs. Czego nie chce to as i bs mieszania w tej samej linii ( tr -s abzastępuje powtarzając as przy pojedynczym a, więc łatwiej jest zobaczyć, co się dzieje):

# This is bad - half lines are mixed
$ (cmd1 & cmd2 ) | tr -s ab
bababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababa
ababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababababab

Jeśli zamiast tego użyjesz GNU Parallel, uzyskasz ładne, czyste pełne linie z as lub bs, ale nigdy nie mieszane:

$ parallel --line-buffer ::: cmd1 cmd2 | tr -s ab
a
a
b
b
b
b
a

Nowsze wersje GNU Parallel unikają nawet zapełniania dysku: powyższe może działać wiecznie.

Ole Tange
źródło
0

Ponieważ już korzystasz node, możesz spróbować spróbować jednocześnie

Uruchom wiele poleceń jednocześnie. Jak, npm run watch-js & npm run watch-lessale lepiej.

Tamlyn
źródło
0

W specjalnym przypadku łączenia wielu danych wyjściowych poleceń BASH w jednym wierszu, oto przepis na uruchamianie każdego polecenia po kolei, usuwając wszelkie znaki nowej linii między ich wyjściami.

(echo 'ab' && echo 'cd' && echo 'ef') | tr -d '\n'
>>> abcdef

Jako przykład ze świata rzeczywistego poniższy kod osadzi komunikat ASCII między dwoma stałymi ciągami bajtów (w tym przypadku tworząc polecenie drukowania)

#   hex prefix           encode a message as hex    hex suffix    | strip newline | hex to binary | (then, for example, send the binary over a TCP connection)
(echo '1b40' && echo "Test print #1" | xxd -p && echo '1d564103') | tr -d '\n'    | xxd -r -p     | nc -N 192.168.192.168 9100

(Uwaga: ta metoda działa tylko wtedy, gdy polecenia kończą się. Aby połączyć standardowe wyjście z poleceń, które się nie kończą, zobacz inne odpowiedzi.)

Łukasz
źródło
(1) Pokaż (oczekiwany) wynik drugiego polecenia. (2) Pokaż, w jaki sposób OP wykorzystałby tę technikę do rozwiązania swojego problemu.
Scott
1) Wyjście drugiego polecenia nie jest ascii binarne, więc nie byłoby użyteczne jego pokazywanie. 2) OP prawdopodobnie rozwiązał swój konkretny problem między 2013 r. A teraz. To pytanie jest teraz skutecznie odniesieniem do łączenia standardowego polecenia wielu poleceń Bash, więc uważam, że technika łączenia ich w jednym wierszu jest użytecznym „przepisem”, o którym należy wspomnieć tutaj (ponieważ przybyłem tutaj, aby go znaleźć i nie mogłem znaleźć to).
Łukasz