Bagaimana cara mengarahkan output ke file dan stdout

989

Dalam bash, panggilan fooakan menampilkan output apa pun dari perintah itu di stdout.

Memanggil foo > outputakan mengarahkan output apa pun dari perintah itu ke file yang ditentukan (dalam hal ini 'keluaran').

Apakah ada cara untuk mengarahkan output ke file dan menampilkannya di stdout?

SCdF
sumber
3
Jika seseorang baru saja berakhir di sini mencari untuk menangkap keluaran kesalahan ke file, lihat - unix.stackexchange.com/questions/132511/…
Murphy
2
Sebuah catatan pada terminologi: ketika Anda mengeksekusi foo > outputdata yang ditulis ke stdout dan stdout adalah file bernama output. Artinya, menulis ke file adalah menulis ke stdout. Anda bertanya apakah mungkin untuk menulis ke stdout dan ke terminal.
William Pursell
2
@ WilliamPursell Saya tidak yakin klarifikasi Anda meningkatkan hal-hal :-) Bagaimana dengan ini: OP bertanya apakah mungkin untuk mengarahkan stdout program yang disebut ke kedua file dan stdout program panggilan (yang terakhir adalah stdout bahwa program yang dipanggil akan mewarisi jika tidak ada yang dilakukan, yaitu terminal, jika program panggilan adalah sesi bash interaktif). Dan mungkin mereka juga ingin mengarahkan stderr program yang disebut dengan cara yang sama ("setiap output dari perintah itu" mungkin secara wajar diartikan berarti termasuk stderr).
Don Hatch

Jawaban:

1380

Perintah yang Anda inginkan bernama tee:

foo | tee output.file

Misalnya, jika Anda hanya peduli dengan stdout:

ls -a | tee output.file

Jika Anda ingin memasukkan stderr, lakukan:

program [arguments...] 2>&1 | tee outfile

2>&1mengalihkan saluran 2 (stderr / standard error) ke saluran 1 (stdout / output standar), sehingga keduanya ditulis sebagai stdout. Ini juga diarahkan ke file output yang diberikan pada teeperintah.

Selanjutnya, jika Anda ingin menambahkan file log, gunakan tee -asebagai:

program [arguments...] 2>&1 | tee -a outfile
Sakit kepala
sumber
173
Jika OP ingin "semua output" dialihkan, Anda juga harus mengambil stderr: "ls -lR / 2> & 1 | tee output.file"
James Brady
45
@evanmcdonnal Jawabannya tidak salah, mungkin saja tidak cukup spesifik, atau lengkap tergantung pada kebutuhan Anda. Pasti ada kondisi di mana Anda mungkin tidak ingin stderr sebagai bagian dari output yang disimpan ke file. Ketika saya menjawab ini 5 tahun yang lalu saya berasumsi bahwa OP hanya menginginkan stdout, karena dia menyebutkan stdout dalam subjek posting.
Zoredache
3
Ah maaf, saya mungkin agak bingung. Ketika saya mencobanya saya baru saja tidak mendapatkan hasil, mungkin itu semua akan stderr.
evanmcdonnal
38
Gunakan -aargumen teeuntuk menambahkan konten output.file, alih-alih menimpanya:ls -lR / | tee -a output.file
kazy
16
Jika Anda menggunakan $?setelah itu akan mengembalikan kode status tee, yang mungkin bukan yang Anda inginkan. Sebagai gantinya, Anda bisa menggunakannya ${PIPESTATUS[0]}.
LaGoutte
501
$ program [arguments...] 2>&1 | tee outfile

2>&1membuang aliran stderr dan stdout. tee outfilemengambil aliran yang didapatnya dan menulisnya ke layar dan ke file "outfile".

Ini mungkin yang dicari kebanyakan orang. Situasi yang mungkin terjadi adalah beberapa program atau skrip bekerja keras untuk waktu yang lama dan menghasilkan banyak output. Pengguna ingin memeriksanya secara berkala untuk mengetahui perkembangannya, tetapi juga ingin keluarannya ditulis ke file.

Masalahnya (terutama ketika mencampur aliran stdout dan stderr) adalah bahwa ada ketergantungan pada aliran yang disiram oleh program. Jika, misalnya, semua menulis ke stdout yang tidak memerah, tapi semua menulis ke stderr yang memerah, maka mereka akan berakhir keluar dari urutan kronologis dalam file output dan pada layar.

Ini juga buruk jika program hanya menghasilkan 1 atau 2 baris setiap beberapa menit untuk melaporkan kemajuan. Dalam kasus seperti itu, jika output tidak memerah oleh program, pengguna bahkan tidak akan melihat output di layar selama berjam-jam, karena tidak ada yang akan didorong melalui pipa selama berjam-jam.

Pembaruan: Program unbuffer, bagian dari expectpaket, akan menyelesaikan masalah buffering. Ini akan menyebabkan stdout dan stderr untuk menulis ke layar dan file segera dan tetap sinkron ketika digabungkan dan dialihkan ke tee. Misalnya:

$ unbuffer program [arguments...] 2>&1 | tee outfile
Matthew Alpert
sumber
7
Adakah yang tahu tentang 'unbuffer' untuk osx?
John Mee
7
Jika Anda tidak dapat menggunakan unbuffer, GNU coreutils menyertakan alat yang disebut stdbuff yang dapat digunakan untuk mencegah buffering keluaran seperti itu$ stdbuf -o 0 program [arguments...] 2>&1 | tee outfile
Peter
1
Jika Anda menggunakan OS X, sedikit lebih mudah untuk menggunakan unbuffer dalam banyak kasus, meskipun tidak jika Anda ingin mengirimkan sinyal ke perintah yang Anda jalankan. Komentar saya lebih ditujukan kepada pengguna yang ada di Linux, di mana coreutils kemungkinan besar diinstal secara default. @Ethan, lihat jawaban ini jika Anda bingung tentang sintaks stdbuf: stackoverflow.com/a/25548995/942781
Peter
3
Catatan yang pythonmemiliki opsi -ubawaan yang membatalkan keluaran.
fabian789
1
Penyelamat absolut untuk model pelatihan ML di mana saya ingin login tanpa kode tambahan tetapi juga melihat output selama berjam-jam / hari untuk menjalankannya, terima kasih!
rococo
126

Cara lain yang bekerja untuk saya adalah,

<command> |& tee  <outputFile>

seperti yang ditunjukkan pada manual bash gnu

Contoh:

ls |& tee files.txt

Jika '| &' digunakan, kesalahan standar command1 , selain output standarnya , terhubung ke input standar command2 melalui pipa; itu adalah singkatan untuk 2> & 1 |. Pengalihan implisit kesalahan standar ke output standar dilakukan setelah setiap pengalihan ditentukan oleh perintah.

Untuk informasi lebih lanjut, lihat pengalihan

kesembuhan
sumber
10
Jika Anda menggunakan $?setelah itu akan mengembalikan kode status tee, yang mungkin bukan yang Anda inginkan. Sebagai gantinya, Anda bisa menggunakannya ${PIPESTATUS[0]}.
LaGoutte
1
Metode ini membuang keluaran konsol berwarna, ada ide?
shakram02
Coba: unbuffer ls -l --color = auto | tee files.txt
Luciano Andress Martini
17

Anda terutama dapat menggunakan solusi Zoredache , tetapi Jika Anda tidak ingin menimpa file output, Anda harus menulis tee dengan opsi -a sebagai berikut:

ls -lR / | tee -a output.file
O. Badr
sumber
11

Sesuatu untuk ditambahkan ...

Paket unbuffer memiliki masalah dukungan dengan beberapa paket di bawah fedora dan redhat rilis unix.

Mengesampingkan masalah

Mengikuti berhasil bagi saya

bash myscript.sh 2>&1 | tee output.log

Terima kasih ScDF & matthew input Anda menghemat banyak waktu ..

nitinr708
sumber
7

Penggunaan tail -f outputharus berhasil.

Chuck Phillips
sumber
3

Jawaban bonus karena penggunaan ini membawa saya ke sini:

Dalam kasus di mana Anda perlu melakukan ini sebagai pengguna lain

echo "some output" | sudo -u some_user tee /some/path/some_file

Perhatikan bahwa gema akan terjadi saat Anda dan penulisan file akan terjadi sebagai "some_user" yang TIDAK akan berfungsi adalah jika Anda menjalankan gema sebagai "some_user" dan mengarahkan ulang output dengan >> "some_file" karena pengalihan file akan terjadi seperti kamu.

Petunjuk: tee juga mendukung append dengan flag -a, jika Anda perlu mengganti baris dalam file sebagai pengguna lain Anda bisa mengeksekusi sed sebagai pengguna yang diinginkan.

jorfus
sumber
2

< command > |& tee filename # ini akan membuat file "nama file" dengan status perintah sebagai konten, Jika file sudah ada akan menghapus konten yang ada dan menulis status perintah.

< command > | tee >> filename # ini akan menambahkan status ke file tetapi tidak mencetak status perintah pada standard_output (layar).

Saya ingin mencetak sesuatu dengan menggunakan "echo" di layar dan menambahkan data yang di-echo ke file

echo "hi there, Have to print this on screen and append to a file" 
kiran sai
sumber
1

Anda dapat melakukannya untuk seluruh skrip Anda dengan menggunakan sesuatu seperti itu di awal skrip Anda:

#!/usr/bin/env bash

test x$1 = x$'\x00' && shift || { set -o pipefail ; ( exec 2>&1 ; $0 $'\x00' "$@" ) | tee mylogfile ; exit $? ; }

# do whaetever you want

Ini mengarahkan output stderr dan stdout ke file yang dipanggil mylogfile dan membiarkan semuanya masuk ke stdout pada saat yang sama .

Ini digunakan beberapa trik bodoh:

  • gunakan exectanpa perintah untuk mengatur pengalihan,
  • gunakan teeuntuk menduplikasi output,
  • mulai ulang skrip dengan pengalihan yang diinginkan,
  • menggunakan parameter pertama khusus ( NULkarakter sederhana yang ditentukan oleh $'string'notasi bash khusus) untuk menentukan bahwa skrip dimulai kembali (tidak ada parameter setara dapat digunakan oleh karya asli Anda),
  • coba pertahankan status keluar asli saat memulai ulang skrip menggunakan pipefailopsi.

Jelek tetapi bermanfaat bagi saya dalam situasi tertentu.

Bruno BEAUFILS
sumber
-13

tee sempurna untuk ini, tetapi ini juga akan melakukan pekerjaan

ls -lr / > output | cat output
kal
sumber
10
Itu kesalahan jika output belum ada dan tidak melakukan apa yang Anda inginkan jika tidak, secara keseluruhan tidak masuk akal. Mungkin maksudmu ";" bukannya "|" ?
Robert Gamble
6
Bahkan jika Anda menggunakan ;, output akan jauh tertunda selama perintah lambat.
Brad Koch