gema bahwa output ke stderr

1116

Apakah ada alat Bash standar yang bertindak seperti gema tetapi output ke stderr daripada stdout?

Saya tahu saya bisa melakukan echo foo 1>&2tetapi itu agak jelek dan, saya curiga, rawan kesalahan (misalnya lebih mungkin salah diedit ketika ada perubahan).

BCS
sumber

Jawaban:

1454

Anda bisa melakukan ini, yang memudahkan membaca:

>&2 echo "error"

>&2menyalin file deskriptor # 2 ke file deskriptor # 1. Oleh karena itu, setelah pengalihan ini dilakukan, kedua deskriptor file akan merujuk ke file yang sama: deskriptor satu file # 2 pada awalnya merujuk. Untuk informasi lebih lanjut, lihat Tutorial Pengalihan Illustrated Bash Hacker .

Marco Aurelio
sumber
2
Saya mempelajari trik ini beberapa waktu yang lalu. Halaman ini memiliki beberapa informasi yang bagus. tldp.org/LDP/abs/html/io-redirection.html
Marco Aurelio
46
@BCS Saya tidak tahu tentang menggunakan aliasskrip shell. Mungkin akan lebih aman untuk digunakanerrcho(){ >&2 echo $@; }
Braden Best
3
> & 2 biasanya diletakkan di akhir. Ini akan berhasil, tetapi lebih jarang digunakan
Iskren Ivov Chernev
159
Dalam hampir 40 tahun saya telah menggunakan sistem mirip Unix, tidak pernah terpikir oleh saya bahwa Anda bisa mengarahkan redirect ke mana saja tetapi pada akhirnya. Meletakkannya di depan seperti ini membuatnya jauh lebih jelas (atau "memfasilitasi membaca" seperti kata @MarcoAurelio). +1 untuk mengajari saya sesuatu yang baru.
Hephaestus
FYI: jika Anda ingin memformat atau melakukan apa pun selain hanya menggemakan string maka Anda harus memindahkan pengalihan kembali ke akhir. Misalnya errcho(){ >&2 echo $@|pr -To5;}tidak akan berfungsi. Untuk melakukan sesuatu seperti itu Anda harus meletakkan redirect di suatu tempat setelah pipa terakhir seperti:errcho(){ echo $@|>&2 pr -To5;}
Jon Red
424

Anda dapat mendefinisikan suatu fungsi:

echoerr() { echo "$@" 1>&2; }
echoerr hello world

Ini akan lebih cepat daripada skrip dan tidak memiliki dependensi.

Saran khusus bash Camilo Martin menggunakan "string di sini" dan akan mencetak apa pun yang Anda berikan padanya, termasuk argumen (-n) yang biasanya ditelan gema:

echoerr() { cat <<< "$@" 1>&2; }

Solusi Glenn Jackman juga menghindari argumen menelan masalah:

echoerr() { printf "%s\n" "$*" >&2; }
James Roth
sumber
7
Saya harus mengatakan bahwa gema agak tidak dapat diandalkan. echoerr -ne xttidak akan mencetak "-ne xt". Lebih baik gunakan printfuntuk itu.
Camilo Martin
10
Oh, Anda benar-benar dapat menggunakan kucing juga:echoerr() { cat <<< "$@" 1>&2; }
Camilo Martin
2
Saya tidak menyadarinya. Ditambahkan.
James Roth
4
Atau,printf "%s\n" "$*" >&2
glenn jackman
4
@GKFX Tentu saja itu hanya berfungsi dengan benar saat mengutip. Mengapa orang tidak mengutip dawai mereka ada di luar jangkauan saya. (ketika Anda tidak mengutip, segala sesuatu yang dipisahkan oleh satu atau lebih $IFSspasi putih dikirim sebagai argumen terpisah, yang dalam hal echocara menggabungkan mereka dengan 0x20s, tetapi bahaya tidak mengutip jauh melebihi kenyamanan 2 karakter untuk mengetik) .
Camilo Martin
252

Karena 1ini adalah output standar, Anda tidak perlu menyebutkannya secara eksplisit di depan pengalihan output seperti >tetapi cukup mengetik:

echo Pesan ini menuju ke stderr> & 2

Karena Anda tampaknya khawatir bahwa 1>&2akan sulit bagi Anda untuk mengetik dengan andal, penghapusan yang berlebihan 1mungkin sedikit menyemangati Anda!

Brandon Rhodes
sumber
59

Pilihan lain

