Bagaimana cara mengarahkan dan menambahkan stdout dan stderr ke file dengan Bash?

1535

Untuk mengarahkan stdout ke file terpotong di Bash, saya tahu harus menggunakan:

cmd > file.txt

Untuk mengarahkan stdout di Bash, menambahkan ke file, saya tahu harus menggunakan:

cmd >> file.txt

Untuk mengarahkan ulang stdout dan stderr ke file terpotong, saya tahu harus menggunakan:

cmd &> file.txt

Bagaimana cara mengarahkan stdout dan stderr menambahkan ke file? cmd &>> file.txttidak bekerja untuk saya.

flybywire
sumber
37
Saya ingin mencatat bahwa &> outfile adalah kode spesifik Bash (dan lainnya) dan tidak portabel. Cara untuk pergi portabel (mirip dengan jawaban yang ditambahkan) selalu dan masih ada> outfile 2> & 1
TheBonsai

Jawaban:

1999
cmd >>file.txt 2>&1

Bash mengeksekusi pengalihan dari kiri ke kanan sebagai berikut:

  1. >>file.txt: Buka file.txtdalam mode tambahkan dan redirect ke stdoutsana.
  2. 2>&1: Redirect stderrke "di mana stdoutsaat ini pergi" . Dalam hal ini, itu adalah file yang dibuka dalam mode append. Dengan kata lain, &1menggunakan kembali deskriptor file yang stdoutsaat ini digunakan.
Alex Martelli
sumber
33
bekerja hebat! tetapi apakah ada cara untuk memahami hal ini atau haruskah saya memperlakukan ini seperti konstruksi bash atom?
flybywire
181
Ini pengalihan sederhana, pernyataan pengalihan dievaluasi, seperti biasa, dari kiri ke kanan. >> file: Merah. STDOUT ke file (mode tambahkan) (kependekan dari 1 >> file) 2> & 1: Merah. STDERR ke "di mana stdout pergi" Perhatikan bahwa interpretasi "mengarahkan STDERR ke STDOUT" salah.
TheBonsai
31
Dikatakan "tambahkan output (stdout, file descriptor 1) ke file.txt dan kirim stderr (file descriptor 2) ke tempat yang sama dengan fd1".
Dijeda sampai pemberitahuan lebih lanjut.
2
@TheBonsai namun bagaimana jika saya perlu mengarahkan STDERR ke file lain tetapi menambahkan? apakah ini mungkin?
arod
41
jika Anda melakukannya cmd >>file1 2>>file2harus mencapai apa yang Anda inginkan.
Woodrow Douglass
367

Ada dua cara untuk melakukan ini, tergantung pada versi Bash Anda.

Cara klasik dan portabel ( Bash pre-4 ) adalah:

cmd >> outfile 2>&1

Cara nonportable, dimulai dengan Bash 4 adalah

cmd &>> outfile

(analog dengan &> outfile)

Untuk gaya pengkodean yang baik, Anda harus

  • memutuskan apakah portabilitas menjadi perhatian (gunakan cara klasik)
  • putuskan apakah portabilitas bahkan ke Bash pre-4 adalah masalah (gunakan cara klasik)
  • tidak masalah sintaks yang Anda gunakan, jangan ubah dalam skrip yang sama (kebingungan!)

Jika skrip Anda sudah mulai dengan #!/bin/sh(tidak peduli apakah itu dimaksudkan atau tidak), maka solusi Bash 4, dan secara umum kode spesifik Bash apa pun, bukanlah cara yang tepat.

Ingat juga bahwa Bash 4 &>>hanya sintaks yang lebih pendek - Bash 4 tidak memperkenalkan fungsionalitas baru atau semacamnya.

Sintaksnya (di samping sintaks redirection lainnya) dijelaskan di sini: http://bash-hackers.org/wiki/doku.php/syntax/redirection#appending_redirected_output_and_error_output

TheBonsai
sumber
8
Saya lebih suka & >> karena konsisten dengan &> dan >>. Juga lebih mudah untuk membaca 'tambahkan keluaran dan kesalahan ke file ini' daripada 'kirim kesalahan ke keluaran, tambahkan keluaran ke file ini'. Catatan sementara Linux umumnya memiliki versi bash saat ini, OS X, pada saat penulisan, masih memerlukan bash 4 untuk diinstal secara manual melalui homebrew dll.
mikemaccana
Saya lebih menyukainya karena lebih pendek dan hanya tweoi tempat per baris, jadi apa yang akan membuat zsh dari "& >>"?
Phillipp
Juga penting untuk dicatat, bahwa dalam pekerjaan cron, Anda harus menggunakan sintaks pra-4, bahkan jika sistem Anda memiliki Bash 4.
hyperknot
5
@zsero cron tidak menggunakan bash sama sekali ... ini digunakan sh. Anda dapat mengubah shell default dengan menambahkan SHELL=/bin/bashke crontab -efile.
Ray Foss
89

Di Bash, Anda juga dapat secara eksplisit menentukan arahan ulang ke file yang berbeda:

