menggabungkan output dari dua perintah dalam bash

81

Apakah mungkin untuk menggabungkan output dari dua perintah ini?

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

Tidak ada perintah yang keluar jadi saya tidak yakin bagaimana melakukan ini.

kenyal
sumber
3
Jika program tidak selesai, mungkin mereka menulis keluaran terus menerus? Apa yang ingin Anda lakukan dengan hasil mereka? Garis interleave, ...? Mengapa Anda ingin melakukan ini?
vonbrand
2
Perintah node tidak menghasilkan banyak, tetapi masih perlu dijalankan. Python satu menampilkan semua permintaan, saya ingin menangkap keduanya dan menonton keduanya di jendela shell yang sama.
chovy

Jawaban:

108

Anda dapat menggabungkan dua perintah dengan mengelompokkannya dengan { }:

{ command1 & command2; }

sejauh ini, Anda dapat mengalihkan grup ke file (terakhir ;sebelum }wajib):

{ command1 & command2; } > new_file

jika Anda ingin memisahkan STDOUTdan STDERRdalam dua file:

{ command1 & command2; } > STDOUT_file 2> STDERR_file
Gilles Quenot
sumber
3
Tidak masalah bahwa programnya tidak selesai. 'tail -f' juga tidak "menyelesaikan", tetapi ini masih berfungsi dan menggabungkan output dari kedua program. Berfungsi untuk lebih dari dua perintah juga. ^ c untuk berhenti hanya membunuh satu dari perintah yang dikelompokkan. Anda harus membunuh yang lain secara manual.
SuperMagic
5
Sepertinya Anda tidak memiliki yang terakhir ;sebelumnya }, itu wajib!
Gilles Quenot
2
Diperingatkan: Ini tidak melindungi seluruh lini! Anda akan mendapatkan hasil yang tidak dapat diandalkan karena garis-garis terpisah dan berpadu satu sama lain. Anda dapat mencoba ini { yes {1..20} & yes {1..20}; } | grep -v '^1 2 3'yang idealnya tidak akan mencetak apa pun jika garis tidak putus.
antak
8
Saya lebih suka menggunakan &&daripada &! command1 & command2- ini menjalankan command1 di latar belakang dan memulai command2 segera, sehingga menjalankan kedua perintah secara paralel dan mengacaukan output. command1 && command2- ini menjalankan command1 (di latar depan) dan kemudian, jika command1 berhasil, jalankan command2.
DUzun
1
@Uzun OP mengatakan tidak ada perintah yang keluar, jadi dengan solusi Anda, perintah kedua tidak akan pernah berjalan
Zoey Hewll
50

Secara umum, dimungkinkan untuk menggunakan subkulit atau pengelompokan perintah, dan mengarahkan output dari seluruh grup sekaligus.

Kode:

( command1 ; command2 ; command3 ) | cat

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

Perbedaan utama antara keduanya adalah bahwa yang pertama membagi proses anak, sedangkan yang kedua beroperasi dalam konteks shell utama. Ini dapat memiliki konsekuensi mengenai pengaturan dan penggunaan variabel dan pengaturan lingkungan lainnya, serta kinerja.

Jangan lupa bahwa braket penutup dalam pengelompokan perintah (dan fungsi) harus dipisahkan dari konten dengan titik koma atau baris baru. Ini karena "}"sebenarnya adalah perintah (kata kunci) sendiri, dan harus diperlakukan seperti itu.