echo foo >>/dev/stderr
Steven Penny
sumber
4
Apakah opsi ini portabel? Apakah ada yang tahu jika ini tidak berhasil untuk rasa unix?
Dacav
7
Ini tidak berfungsi di chroot tertentu, yang tidak dapat mengakses / dev / stderr.
Zachary Vance
12
Jika skrip yang mengeksekusi baris ini - sebut saja foo- memiliki stderrnya sendiri yang dialihkan - mis. foo >foo.log 2>&1- maka echo foo >/dev/stderrakan merusak semua output sebelumnya. >>harus digunakan sebagai gantinya:echo foo >>/dev/stderr
doshea
Demikian pula halnya dengan Anda /dev/fd/2.
jbruni
@Dacav ini pasti portable: /proc/self/fd/2. Lihat jawaban saya di bawah ini :)
Sebastian
31

Tidak, itu cara standar untuk melakukannya. Seharusnya tidak menyebabkan kesalahan.

Matthew Flaschen
sumber
9
Ini seharusnya tidak menimbulkan kesalahan, tapi saya mungkin akan lebih mungkin untuk. OTOH itu bukan masalah besar.
BCS
6
@Mike DeSimone: Jika orang lain mengacaukan kode, mengacak di sekitar output, dan tidak benar-benar tahu bash, mereka dapat dengan mudah menjatuhkan (atau salah ketik) itu 1>&2. Kita semua berharap ini tidak akan terjadi, tetapi saya yakin kita semua pernah menjadi tempat di mana itu terjadi.
Cascabel
2
( echo something 1>&2 ; something else ) > log-> (echo something; cp some junk 1>&2 ; something else) > logUps.
BCS
29
IMHO, jika seseorang mengacaukan kode dan tidak tahu bash, ini mungkin masalah Anda yang paling sedikit.
Mike DeSimone
7
Saya pikir jika itu mungkin menjadi masalah, Anda harus mulai menggunakan bahasa yang berbeda: mencoba untuk membuat bash sangat mudah adalah usaha orang bodoh.
intuited
17

Jika Anda tidak keberatan mencatat pesan juga ke syslog, cara not_so_ugly adalah:

logger -s $msg

Opsi -s berarti: "Keluarkan pesan ke kesalahan standar dan juga ke log sistem."

Grzegorz Luczywo
sumber
1
ini bagus! seberapa portabel itu?
code_monk
@code_monk: Perintah logger diharapkan menjadi IEEE Std 1003,2 ( "POSIX.2") yang kompatibel, Perintah logger adalah bagian dari paket util-linux dan tersedia dari Linux Kernel Arsip ⟨ kernel.org/pub/linux/utils / util- linux⟩.
miku
12

Ini adalah fungsi STDERR sederhana, yang mengarahkan input pipa ke STDERR.

#!/bin/bash
# *************************************************************
# This function redirect the pipe input to STDERR.
#
# @param stream
# @return string
#
function STDERR () {

cat - 1>&2

}

# remove the directory /bubu
if rm /bubu 2>/dev/null; then
    echo "Bubu is gone."
else
    echo "Has anyone seen Bubu?" | STDERR
fi


# run the bubu.sh and redirect you output
tux@earth:~$ ./bubu.sh >/tmp/bubu.log 2>/tmp/bubu.err
erselbst
sumber
2
Saya pikir Anda dapat melakukan hal yang sama dengan alias dan menjadi jauh lebih kompak
BCS
atau Anda bisa langsung echo what | /dev/stderr
mem-
11

Catatan: Saya menjawab pertanyaan post-bukan pertanyaan "gema yang keluar ke stderr" yang menyesatkan / tidak jelas (sudah dijawab oleh OP).

Gunakan fungsi untuk menunjukkan maksud dan sumber implementasi yang Anda inginkan. Misalnya

#!/bin/bash

[ -x error_handling ] && . error_handling

filename="foobar.txt"
config_error $filename "invalid value!"

output_xml_error "No such account"

debug_output "Skipping cache"

log_error "Timeout downloading archive"

notify_admin "Out of disk space!"

fatal "failed to open logger!"

Dan error_handlingmenjadi:

ADMIN_EMAIL=root@localhost

config_error() { filename="$1"; shift; echo "Config error in $filename: $*" 2>&1; }

output_xml_error() { echo "<error>$*</error>" 2>&1; }

debug_output() { [ "$DEBUG"=="1" ] && echo "DEBUG: $*"; }

log_error() { logger -s "$*"; }

fatal() { which logger >/dev/null && logger -s "FATAL: $*" || echo "FATAL: $*"; exit 100; }

notify_admin() { echo "$*" | mail -s "Error from script" "$ADMIN_EMAIL"; }

