Saring output perintah berdasarkan warna

13

Saya menjalankan utilitas yang tidak menawarkan cara untuk memfilter outputnya. Tidak ada dalam teks output yang menunjukkan bahwa fungsi tertentu gagal tetapi tidak muncul dalam warna merah. Outputnya sangat panjang sehingga pada akhirnya ketika # melaporkan beberapa kesalahan saya tidak bisa selalu gulir untuk melihat output di mana kesalahan terjadi.

Bagaimana saya bisa memfilter teks non-merah?

kode semu:

dolongtask | grep -color red

Edit

Perintah output warna lain juga dan saya harus mampu menyaring keluar semua teks yang tidak merah. Juga pewarnaan teks adalah multiline.

km6zla
sumber
1
Saya minta maaf karena menanyakan yang sudah jelas - tetapi semua output aktif >&1? Maksudku, benda merah tidak hilang jika kau 2>/dev/null, kan?
mikeserv

Jawaban:

15

Pergantian warna dilakukan melalui urutan escape yang tertanam dalam teks. Biasanya, program mengeluarkan urutan pelarian ANSI , karena itulah yang sebenarnya didukung semua terminal saat ini.

Urutan melarikan diri untuk mengalihkan warna latar depan menjadi merah adalah \e[31m, di mana \emenunjuk karakter pelarian (oktal 033, 1b heksadesimal, juga dikenal sebagai ESC, ^[dan berbagai sebutan lainnya). Angka dalam kisaran 30–39 mengatur warna latar depan; nomor lain mengatur atribut yang berbeda. \e[0mmengatur ulang semua atribut ke nilai standarnya. Jalankan cat -vuntuk memeriksa apa yang dicetak oleh program, mungkin menggunakan beberapa varian seperti \e[0;31muntuk mengatur ulang semua atribut terlebih dahulu, atau \e[3;31juga untuk mengaktifkan huruf miring (yang tidak didukung banyak terminal).

Di ksh, bash, atau zsh, Anda dapat menggunakan $'…'untuk mengaktifkan $'\e'escape backslash di dalam tanda kutip, yang memungkinkan Anda mengetik untuk mendapatkan karakter pelarian. Perhatikan bahwa Anda harus menggandakan backslash yang ingin Anda sampaikan grep. Di /bin/sh, Anda bisa menggunakan "$(printf \\e)"atau mengetikkan karakter pelarian literal.

Dengan grep -oopsi GNU , cuplikan berikut memfilter teks merah, dengan asumsi bahwa itu dimulai dengan urutan escape \e[31m, diakhiri dengan salah satu \e[0matau \e[30mpada baris yang sama, dan tidak mengandung urutan escape yang tertanam.

grep -Eo $'\e\\[31m[^\e]*\e\\[[03]?m'

awkCuplikan berikut mengekstrak teks merah, meskipun multiline.

awk -v RS='\033' '
    match($0, /^\[[0-9;]*m/) {
        color = ";" substr($0, 2, RLENGTH-2) ";";
        $0 = substr($0, RLENGTH+1);
        gsub(/(^|;)0*[^03;][0-9]*($|;)/, ";", color);
        red = (color ~ /1;*$/)
    }
    red'

Berikut adalah variasi yang mempertahankan perintah pengubah warna, yang bisa berguna jika Anda memfilter banyak warna (di sini merah dan magenta).

awk -v RS='\033' '
    match($0, /^\[[0-9;]*m/) {
        color = ";" substr($0, 2, RLENGTH-2) ";";
        printf "\033%s", substr($0, 1, RLENGTH);
        $0 = substr($0, RLENGTH+1);
        gsub(/(^|;)0*[^03;][0-9]*($|;)/, ";", color);
        desired = (color ~ /[15];*$/)
    }
    desired'
Gilles 'SANGAT berhenti menjadi jahat'
sumber
Solusi awk bekerja untuk saya. Adakah cara untuk mempertahankan warna dalam keluaran?
km6zla
@ ogc-nick Anda ingin semua-red output? printf '\e[31m'; awk …; printf '\e[0m'
Gilles 'SO- stop being evil'
Hanya untuk warna apa pun yang saya filter untuk dipertahankan dalam output.
km6zla
@ ogc-nick Lihat hasil edit saya.
Gilles 'SO- stop being evil'
6

Anda dapat meminta grep mencari karakter kontrol, beberapa di antaranya bertanggung jawab untuk membuat warna-warna cantik di terminal.

dolongtask | grep '[[:cntrl:]]'

Misalnya, ini menggemakan "tes" merah ke grep, yang menemukannya karena dikelilingi oleh karakter kontrol:

$ echo -e '\033[00;31mtest\033[00m' | grep --color=none '[[:cntrl:]]'
test     <-- in red

Ini --color=nonehanya untuk memastikan grep tidak menerapkan pewarnaannya sendiri untuk output yang cocok, tetapi mencetak seluruh baris dengan setia sehingga karakter kontrol akan ditafsirkan oleh shell.

savanto
sumber
Bagus. Saya ingin tahu apakah seseorang dapat melangkah lebih jauh dan melakukan sesuatu seperti grep -E $'\033\[0?[01];31m.+?\033\[0?0m'atau grep -Po '\033\[0?[01]+;31m\K.+?(?=\033\[0?0m)'menguji untuk warna merah secara khusus?
steeldriver
Saya mulai membuat regex seperti yang Anda sarankan, tetapi sebelum saya bisa membuatnya bekerja, saya tersandung [[:cntrl:]]. Saya menguji Anda dan mereka bekerja untuk saya, yaitu. cocok merah dan gagal untuk mencocokkan warna lain.
savanto
Berfungsi bagus tetapi akan cocok dengan warna apa pun. Saya tidak menyebutkannya dalam pertanyaan tetapi banyak warna lain juga keluaran dan saya hanya ingin melihat hal-hal merah. +1 untuk kode sederhana dan berfungsi.
km6zla