bash: in stderr màu đỏ


123

Có cách nào để làm cho bash hiển thị thông điệp stderr màu đỏ không?


4
Tôi đoán bash sẽ không bao giờ tô màu đầu ra của nó: một số chương trình có thể muốn phân tích một cái gì đó và việc tô màu sẽ làm hỏng dữ liệu với các chuỗi thoát. Một ứng dụng GUI nên xử lý màu sắc, tôi đoán vậy.
kolypto

Kết hợp câu trả lời của Balázs Pozsár và killdash9 mang lại sự sinh động: function color { "$@" 2> >(sed $'s,.*,\e[31m&\e[m,') } Hoạt động cho bash và zsh. Không thể thêm điều này như một câu trả lời danh tiếng.
Heinrich Hartmann

1
Tôi đang chờ đợi một câu trả lời sửa đổi bash để làm điều này. Tất cả các giải pháp bên dưới đều thực sự sửa đổi thiết bị lỗi chuẩn và thậm chí có thể sắp xếp lại nó, thiết bị xuất chuẩn sẽ phá vỡ mọi thứ khi chuỗi byte chính xác của thiết bị xuất chuẩn phải được bảo toàn, ví dụ như khi đường ống.
masterxilo

Câu trả lời:


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

6
Tuyệt quá! Nhưng tôi tự hỏi nếu có một cách để làm cho nó vĩnh viễn :)
kolypto

9
Mẹo tuyệt vời! Gợi ý: Bằng cách thêm >&2ngay trước đó ; done), đầu ra dành cho stderr thực sự được ghi vào stderr. Điều đó hữu ích nếu bạn muốn nắm bắt đầu ra bình thường của chương trình.
henko

8
Theo tôi, những cách sử dụng sau đây tputvà dễ đọc hơn một chút:command 2> >(while read line; do echo -e "$(tput setaf 1)$line$(tput sgr0)" >&2; done)
Stefan Lasiewski

2
Tôi nghĩ rằng việc thực hiện 2 quy trình xử lý cho mỗi dòng đầu ra là không thanh lịch chút nào. Có lẽ nếu bạn sẽ lưu trữ đầu ra của các lệnh tput trong một biến và sử dụng chúng cho mỗi echo. Nhưng một lần nữa, khả năng đọc không thực sự tốt hơn.
Balázs Pozsár

1
Giải pháp này không bảo toàn khoảng trắng nhưng tôi thích nó vì sự ngắn gọn của nó. IFS= read -r linenên giúp nhưng không được. Không chắc chắn lý do tại sao.
Max Murphy

89

Phương pháp 1: Sử dụng thay thế quá trình:

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

Phương pháp 2: Tạo một hàm trong tập lệnh bash:

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

Sử dụng nó như thế này:

$ color command

Cả hai phương thức sẽ hiển thị lệnh stderrmàu đỏ.