Alasan yang menangani masalah dalam OP:

  • Sintaks terbaik mungkin (kata-kata yang bermakna bukannya simbol jelek)
  • lebih sulit untuk membuat kesalahan (terutama jika Anda menggunakan kembali skrip)
  • ini bukan alat Bash standar, tetapi ini bisa menjadi pustaka shell standar untuk Anda atau perusahaan / organisasi Anda

Alasan lain:

  • kejelasan - menunjukkan niat untuk pengelola lainnya
  • kecepatan - fungsi lebih cepat dari skrip shell
  • reusability - suatu fungsi dapat memanggil fungsi lain
  • konfigurabilitas - tidak perlu mengedit skrip asli
  • debugging - lebih mudah untuk menemukan jalur yang bertanggung jawab atas kesalahan (terutama jika Anda mematikan dengan satu ton redirecting / filtering output)
  • kekokohan - jika ada fungsi yang hilang dan Anda tidak dapat mengedit skrip, Anda dapat kembali menggunakan alat eksternal dengan nama yang sama (misalnya log_error dapat alias logger di Linux)
  • berpindah implementasi - Anda dapat beralih ke alat eksternal dengan menghapus atribut "x" perpustakaan
  • output agnostik - Anda tidak lagi harus peduli jika pergi ke STDERR atau di tempat lain
  • personalisasi - Anda dapat mengonfigurasi perilaku dengan variabel lingkungan
Cezary Baginski
sumber
10

Saran saya:

echo "my errz" >> /proc/self/fd/2

atau

echo "my errz" >> /dev/stderr

echo "my errz" > /proc/self/fd/2akan efektif output ke stderrkarena /proc/selfini adalah link ke proses saat ini, dan /proc/self/fdmemegang proses membuka deskriptor file, dan kemudian, 0, 1, dan 2berdiri untuk stdin, stdoutdanstderr masing-masing.