cmd >log.out 2>log_error.out

Menambahkan akan:

cmd >>log.out 2>>log_error.out
Aaron R.
sumber
6
Mengarahkan dua aliran ke file yang sama menggunakan opsi pertama Anda akan menyebabkan yang pertama menulis "di atas" yang kedua, menimpa sebagian atau semua konten. Gunakan cmd >> log.out 2> log.out sebagai gantinya.
Orestis P.
3
Terima kasih telah menangkapnya; Anda benar, yang satu akan mengalahkan yang lain. Namun, perintah Anda juga tidak berfungsi. Saya pikir satu-satunya cara untuk menulis ke file yang sama adalah seperti yang telah diberikan sebelumnya cmd >log.out 2>&1. Saya sedang mengedit jawaban saya untuk menghapus contoh pertama.
Aaron R.
65

Dalam Bash 4 (serta ZSH 4.3.11):

cmd &>>outfile

di luar kotak

AB
sumber
2
@all: ini adalah jawaban yang bagus, karena ini bekerja dengan bash dan singkat, jadi saya telah mengedit untuk memastikannya menyebutkan bash secara eksplisit.
mikemaccana
10
@mikemaccana: Jawaban TheBonsai menunjukkan solusi bash 4 sejak 2009
jfs
52

Ini seharusnya bekerja dengan baik:

your_command 2>&1 | tee -a file.txt

Ini akan menyimpan semua log di file.txt serta membuangnya di terminal.

Pradeep Goswami
sumber
Ini adalah jawaban yang benar jika Anda ingin melihat output di terminal juga. Namun, ini bukan pertanyaan yang awalnya ditanyakan.
Mikko Rantalainen
25

Coba ini

You_command 1>output.log  2>&1

Penggunaan &> x.file Anda berfungsi di bash4. maaf untuk itu : (

Ini dia beberapa tips tambahan.

0, 1, 2 ... 9 adalah deskriptor file dalam bash.

0 singkatan stdin, 1 singkatan stdout, 2 singkatan stderror. 3 ~ 9 adalah cadangan untuk penggunaan sementara lainnya.

Deskriptor file apa pun dapat dialihkan ke deskriptor file lain atau file dengan menggunakan operator >atau >>(tambahkan).

Penggunaan: < file_descriptor > > < nama file | & file_descriptor >

Silakan merujuk ke http://www.tldp.org/LDP/abs/html/io-redirection.html

Quintus.Zhou
sumber
Contoh Anda akan melakukan sesuatu yang berbeda dari yang diminta OP: Ini akan mengarahkan stderr You_commandke stdout dan stdout You_commandke file output.log. Selain itu tidak akan ditambahkan ke file tetapi akan menimpanya.
pabouk
Benar: Deskriptor file dapat berupa nilai apa saja yang lebih dari 3 untuk semua file lainnya.
Itachi
5
Jawaban Anda menunjukkan kesalahan pengalihan output yang paling umum: mengarahkan STDERR ke tempat STDOUT saat ini menunjuk dan hanya setelah itu mengarahkan STDOUT ke file. Ini tidak akan menyebabkan STDERR dialihkan ke file yang sama. Urutan pengalihan penting.
Jan Wikholm
1
apakah ini berarti, saya pertama-tama harus mengarahkan STDERROR ke STDOUT, kemudian mengarahkan STDOUT ke file. 1 > output.log 2>&1
Quintus.Zhou
1
@ Quintus.Zhou Yup. Pengalihan versi Anda salah untuk keluar, dan pada saat yang sama ke file.
Alex Yaroshevich
11

Saya terkejut bahwa dalam hampir sepuluh tahun, belum ada yang memposting pendekatan ini:

Jika menggunakan versi bash yang lebih lama di mana &>>tidak tersedia, Anda juga dapat melakukan:

(cmd 2>&1) >> file.txt

Ini menghasilkan subkulit, sehingga kurang efisien daripada pendekatan tradisional cmd >> file.txt 2>&1, dan akibatnya tidak akan bekerja untuk perintah yang perlu memodifikasi shell saat ini (misalnya cd,pushd ), tetapi pendekatan ini terasa lebih alami dan dapat dimengerti oleh saya:

  1. Redirect stderr ke stdout.
  2. Arahkan stdout baru dengan menambahkan file.

Juga, tanda kurung menghapus ambiguitas pesanan, terutama jika Anda ingin mengirim stdout dan stderr ke perintah lain.

jamesdlin
sumber
Implementasi ini menyebabkan satu proses ekstra untuk menjalankan sistem. Menggunakan sintaks cmd >> file 2>&1berfungsi di semua shell dan tidak perlu proses ekstra untuk dijalankan.
Mikko Rantalainen
@MikkoRantalainen Saya sudah menjelaskan bahwa itu memunculkan subkulit dan kurang efisien. Inti dari pendekatan ini adalah bahwa jika efisiensi bukanlah masalah besar (dan jarang), cara ini lebih mudah diingat dan lebih sulit untuk salah.
jamesdlin