j9s
sumber
2
Pengalihan dari ( )berfungsi dengan baik juga.
muru
2
}sama sekali bukan perintah. Itu kata yang dilindungi undang-undang. Sama berlaku untuk {. Saya biasanya menulis daftar tersebut seperti: { command1;command2;} > outfile.txt. Anda bisa menambahkan spasi setelah titik koma tetapi tidak perlu. Ruang setelah { ini diperlukan, meskipun.
Wildcard
1
Diperingatkan: Ini tidak melindungi seluruh lini! Anda akan mendapatkan hasil yang tidak dapat diandalkan karena garis-garis terpisah dan berpadu satu sama lain. Anda dapat mencoba ini ( yes {1..20} & yes {1..20}; ) | grep -v '^1 2 3'yang idealnya tidak akan mencetak apa pun jika garis tidak putus. (T / ke @antak).
Ole Tange
3
Terkadang Anda ingin menjalankan command2 hanya jika command1 berhasil:( command1 && command2 && command3 ) | cat
DUzun
Saya lebih suka kurung bulat ()seperti kurung keriting {}berjalan sebagai latar belakang dan kemudian Anda harus berurusan dengan output dari itu. Juga pipa ke kucing `| cat` adalah alternatif yang lebih baik daripada `> / dev / stdout`
DarkMukke
2

Saya akhirnya melakukan ini, saran lain tidak berhasil, karena perintah ke-2 terbunuh atau tidak pernah dieksekusi.

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
}
kenyal
sumber
1
Catatan: ini dapat menyebabkan kesalahan I / O jika kedua proses mencoba menulis ke file "pada saat yang sama".
Djizeus
2
dapat menentukan 2 file log yang berbeda dan melakukan tail -f *.logwalaupun saya belum pernah melihat ini sebagai masalah dengan 2 proses berbeda menulis ke file log yang sama.
chovy
@ chovy: dapatkah Anda menulis masalah Anda sebagai pertanyaan di sini ... ini berguna
Abdennour TOUMI
1
Diperingatkan: Ini tidak melindungi seluruh lini! Anda akan mendapatkan hasil yang tidak dapat diandalkan karena garis-garis terpisah dan berpadu satu sama lain. Anda dapat mencoba ini dengan command1 = yes {1..20}command2 = yes {1..20}dan menyalurkan output gabungan | grep -v '^1 2 3'yang idealnya tidak akan mencetak apa pun jika garis tidak rusak. (T / ke @antak).
Ole Tange
Selain itu, disk Anda dapat berjalan penuh jika jumlah datanya besar.
Ole Tange
2

Coba ini:

paste $(node ~/projects/trunk/index.js) $(python ~/projects/trunk/run.py run) > outputfile
frogstarr78
sumber
1
apa yang dilakukan 'tempel'?
chovy
@chovy, lihat di sini: techrepublic.com/article/... Tidak yakin apakah itu akan berhasil dalam konteks ini.
FixMaker
Saya tidak berpikir tempel tepat di sini, karena itu dimaksudkan untuk meletakkan kolom di sebelah satu sama lain
Bernhard
@Bernhard memang. Tapi itu tidak ditentukan dalam req's
frogstarr78
@ frogstarr78 Saya pikir itu sangat tidak mungkin bahwa ini adalah apa yang dia inginkan, tetapi Anda benar, itu tidak ditentukan.
Bernhard
1

Sebagian besar solusi sejauh ini sangat buruk dengan masalah garis parsial. Asumsikan sebentar bahwa programnya adalah:

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

Saat menjalankannya secara paralel, Anda ingin output memiliki garis penuh as diikuti dengan garis penuh bs. Apa yang tidak Anda inginkan adalah pencampuran s adan bs pada baris yang sama ( tr -s abmenggantikan pengulangan adengan satu a, sehingga lebih mudah untuk melihat apa yang terjadi):

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

Jika Anda menggunakan GNU Parallel, Anda mendapatkan baris penuh bersih yang bagus dengan as atau bs tetapi tidak pernah dicampur:

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

Versi GNU Paralel yang lebih baru bahkan menghindari mengisi disk Anda: Hal di atas dapat berjalan selamanya.

Ole Tange
sumber
0

Karena Anda sudah menggunakan node, Anda mungkin ingin mencoba secara bersamaan

Jalankan beberapa perintah secara bersamaan. Suka npm run watch-js & npm run watch-lesstapi lebih baik.

Tamlyn
sumber
0

Untuk kasus khusus menggabungkan beberapa output perintah BASH ke satu baris, berikut adalah resep untuk menjalankan setiap perintah secara bergantian, menghapus baris baru di antara output mereka.

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

Sebagai contoh dunia nyata, kode di bawah ini akan menyematkan pesan ASCII antara dua string byte tetap (membentuk perintah cetak, dalam hal ini)

#   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

(Catatan: metode ini hanya berfungsi jika perintah keluar. Untuk menggabungkan stdout dari perintah yang tidak keluar, lihat jawaban lain.)

Luke
sumber
(1) Tolong tunjukkan output (yang diharapkan) dari perintah kedua Anda. (2) Tolong tunjukkan bagaimana OP akan menggunakan teknik ini untuk menyelesaikan masalahnya.
Scott
1) Output dari perintah kedua adalah biner non-ascii, jadi tidak akan berguna untuk menunjukkannya. 2) OP kemungkinan menyelesaikan masalah spesifiknya antara 2013 dan sekarang. Pertanyaan ini sekarang secara efektif merupakan referensi untuk menggabungkan stdout dari beberapa perintah Bash, jadi saya percaya teknik untuk menggabungkannya pada satu baris adalah "resep" yang berguna untuk disebutkan di sini (karena saya datang ke sini mencarinya dan tidak dapat menemukan saya t).
Luke