The /proc/selflink tidak bekerja pada MacOS, bagaimanapun, /proc/self/fd/*tersedia di Termux di Android, tapi tidak /dev/stderr. Bagaimana cara mendeteksi OS dari skrip Bash? dapat membantu jika Anda perlu membuat skrip Anda lebih portabel dengan menentukan varian mana yang akan digunakan.

Sebastian
sumber
5
The /proc/selfLink tidak bekerja pada MacOS, jadi saya akan tetap dengan lebih lurus ke depan /dev/stderrmetode. Juga, seperti disebutkan dalam jawaban / komentar lain, mungkin lebih baik digunakan >>untuk menambahkan.
MarkHu
4
/proc/self/fd/*tersedia di Termux di Android, tetapi tidak /dev/stderr.
go2null
9

Jangan gunakan catkarena beberapa disebutkan di sini. catadalah program sementara echodan printfmerupakan bash (shell) bawaan. Meluncurkan program atau skrip lain (juga disebutkan di atas) berarti membuat proses baru dengan semua biayanya. Menggunakan builtin, fungsi penulisan cukup murah, karena tidak perlu membuat (mengeksekusi) suatu proses (-environment).

Opner bertanya "apakah ada alat standar untuk keluaran ( pipa ) ke stderr", jawabannya adalah: TIDAK ... mengapa? ... pipa rediredcting adalah konsep elemantari dalam sistem seperti unix (Linux ...) dan bash (sh) dibangun di atas konsep-konsep ini.

Saya setuju dengan pembuka yang mengarahkan ulang dengan notasi seperti ini: &2>1 tidak terlalu menyenangkan untuk programmer modern, tapi itu bash. Bash tidak dimaksudkan untuk menulis program yang besar dan tangguh, ini dimaksudkan untuk membantu para admin agar bisa bekerja di sana dengan penekanan tombol yang lebih sedikit ;-)

Dan setidaknya, Anda dapat menempatkan pengalihan di mana saja di baris:

$ echo This message >&2 goes to stderr 
This message goes to stderr
kembali42
sumber
1
Memberitahu pengembang untuk tidak menggunakan program hanya karena alasan kinerja adalah optimasi prematur. Pendekatan yang elegan, mudah diikuti harus lebih disukai daripada kode yang sulit dipahami yang berkinerja lebih baik (sesuai urutan milidetik).
GuyPaddock
@GuyPaddock maaf, Anda belum membacanya dengan baik. Pertama; Ini tentang mengarahkan pipa yang ditangani dengan baik oleh bash. Jika seseorang tidak menyukai sintaks (jelek) bagaimana bash mengalihkan, ia harus berhenti mengimplementasikan skrip bash atau mempelajari cara bash. Kedua; Anda harus tahu betapa mahalnya meluncurkan prozess baru dibandingkan dengan hanya memanggil bash builtin.
kembali42
1
Ada perbedaan antara membiarkan seseorang mengetahui pertukaran kinerja Bash built-in vs catdan menginstruksikan seseorang untuk tidak menggunakan kucing karena lambat. Ada banyak kasus penggunaan di mana kucing adalah pilihan yang tepat, jadi itu sebabnya saya keberatan dengan jawaban Anda.
GuyPaddock
@GuyPaddock Pembuka meminta echopengganti. Bahkan jika dia menggunakan cat, dia harus menggunakan pengalihan bash. bagaimanapun. Jadi, sama sekali tidak masuk akal untuk digunakan di catsini. BTW saya menggunakan cat100 kali sehari, tetapi tidak pernah dalam konteks pembuka meminta ... Anda mendapatkannya?
kembali42
8

Opsi lain yang baru-baru ini saya temukan adalah:

    {
        echo "First error line"
        echo "Second error line"
        echo "Third error line"
    } >&2

Ini hanya menggunakan Bash built-in sambil membuat output kesalahan multi-baris lebih sedikit kesalahan (karena Anda tidak harus ingat untuk menambahkan &>2ke setiap baris).

GuyPaddock
sumber
1
Tidak percaya, Anda memilih saya saat saya merekomendasikan untuk menggunakan bash-redirect dan dalam jawaban Anda sendiri Anda menggunakan bash-redirect.
kembali42
1
@ return42 Saya menolak jawaban Anda karena yang dilakukannya hanyalah memberi tahu OP bahwa tidak ada jawaban yang lebih baik daripada apa yang mereka mulai dengan .. itu sebenarnya bukan jawaban. Saya juga tidak melihat saran sub-shell dalam jawaban Anda ... jawaban Anda benar-benar hanya menyarankan OP untuk tidak menggunakan catatau utilitas lain, yang di luar topik untuk pertanyaan itu.
GuyPaddock
6

read adalah perintah shell builtin yang mencetak ke stderr, dan dapat digunakan seperti gema tanpa melakukan trik pengalihan:

read -t 0.1 -p "This will be sent to stderr"

Ini -t 0.1adalah batas waktu yang menonaktifkan fungsi utama baca, menyimpan satu baris stdin ke dalam variabel.

Douglas Mayle
sumber
5
Bash pada OS X tidak mengizinkan "0,1"
James Roth
2

Buat skrip

#!/bin/sh
echo $* 1>&2

itu akan menjadi alat Anda.

Atau buat fungsi jika Anda tidak ingin memiliki skrip dalam file terpisah.

n0
sumber
6
Lebih baik itu berfungsi (seperti jawaban James Roth), dan lebih baik menyampaikan semua argumen, bukan hanya yang pertama.
Cascabel
2
Mengapa suatu fungsi lebih baik? (Atau, sebagai alternatif: "Lebih baik untuk menjelaskan mengapa akan lebih baik ...")
Ogre Psalm33
3
@ OgrePsalm33 Salah satu alasan fungsi lebih baik adalah ketika memanggil skrip, biasanya instance shell baru dibuat untuk menyediakan lingkungan di mana untuk mengeksekusi skrip. Sebuah fungsi, di sisi lain, ditempatkan ke lingkungan shell yang sedang berjalan. Memanggil fungsi, dalam hal ini, akan menjadi operasi yang jauh lebih efisien karena pembuatan instance shell lainnya akan dihindari.
destenson
0

Menggabungkan solusi yang disarankan oleh James Roth dan Glenn Jackman

  • tambahkan kode warna ANSI untuk menampilkan pesan kesalahan dengan warna merah:
echoerr() { printf "\e[31;1m%s\e[0m\n" "$*" >&2; }

# if somehow \e is not working on your terminal, use \u001b instead
# echoerr() { printf "\u001b[31;1m%s\u001b[0m\n" "$*" >&2; }

echoerr "This error message should be RED"
Polymerase
sumber
-10

Mac OS X: Saya mencoba jawaban yang diterima dan beberapa jawaban lainnya dan semuanya menghasilkan penulisan STDOUT bukan STDERR pada Mac saya.

Berikut ini adalah cara portabel untuk menulis ke kesalahan standar menggunakan Perl:

echo WARNING! | perl -ne 'print STDERR'
Noah Sussman
sumber
lol downvote semua yang Anda inginkan tetapi ini adalah solusi yang sebenarnya saya gunakan dalam kode saya!
Noah Sussman