TL;DR:
$ cmd 2> >(stderr-filter >&2)
Contoh:
% cat /non-existant 2> >(tr o X >&2)
cat: /nXn-existant: NX such file Xr directXry
%
Ini akan bekerja di bash dan zsh. Bash cukup banyak di mana-mana akhir-akhir ini, namun, jika Anda benar-benar membutuhkan solusi (sangat degil) untuk POSIX sh
, lalu lihat di sini.
Penjelasan
Sejauh ini, cara termudah untuk melakukannya adalah dengan mengalihkan STDERR melalui substitusi proses:
Substitusi proses memungkinkan input atau output proses dirujuk menggunakan nama file. Ini mengambil bentuk
>(list)
Daftar proses dijalankan secara asinkron, dan input atau outputnya muncul sebagai nama file.
Jadi yang Anda dapatkan dengan penggantian proses adalah nama file.
Seperti yang bisa Anda lakukan:
$ cmd 2> filename
kamu bisa melakukannya
$ cmd 2> >(filter >&2)
>&2
pengalihan filter
STDOUT kembali ke STDERR asli.
TL;DR:(bash dan zsh)
$ cmd 2> >(stderr-filter >&2)
Contoh:
% cat /non-existant 2> >(tr o X >&2)
cat: /nXn-existant: NX such file Xr directXry
%
Banyak jawaban di jaringan StackExchange berbentuk:
cat /non-existant 3>&1 1>&2 2>&3 3>&- | sed 's/e/E/g'
Ini memiliki asumsi bawaan:deskriptor file 3 tidak digunakan untuk hal lain.
Sebagai gantinya, gunakan deskriptor file bernama, dan {ba,z}sh
akan mengalokasikan deskriptor file berikutnya yang tersedia>=10:
cat /non-existant {tmp}>&1 1>&2 2>&$tmp {tmp}>&- | sed 's/e/E/g'
Perhatikan bahwa deskriptor file bernama tidak didukung oleh POSIX sh
.
Masalah lain dengan hal di atas adalah bahwa perintah tidak dapat disalurkan ke perintah lebih lanjut tanpa lagi menukar STDOUT dan STDERR kembali ke nilai aslinya.
Untuk mengizinkan pemipaan selanjutnya di POSIX sh
, (dan masih dengan asumsi FD 3 tidak digunakan) menjadi rumit:
(cmd 2>&1 >&3 3>&- | stderr-filter >&2 3>&-) 3>&1
Jadi, Mengingat asumsi dan sintaks degil ini, Anda mungkin lebih baik menggunakan bash
yang lebih sederhana /zsh
sintaks ditampilkan di TL;DR di atas, dan dijelaskan di sini.
demonstrasi praktis, hanya mengambil stderr:
$ ls -l . noexistABC noexistXYZ
ls: cannot access 'noexistABC': No such file or directory
ls: cannot access 'noexistXYZ': No such file or directory
.:
total 4
-rw-rw-r-- 1 frank frank 0 Aug 19 12:26 bar.txt
-rw-rw-r-- 1 frank frank 0 Aug 19 12:26 foo.txt
drwxrwxr-x 2 frank frank 4096 Aug 19 12:26 someFolder
$ ( ls -l . noexistABC noexistXYZ 2>&1 >&3 3>&- | grep ABC >&2 3>&-) 3>&1
.:
ls: cannot access 'noexistABC': No such file or directory
total 4
-rw-rw-r-- 1 frank frank 0 Aug 19 12:26 bar.txt
-rw-rw-r-- 1 frank frank 0 Aug 19 12:26 foo.txt
drwxrwxr-x 2 frank frank 4096 Aug 19 12:26 someFolder
Berikut ini sebuah contoh, yang dimodelkan setelah cara menukar deskriptor file di bash . Output dari a.out adalah sebagai berikut, tanpa awalan 'STDXXX:'.
STDERR: stderr output
STDOUT: more regular
./a.out 3>&1 1>&2 2>&3 3>&- | sed 's/e/E/g'
more regular
stdErr output
Mengutip dari tautan di atas:
- Pertama simpan stdout sebagai &3 (&1 ditipu menjadi 3)
- Selanjutnya kirim stdout ke stderr (&2 ditipu menjadi 1)
- Kirim stderr ke &3 (stdout) (&3 ditipu menjadi 2)
- tutup &3 (&- ditipu menjadi 3)
Penggunaan substitusi proses yang naif tampaknya memungkinkan pemfilteran stderr
terpisah dari stdout
:
:; ( echo out ; echo err >&2 ) 2> >( sed s/^/e:/ >&2 )
out
e:err
Perhatikan bahwa stderr
keluar pada stderr
dan stdout
pada stdout
, yang dapat kita lihat dengan membungkus semuanya dalam subkulit lain dan mengalihkan ke file o
dan e
( ( echo out ; echo err >&2 ) 2> >( sed s/^/e:/ >&2 ) ) 1>o 2>e