bash: พิมพ์ stderr ด้วยสีแดง


122

มีวิธีทำ bash แสดงข้อความstderrในสีแดง?


4
ฉันเดาว่า bash จะไม่ทำให้สีของมันออกมา: โปรแกรมบางโปรแกรมอาจต้องการแยกวิเคราะห์บางอย่างและการทำให้ colorizing จะทำให้ข้อมูลเสียหายด้วยลำดับที่หลีกเลี่ยง แอพ GUI ควรจัดการกับสีฉันเดา
kolypto

การรวมBalázsPozsárและคำตอบ killdash9 จะให้ความคมชัด: ใช้ function color { "$@" 2> >(sed $'s,.*,\e[31m&\e[m,') } งานได้กับทุบตีและ zsh ไม่สามารถเพิ่มสิ่งนี้เป็นคำตอบ b / c ชื่อเสียง
Heinrich Hartmann

1
ฉันรอคำตอบที่แก้ไขทุบตีเพื่อทำสิ่งนี้ โซลูชันด้านล่างทั้งหมดแก้ไข stderr จริงและอาจเรียงลำดับใหม่ wrt stdout ซึ่งแบ่งสิ่งต่าง ๆ เมื่อลำดับไบต์ที่แน่นอนของ stderr ต้องถูกเก็บรักษาไว้เช่นเมื่อทำการไพพ์
masterxilo

คำตอบ:


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

6
ที่ดี! แต่ฉันสงสัยว่ามีวิธีที่จะทำให้มัน :) ถาวร
kolypto

9
สุดยอดเคล็ดลับ! คำแนะนำ: โดยการเพิ่ม>&2ก่อนหน้า; done)นี้เอาต์พุตที่มีไว้สำหรับ stderr จริงๆแล้วจะถูกเขียนไปยัง stderr มีประโยชน์ถ้าคุณต้องการบันทึกผลลัพธ์ปกติของโปรแกรม
henko

8
การใช้งานต่อไปนี้tputและสามารถอ่านได้ในความคิดของฉันเล็กน้อย:command 2> >(while read line; do echo -e "$(tput setaf 1)$line$(tput sgr0)" >&2; done)
Stefan Lasiewski

2
ฉันคิดว่าการดำเนินการ 2 กระบวนการ tput สำหรับแต่ละบรรทัดเอาต์พุตนั้นไม่ได้สวยงามเลย บางทีถ้าคุณจะเก็บเอาต์พุตของคำสั่ง tput ในตัวแปรและใช้คำสั่งนั้นสำหรับแต่ละ echo แต่จากนั้นอีกครั้งการอ่านไม่ได้ดีขึ้นจริงๆ
BalázsPozsár

1
วิธีนี้ไม่ได้รักษาช่องว่าง แต่ฉันชอบมันเพื่อความกะทัดรัด IFS= read -r lineควรช่วย แต่ไม่ ไม่แน่ใจว่าทำไม
Max Murphy

89

วิธีที่ 1: ใช้การทดแทนกระบวนการ:

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

วิธีที่ 2: สร้างฟังก์ชันในสคริปต์ทุบตี:

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

ใช้แบบนี้:

$ color command

ทั้งสองวิธีจะแสดงคำสั่งเป็นstderrสีแดง

