bash: stderr'i kırmızı renkte yazdır


122

Bash ekranını stderr mesajlarını kırmızı renkte yapmanın bir yolu var mı ?


4
Sanırım bash çıktısını asla renklendirmeyecek: bazı programlar bir şeyi ayrıştırmak isteyebilir ve renklendirme, kaçan dizilerle verileri bozar. Bir GUI uygulaması renkleri işlemelidir, sanırım.
kolypto

Balázs Pozsár ve killdash9'un cevabını birleştirerek netliği veriyor: function color { "$@" 2> >(sed $'s,.*,\e[31m&\e[m,') } bash ve zsh için çalışıyor. Bunu bir cevap b / c itibarı olarak ekleyemiyorum.
Heinrich Hartmann

1
Bunu yapmak için bash değiştiren bir cevap bekliyorum. Altındaki çözümler gerçekte stderr'i değiştirir ve hatta stderr'nin tam bayt dizisinin korunması gerektiğinde, örneğin boru tesisatı sırasında korunması gereken şeyleri kıran ile yeniden düzenler.
masterxilo

Yanıtlar:


98
command 2> >(while read line; do echo -e "\e[01;31m$line\e[0m" >&2; done)

6
Harika! Ama bunu kalıcı
kılmanın

9
Harika ipucu! Öneri: >&2Hemen önce ekleyerek ; done), stderr için amaçlanan çıktı aslında stderr'e yazılır. Programın normal çıktısını yakalamak istiyorsanız bu yararlıdır.
henko

8
Aşağıdakiler kullanır tputve bence biraz daha okunaklı:command 2> >(while read line; do echo -e "$(tput setaf 1)$line$(tput sgr0)" >&2; done)
Stefan Lasiewski

2
Her çıkış hattı için 2 tput işlemi yürütmenin hiç de zarif olmadığını düşünüyorum. Belki de tput komutlarının çıktısını bir değişkende saklarsanız ve bunları her yankı için kullanırsanız. Fakat yine de, okunabilirlik gerçekten daha iyi değil.
Balázs Pozsár

1
Bu çözüm boşlukları korumaz, ancak kısayıcılığını seviyorum. IFS= read -r lineyardım etmeli ama etmemeli. Emin değilim neden.
Max Murphy

89

Yöntem 1: işlem değiştirme kullanın:

command 2> >(sed $'s,.*,\e[31m&\e[m,'>&2)

Yöntem 2: Bir bash komut dosyasında bir işlev oluşturun:

color()(set -o pipefail;"$@" 2>&1>&3|sed $'s,.*,\e[31m&\e[m,'>&2)3>&1

Bu şekilde kullanın:

$ color command

Her iki yöntem de komutun stderrkırmızı olduğunu gösterecektir .

Yöntem 2'nin nasıl çalıştığının bir açıklaması için okumaya devam edin. Bu komutun gösterdiği bazı ilginç özellikler var.

  • color()... - Renkli denilen bir bash işlevi oluşturur.
  • set -o pipefail- Bu, çıktısı başka bir komuta aktarılan bir komutun hata dönüş kodunu koruyan bir kabuk seçeneğidir. Bu, dış kabuktaki pipefail seçeneğini değiştirmemek için parantez içinde oluşturulan bir alt kabukta yapılır.
  • "$@"- İşlevin argümanlarını yeni bir komut olarak çalıştırır. "$@"eşittir"$1" "$2" ...
  • 2>&1- stderrKomutun komutunu '' olacak stdoutşekilde yönlendirir .sedstdin
  • >&3- Kısaca 1>&3, bu stdoutyeni bir geçici dosya tanımlayıcısına yönlendirir 3. sonra 3tekrar yönlendirilir stdout.
  • sed ...- Yukarıdaki yönlendirmeler Çünkü sed'ın stdinolduğu stderrkomutun. İşlevi her satırı renk kodlarıyla çevrelemektir.
  • $'...' Ters eğik çizgiden kaçan karakterleri anlamasına neden olan bir bash yapısı
  • .* - Tüm çizgiyle eşleşir.
  • \e[31m - Aşağıdaki karakterlerin kırmızı olmasına neden olan ANSI çıkış sırası
  • &- sedEşleşen dizginin tamamına genişleyen değiştirme karakteri (bu durumda tüm çizgi).
  • \e[m - Rengi sıfırlayan ANSI çıkış sırası.
  • >&2- için Steno 1>&2, bu yönlendirmeleri sed'ler stdoutiçin stderr.
  • 3>&1- Geçici dosya tanımlayıcısını 3tekrar içine yönlendirir stdout.

9
+1 en iyi cevap! absolutly underrated!
muhqu

3
Harika cevap ve daha da iyi bir açıklama
Daniel Serodio 19

Neden tüm ek yönlendirmeleri yapmanız gerekiyor? overkill gibi görünüyor
qodeninja

1
Çalışmasını sağlamanın bir yolu var mı zsh?
Eyal Levin

1
ZSH, kısa yoldan yönlendirme formlarını tanımıyor. Sadece iki tane daha 1'e ihtiyaç duyuyor, yani:zsh: color()(set -o pipefail;"$@" 2>&1 1>&3|sed $'s,.*,\e[31m&\e[m,'1>&2)3>&1
Rekin

26

Ayrıca stderred'ı da kontrol edebilirsiniz: https://github.com/sickill/stderred


Vay, bu yardımcı program harika, ihtiyaç duyacağı tek şey, onu etkinleştirmek için daha fazla iş yapmak zorunda kalmadan, tek bir satırla tüm kullanıcılar için yükleyen uygun bir havuza sahip olmak.
sorin

Ayrı bir terminalde bir derleme betiği ile test ettiğimde iyi çalıştığı görülüyordu, ancak küresel olarak kullanmakta tereddüt ediyorum (in .bashrc). Yine de teşekkürler!
Joel Purra

2
OS X El Capitan'da bunun çalışma şekli (DYLD_INSERT_LIBRARIES) sistem ikili dosyalarında "bozuluyor" çünkü SIP tarafından korunuyorlar. Bu nedenle diğer cevaplarda verilen bash seçeneklerini kullanmak daha iyi olabilir.
hmijail

1
MacOS için @hmijail, lütfen github.com/sickill/stderred/issues/60 adresini takip edin, böylece bir geçici çözüm bulabiliriz, kısmi bir tane zaten var ama birazcık sorunlu.
sorin,

15

Stderr'i kalıcı olarak kırmızı yapmanın bash yolu, akışları yönlendirmek için 'exec' i kullanmaktır. Bashrc'ınıza aşağıdakileri ekleyin:

exec 9>&2
exec 8> >(
    while IFS='' read -r line || [ -n "$line" ]; do
       echo -e "\033[31m${line}\033[0m"
    done
)
function undirect(){ exec 2>&9; }
function redirect(){ exec 2>&8; }
trap "redirect;" DEBUG
PROMPT_COMMAND='undirect;'

Bunu daha önce yayınladım: STDOUT ve STDERR için yazı tipi rengi nasıl ayarlanır



1
Bu, şu ana kadarki en iyi cevap; kurulum / sudo ayrıcalığı gerektirmeden uygulanması kolaydır ve tüm komutlara genelleştirilebilir.
Luke Davis

1
Maalesef bu, komut zincirleme ile iyi bir şekilde çalışmıyor (command && nextCommand || errorHandlerCommand). ErrorHandlerCommand çıktısından sonra hata çıktısı gider.
carlin.scott

1
Benzer şekilde, source ~/.bashrcbununla iki kez yaparsam terminalim kilitlenir.
Dolph

@Dolf: Bashrc'imde, bu kodun yeniden yüklenmesini önlemek için çevreleyen if ifadesiyle kolayca koruyabilirim. Aksi halde, sorun yeniden yönlendirme gerçekleştikten sonra yeniden yönlendirme 'exec 9> & 2' olur. Belki de> 2'nin başlangıçta nereye işaret ettiğini biliyorsanız, bunu sabit olarak değiştirin.
18'de


7

Balázs Pozsár'ın cevabını saf bashta uygulayan bir sarmalayıcı senaryo yazdım. Çıktılarını renklendirmek için $ PATH ve önek komutlarınıza kaydedin.

    #! / Bin / bash

    eğer [$ 1 == "--help"]; sonra
        echo "Bir komutu çalıştırır ve meydana gelen tüm hataları renklendirir"
        echo "Örnek:` basename $ {0} `wget ..."
        echo "(c) o_O Tync, ICQ # 1227-700, tadını çıkarın!"
        Çıkış 0
        fi

    Tüm hataları yakalamak için # Temp dosyası
    TMP_ERRS = $ (mktemp)

    # Komutu çalıştır
    "$ @" 2>> (okuma satırında; echo -e "\ e [01; 31m $ satır \ e [0m" | tee - $ TMP_ERRS; yapılır)
    EXIT_CODE = $?

    # Tüm hataları tekrar göster
    eğer [-s "$ TMP_ERRS"]; sonra
        echo -e "\ n \ n \ n \ e [01; 31m === HATALAR === \ e [0m"
        cat $ TMP_ERRS
        fi
    rm -f $ TMP_ERRS

    # Bitiş
    $ EXIT_CODE


2
Bu "| tee ..." "yapıldıktan sonra" konduysa daha verimli yapılabilir.
Juliano

3

Böyle bir işlevi kullanabilirsiniz


 #!/bin/sh

color() {
      printf '\033[%sm%s\033[m\n' "$@"
      # usage color "31;5" "string"
      # 0 default
      # 5 blink, 1 strong, 4 underlined
      # fg: 31 red,  32 green, 33 yellow, 34 blue, 35 purple, 36 cyan, 37 white
      # bg: 40 black, 41 red, 44 blue, 45 purple
      }
string="Hello world!"
color '31;1' "$string" >&2

Stderr'e yazdırmak için> 2 eklerim


4
Sorunu çözmemek. Stderr'i stdout'tan ayırmanın bir yolunu bulamadınız, bu OP'nin ilgilendiği şey.
Jeremy Visser

1

Ben O_o Tync'in betiğinin biraz değiştirilmiş bir sürümüne sahibim. Bu modları OS X Lion için yapmam gerekiyordu ve mükemmel değildi çünkü senaryo bazen sarılmış komuttan önce tamamlanıyor. Bir uyku ekledim ama daha iyi bir yol olduğuna eminim.

#!/bin/bash

   if [ $1 == "--help" ] ; then
       echo "Executes a command and colorizes all errors occured"
       echo "Example: `basename ${0}` wget ..."
       echo "(c) o_O Tync, ICQ# 1227-700, Enjoy!"
       exit 0
       fi

   # Temp file to catch all errors
   TMP_ERRS=`mktemp /tmp/temperr.XXXXXX` || exit 1

   # Execute command
   "$@" 2> >(while read line; do echo -e "$(tput setaf 1)$line\n" | tee -a $TMP_ERRS; done)
   EXIT_CODE=$?

   sleep 1
   # Display all errors again
   if [ -s "$TMP_ERRS" ] ; then
       echo -e "\n\n\n$(tput setaf 1) === ERRORS === "
       cat $TMP_ERRS
   else
       echo "No errors collected in $TMP_ERRS"
   fi
   rm -f $TMP_ERRS

   # Finish
   exit $EXIT_CODE

1

Bu çözüm benim için çalıştı: https://superuser.com/questions/28869/immediately-tell-which-output-was-sent-to-stderr

Bu işlevi şuna .bashrcveya içine koydum .zshrc:

# Red STDERR
# rse <command string>
function rse()
{
    # We need to wrap each phrase of the command in quotes to preserve arguments that contain whitespace
    # Execute the command, swap STDOUT and STDERR, colour STDOUT, swap back
    ((eval $(for phrase in "$@"; do echo -n "'$phrase' "; done)) 3>&1 1>&2 2>&3 | sed -e "s/^\(.*\)$/$(echo -en \\033)[31;1m\1$(echo -en \\033)[0m/") 3>&1 1>&2 2>&3
}

Sonra örneğin:

$ rse cat non_existing_file.txt

bana kırmızı bir çıktı verecek.


Yönlendirme çıkış kodu için daha set -o pipefail;önce ekleyebilirsiniz(eval
kvaps

Ayrıca ekleme "argüman olarak boşluklarının muhafaza edilmesi için eval
kvaps


0

fifos kullanan bir sürüm

mkfifo errs
stdbuf -o0 -e0 -i0 grep . foo | while read line; do echo -e "\e[01;31m$line  \e[0m" >&2; done &
stdbuf -o0 -e0 -i0 sh $script 2>errs
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.