Tiếp tục đọc để giải thích về cách thức hoạt động của phương pháp 2. Có một số tính năng thú vị được thể hiện bằng lệnh này.

  • color()... - Tạo một hàm bash gọi là màu.
  • set -o pipefail- Đây là một tùy chọn shell bảo tồn mã trả về lỗi của một lệnh có đầu ra được dẫn vào một lệnh khác. Điều này được thực hiện trong một lớp con, được tạo bởi dấu ngoặc đơn, để không thay đổi tùy chọn đường ống ở lớp vỏ ngoài.
  • "$@"- Thực hiện các đối số cho hàm như một lệnh mới. "$@"tương đương với"$1" "$2" ...
  • 2>&1- Chuyển hướng các stderrlệnh để stdoutsao cho nó trở nên sed's stdin.
  • >&3- Viết tắt cho 1>&3, điều này chuyển hướng stdoutđến một mô tả tập tin tạm thời mới 3. 3được chuyển trở lại vào stdoutsau.
  • sed ...- Do các chuyển hướng ở trên, sed's stdinstderrlệnh được thực thi. Chức năng của nó là bao quanh mỗi dòng với mã màu.
  • $'...' Cấu trúc bash khiến nó hiểu các ký tự thoát dấu gạch chéo ngược
  • .* - Phù hợp với toàn bộ dòng.
  • \e[31m - Trình tự thoát ANSI làm cho các ký tự sau có màu đỏ
  • &- Ký sedtự thay thế mở rộng ra toàn bộ chuỗi khớp (toàn bộ dòng trong trường hợp này).
  • \e[m - Trình tự thoát ANSI đặt lại màu.
  • >&2- Viết tắt cho 1>&2, điều này chuyển hướng sed's stdoutđể stderr.
  • 3>&1- Chuyển hướng mô tả tập tin tạm thời 3trở lại stdout.

9
+1 câu trả lời hay nhất! hoàn toàn bị đánh giá thấp!
muhqu

3
Câu trả lời tuyệt vời và giải thích thậm chí tốt hơn
Daniel Serodio

Tại sao bạn cần phải làm tất cả các chuyển hướng bổ sung? có vẻ như quá mức cần thiết
qodeninja

1
Có cách nào để làm cho nó hoạt động zsh?
Mắt Levin

1
ZSH không nhận ra các hình thức chuyển hướng tốc ký. Nó chỉ cần thêm hai zsh: color()(set -o pipefail;"$@" 2>&1 1>&3|sed $'s,.*,\e[31m&\e[m,'1>&2)3>&1
giây

26

Bạn cũng có thể xem stderred: https://github.com/sickill/stderred


Wow, tiện ích này rất tuyệt, điều duy nhất nó cần là có một kho chứa apt cài đặt nó cho tất cả người dùng, với một dòng, không phải làm thêm việc để kích hoạt nó.
sorin

Có vẻ hoạt động tốt khi tôi thử nghiệm nó với một tập lệnh xây dựng trong một thiết bị đầu cuối riêng biệt, nhưng tôi ngần ngại sử dụng nó trên toàn cầu (in .bashrc). Cảm ơn mặc dù!
Joel Purra

2
Trong OS X El Capitan, cách thức hoạt động của nó (DYLD_INSERT_LIBRARIES) bị "hỏng" trong các nhị phân hệ thống vì chúng được SIP bảo vệ. Vì vậy, có thể tốt hơn để sử dụng các tùy chọn bash được đưa ra trong các câu trả lời khác.
hmijail

1
@hmijail cho MacOS, vui lòng theo dõi github.com/sickill/stderred/issues/60 để chúng tôi có thể tìm thấy một cách giải quyết, một phần đã tồn tại nhưng có một chút lỗi.
sorin

15

Cách bash làm stderr đỏ vĩnh viễn là sử dụng 'exec' để chuyển hướng luồng. Thêm phần sau vào bashrc của bạn:

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

Tôi đã đăng trên này trước đây: Cách đặt màu phông chữ cho STDOUT và STDERR



1
Đây là câu trả lời tốt nhất cho đến nay; dễ dàng thực hiện mà không cần cài đặt / yêu cầu đặc quyền sudo và có thể khái quát cho tất cả các lệnh.
Luke Davis

1
Thật không may, điều này không chơi tốt với chuỗi lệnh (lệnh && nextCommand || errorHandlerCommand). Đầu ra lỗi đi sau đầu ra errorHandlerCommand.
carlin.scott

1
Tương tự, nếu tôi source ~/.bashrchai lần với điều này, thiết bị đầu cuối của tôi về cơ bản khóa.
Dolph

@Dolf: Trong bashrc của tôi, tôi dễ dàng bảo vệ chống lại điều này bằng một câu lệnh if xung quanh để ngăn mã này tải lại. Mặt khác, vấn đề là chuyển hướng 'exec 9> & 2' sau khi chuyển hướng đã diễn ra. Có lẽ thay đổi nó thành một hằng số nếu bạn biết nơi> 2 đang chỉ vào ban đầu.
Tin mừng


7

Tôi đã tạo một kịch bản bao bọc thực hiện câu trả lời của Balázs Pozsár trong bash thuần túy. Lưu nó trong các lệnh $ PATH và tiền tố của bạn để tô màu đầu ra của chúng.

    #! / bin / bash

    if [$ 1 == "- trợ giúp"]; sau đó
        echo "Thực thi một lệnh và tô màu tất cả các lỗi xảy ra"
        echo "Ví dụ:` tên cơ sở $ {0} `wget ..."
        tiếng vang "(c) o_O Tync, ICQ # 1227-700, Hãy tận hưởng!"
        thoát 0
        fi

    # Tệp tạm thời để bắt tất cả các lỗi
    TMP_ERRS = $ (mktemp)

    # Thực thi lệnh
    "$ @" 2 >> (trong khi đọc dòng; làm echo -e "\ e [01; 31m $ line \ e [0m" | tee --append $ TMP_ERRS; xong)
    EXIT_CODE = $?

    # Hiển thị lại tất cả các lỗi
    nếu [-s "$ TMP_ERRS"]; sau đó
        tiếng vang -e "\ n \ n \ n \ e [01; 31m === LRI === \ e [0m"
        mèo $ TMP_ERRS
        fi
    rm -f $ TMP_ERRS

    # Hoàn thành
    thoát $ EXIT_CODE


2
Điều này có thể được thực hiện hiệu quả hơn nếu "| tee ..." được đặt sau khi "hoàn thành".
Juliano

3

Bạn có thể sử dụng một chức năng như thế này


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

Tôi chắp thêm> & 2 để in lên stderr


4
Không giải quyết vấn đề. Bạn chưa cung cấp cách tách stderr khỏi thiết bị xuất chuẩn, đó là điều mà OP quan tâm.
Jeremy Visser

1

Tôi có một phiên bản sửa đổi một chút của tập lệnh của O_o Tync. Tôi cần phải tạo các mod này cho OS X Lion và nó không hoàn hảo vì tập lệnh đôi khi hoàn thành trước khi lệnh được gói. Tôi đã thêm một giấc ngủ nhưng tôi chắc chắn có một cách tốt hơn.

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

Giải pháp này hiệu quả với tôi: https://superuser.com/questions/28869/immediately-tell-which-output-was-sent-to-stderr

Tôi đã đặt chức năng này trong .bashrchoặc .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
}

Sau đó, ví dụ:

$ rse cat non_existing_file.txt

sẽ cho tôi một đầu ra màu đỏ.


Bạn có thể thêm set -o pipefail;trước (evalđể chuyển hướng mã thoát
kvaps

đồng thời thêm "eval để giữ khoảng trắng trong các đối số
kvaps


0

một phiên bản sử dụng 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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.