อ่านต่อเพื่อดูคำอธิบายวิธีการทำงานของวิธีที่ 2 มีคุณสมบัติที่น่าสนใจที่แสดงโดยคำสั่งนี้

  • color()... - สร้างฟังก์ชั่นทุบตีที่เรียกว่าสี
  • set -o pipefail- นี่คือตัวเลือกเชลล์ที่เก็บรักษาโค้ดส่งคืนข้อผิดพลาดของคำสั่งที่มีการส่งออกไพพ์ไปยังคำสั่งอื่น สิ่งนี้ทำใน subshell ซึ่งสร้างโดยวงเล็บเพื่อไม่ให้เปลี่ยนตัวเลือก pipefail ในเปลือกนอก
  • "$@"- ดำเนินการขัดแย้งกับฟังก์ชั่นเป็นคำสั่งใหม่ "$@"เทียบเท่ากับ"$1" "$2" ...
  • 2>&1- เปลี่ยนเส้นทางstderrของคำสั่งการstdoutเพื่อที่จะกลายเป็นsedstdin
  • >&3- ชวเลขสำหรับ1>&3นี้เปลี่ยนเส้นทางไปยังอธิบายไฟล์ใหม่ชั่วคราว stdout ถูกส่งกลับเข้าไปในภายหลัง33stdout
  • sed ...- เนื่องจากการเปลี่ยนเส้นทางข้างต้นsed's stdinเป็นstderrคำสั่งประหารชีวิต ฟังก์ชั่นคือการล้อมรอบแต่ละบรรทัดด้วยรหัสสี
  • $'...' โครงสร้างทุบตีที่ทำให้เข้าใจอักขระที่ใช้เครื่องหมายแบคสแลช
  • .* - จับคู่ทั้งบรรทัด
  • \e[31m - ลำดับ ANSI escape ที่ทำให้อักขระต่อไปนี้เป็นสีแดง
  • &- sedอักขระแทนที่ที่ขยายเป็นสตริงที่ตรงกันทั้งหมด (ทั้งบรรทัดในกรณีนี้)
  • \e[m - ลำดับ ANSI escape ที่รีเซ็ตสี
  • >&2- ชวเลขสำหรับ1>&2นี้เปลี่ยนเส้นทางsedของการstdoutstderr
  • 3>&1- เปลี่ยนเส้นทางบ่งแฟ้มชั่วคราว3กลับเข้าstdoutมา

9
+1 คำตอบที่ดีที่สุด! underrated อย่างแน่นอน!
muhqu

3
คำตอบที่ยอดเยี่ยมและคำอธิบายที่ดียิ่งขึ้น
Daniel Serodio

ทำไมคุณต้องทำการเปลี่ยนเส้นทางเพิ่มเติมทั้งหมด? ดูเหมือน overkill
qodeninja

1
มีวิธีที่จะทำให้มันทำงานได้zshหรือไม่?
Eyal Levin

1
ZSH ไม่รู้จักรูปแบบการเปลี่ยนเส้นทางชวเลข มันแค่ต้องการอีกสองตัวคือ:zsh: color()(set -o pipefail;"$@" 2>&1 1>&3|sed $'s,.*,\e[31m&\e[m,'1>&2)3>&1
Rekin

26

นอกจากนี้คุณยังสามารถดู stderred: https://github.com/sickill/stderred


ว้าวยูทิลิตี้นี้ยอดเยี่ยมสิ่งเดียวที่มันจะต้องมีคือที่เก็บ apt ที่ติดตั้งไว้สำหรับผู้ใช้ทุกคนด้วยบรรทัดเดียวไม่ต้องทำงานมากขึ้นเพื่อเปิดใช้งาน
โซริน

ดูเหมือนว่าจะทำงานได้ดีเมื่อฉันทดสอบด้วยสคริปต์การสร้างในเทอร์มินัลแยกต่างหาก แต่ฉันลังเลที่จะใช้งานทั่วโลก (ใน.bashrc) ขอบคุณนะ!
Joel Purra

2
ใน OS X El Capitan วิธีการทำงาน (DYLD_INSERT_LIBRARIES) นี้เป็น "เสีย" ในไบนารีระบบเนื่องจากได้รับการคุ้มครองโดย SIP ดังนั้นจึงเป็นการดีกว่าถ้าใช้ตัวเลือก bash ที่ให้ไว้ในคำตอบอื่น
hmijail

1
@hmijail สำหรับ MacOS โปรดติดตามgithub.com/sickill/stderred/issues/60เพื่อให้เราสามารถหาวิธีแก้ปัญหาได้มีบางส่วนที่มีอยู่แล้ว แต่เป็นรถเล็ก ๆ น้อย ๆ
sorin

15

วิธีทุบตีในการทำให้stderrเป็นสีแดงอย่างถาวรคือการใช้ 'exec' เพื่อเปลี่ยนเส้นทางสตรีม เพิ่มสิ่งต่อไปนี้ใน bashrc ของคุณ:

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;'

ฉันโพสต์เมื่อก่อนหน้านี้: วิธีการตั้งค่าสีตัวอักษรสำหรับ STDOUT และ STDERR


เกี่ยวข้อง: unix.stackexchange.com/questions/367636/…
phil294

1
นี่เป็นคำตอบที่ดีที่สุด ติดตั้งง่าย / ไม่ต้องใช้สิทธิ์ sudo และสามารถใช้กับคำสั่งทั้งหมดได้
ลุคเดวิส

1
น่าเสียดายที่สิ่งนี้เล่นได้ไม่ดีนักกับการผูกมัดคำสั่ง (command && nextCommand || errorHandlerCommand) เอาต์พุตข้อผิดพลาดเกิดขึ้นหลังจากข้อผิดพลาด outputHandlerCommand
carlin.scott

1
ในทำนองเดียวกันถ้าฉันsource ~/.bashrcสองครั้งด้วยสิ่งนี้ขั้วของฉันล็อคโดยทั่วไป
Dolph

@ ดอล์ฟ: ใน bashrc ของฉันฉันสามารถป้องกันสิ่งนี้ได้โดยง่ายถ้ามีคำสั่งเพื่อป้องกันไม่ให้โค้ดนี้โหลดซ้ำ มิฉะนั้นปัญหาคือการเปลี่ยนเส้นทาง 'exec 9> & 2' หลังจากการเปลี่ยนเส้นทางเกิดขึ้นแล้ว อาจเปลี่ยนเป็นค่าคงที่ถ้าคุณรู้ว่า> 2 ชี้ไปที่จุดเริ่มต้น
พระประวัติ


7

ฉันสร้างสคริปต์ตัวคลุมที่ใช้คำตอบของBalázsPozsárในการทุบตีบริสุทธิ์ บันทึกไว้ในคำสั่ง $ PATH และคำนำหน้าเพื่อเปลี่ยนสีเอาต์พุตของพวกเขา

    #! / bin / ทุบตี

    ถ้า [$ 1 == "- ช่วยเหลือ"]; แล้วก็
        echo "เรียกใช้งานคำสั่งและ colorize ข้อผิดพลาดทั้งหมดที่เกิดขึ้น"
        echo "ตัวอย่าง:` basename $ {0} `wget ... "
        echo "(c) o_O Tync, ICQ # 1227-700, Enjoy!"
        ออก 0
        Fi

    # ไฟล์ชั่วคราวเพื่อตรวจจับข้อผิดพลาดทั้งหมด
    TMP_ERRS = $ (mktemp)

    # รันคำสั่ง
    "$ @" 2>> (ในขณะที่อ่านบรรทัด; ทำ echo -e "\ e [01; 31m $ line \ e [0m" | tee - เพิ่ม $ TMP_ERRS; เสร็จแล้ว)
    EXIT_CODE = $?

    # แสดงข้อผิดพลาดทั้งหมดอีกครั้ง
    ถ้า [-s "$ TMP_ERRS"]; แล้วก็
        echo -e "\ n \ n \ n \ e [01; 31m === ข้อผิดพลาด === \ e [0m"
        cat $ TMP_ERRS
        Fi
    rm -f $ TMP_ERRS

    # เสร็จสิ้น
    ออกจาก $ EXIT_CODE


2
สิ่งนี้จะทำให้มีประสิทธิภาพมากขึ้นถ้า "| tee ... " ถูกวางหลังจาก "เสร็จสิ้น"
Juliano

3

คุณสามารถใช้ฟังก์ชั่นเช่นนี้


 #!/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

ฉันผนวก> & 2 เพื่อพิมพ์ไปยัง stderr


4
ไม่ได้แก้ไขปัญหา คุณไม่ได้ให้วิธีการแยกจาก stderr stdout ซึ่งเป็นสิ่งที่ OP มีความสนใจใน.
เจเรมีไขควง

1

ฉันมีสคริปต์ของ O_o Tync เวอร์ชันแก้ไขเล็กน้อย ฉันต้องการทำให้ mods เหล่านี้สำหรับ OS X Lion และมันไม่สมบูรณ์แบบเพราะบางครั้งสคริปต์จะเสร็จสิ้นก่อนที่คำสั่ง wrapper จะทำ ฉันได้เพิ่มการนอนหลับ แต่ฉันแน่ใจว่ามีวิธีที่ดีกว่า

#!/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

วิธีนี้ใช้ได้ผลกับฉัน: https://superuser.com/questions/28869/immediately-tell-which-output-was-sent-to-stderr

ฉันได้ใส่ฟังก์ชั่นนี้ในของฉัน.bashrcหรือ.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
}

ตัวอย่างเช่น:

$ rse cat non_existing_file.txt

จะให้ผลลัพธ์เป็นสีแดง


คุณสามารถเพิ่มset -o pipefail;ก่อน(evalเพื่อเปลี่ยนรหัสออก
kvaps

นอกจากนี้ยังเพิ่มการ"eval เพื่อรักษาช่องว่างในการขัดแย้ง
kvaps


0

รุ่นที่ใช้Fifos

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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.