Bagaimana Anda hanya mewarnai beberapa kata kunci untuk skrip bash?

10

Saya menjalankan beberapa kode uji unit. Kode tes unit menghasilkan teks biasa. Ada banyak teks jadi saya ingin menyoroti untuk kata kunci penting pengguna.

Dalam hal ini kata kunci adalah "LULUS" dan "GAGAL".

Bagaimana Anda mewarnai "LULUS" menjadi hijau dan "GAGAL" menjadi merah?

Trevor Boyd Smith
sumber
Pernahkah Anda berpikir untuk menekan stdout / stderr dari tes yang lulus, dan hanya mencetak stdout / stderr untuk tes yang gagal? PHPUnit melakukan ini, atau dapat dikonfigurasi untuk melakukan ini. Saya telah menemukan bahwa pendekatan ini berfungsi dengan baik, YMMV.
Clayton Stanley

Jawaban:

8

supercat tampaknya melakukan apa yang Anda cari.

Paket: supercat
Deskripsi-id: program yang mewarnai teks untuk terminal dan HTML
 Supercat adalah program yang mewarnai teks berdasarkan pencocokan biasa
 ekspresi / string / karakter. Supercat mendukung output html juga
 sebagai teks ASCII standar. Berbeda dengan beberapa program pewarnaan teks itu
 ada, Supercat tidak mengharuskan Anda harus menjadi seorang programmer
 membuat aturan pewarnaan.
Situs web: http://supercat.nosredna.net/

Tampaknya tidak ada cara untuk mengatakan apa yang harus diwarnai pada baris perintah, Anda harus menentukan file konfigurasi.

Sepertinya saya ingat dulu ada program yang disebut 'hilite' atau 'hl' yang menyorot teks yang cocok dengan pola (seperti grep --colour, tetapi juga menampilkan garis yang tidak cocok), tetapi saya tidak dapat menemukannya ketika saya mencarinya.

Akhirnya, GNU grepdapat digunakan untuk menyoroti pola - tetapi hanya satu warna yang dapat digunakan (yaitu Anda tidak dapat memiliki PASS berwarna hijau dan GAGAL merah, keduanya akan disorot dengan warna yang sama).

Pipa data Anda melalui sesuatu seperti ini:

egrep --color "\b(PASS|FAIL)\b|$"

Contoh ini menggunakan egrep (alias grep -E), tetapi -Gregexp dasar, -Fstring-tetap, dan -PPCRE juga berfungsi.

Semua pertandingan akan disorot. Defaultnya merah, atau atur GREP_COLOR env var.

Kunci dari kerja ini adalah bahwa final |$dalam pola cocok dengan end-of-line (yaitu semua garis cocok) sehingga semua garis akan ditampilkan (tetapi tidak diwarnai).

The \badalah kata-batas penanda sehingga cocok misalnya FAIL tapi tidak KEGAGALAN. mereka tidak perlu, jadi hapuslah jika Anda ingin mencocokkan kata-kata parsial.

Inilah contoh skrip wrapper untuk supercat yang saya tulis kemarin. Ini berfungsi, tetapi dalam menulisnya, saya menemukan bahwa supercat tidak memiliki opsi untuk pencarian case-sensitive. IMO, yang membuat program secara signifikan kurang bermanfaat. Itu, bagaimanapun, sangat menyederhanakan skrip karena saya tidak perlu menulis opsi '-i' :)

#! /bin/bash 

# Requires: tempfile from debian-utils, getopt from util-linux, and supercat

SCRIPTNAME=$(basename $0)
CFGFILE=$(tempfile -p spc)

usage() {
  cat <<__EOF__
Highlight regexp patterns found on stdin or files specified on command
line with specified colours.

Usage: $SCRIPTNAME [ --colour "pattern" ...] [FILE]

Options:

        -k,--black   regexp
        -r,--red     regexp
        -g,--green   regexp
        -y,--yellow  regexp
        -b,--blue    regexp
        -m,--magenta regexp
        -c,--cyan    regexp
        -w,--white   regexp

Example:

    run-script.sh | $SCRIPTNAME --green PASS --red FAIL

__EOF__
  exit 0
}


# Format definition from the spc man page:
#1234567890123456789012345678901234567890123456789012345
#HTML Color Name      Col A N T RE / String / Characters
FMT="%-20s %3s %1s %1s %1s (%s)\n"

add_color_to_config() {
  COLOR="$1"
  PATTERN="$2"

  printf "$FMT" "$COLOR" "$COLOR" - 0 r "$PATTERN" >> "$CFGFILE"
}


# uses the "getopt" program from util-linux, which supports long
# options. The "getopts" built-in to bash does not.
TEMP=$(getopt \
       -o 'hk:r:g:y:b:m:c:w:' \
       -l 'help,black:,red:,green:,yellow:,blue:,magenta:,cyan:,white:' \
       -n "$0" -- "$@")

if [ $? != 0 ] ; then echo "Terminating..." >&2 ; exit 1 ; fi

eval set -- "$TEMP"

while true ; do
    case "$1" in
        -k|--bla*)       add_color_to_config blk "$2" ; shift 2 ;;
        -r|--red)        add_color_to_config red "$2" ; shift 2 ;;
        -g|--gre*)       add_color_to_config grn "$2" ; shift 2 ;;
        -y|--yel*)       add_color_to_config yel "$2" ; shift 2 ;;
        -b|--blu*)       add_color_to_config blu "$2" ; shift 2 ;;
        -m|--mag*)       add_color_to_config mag "$2" ; shift 2 ;;
        -c|--cya*)       add_color_to_config cya "$2" ; shift 2 ;;
        -w|--whi*)       add_color_to_config whi "$2" ; shift 2 ;;

        -h|--hel*)       usage ; exit 0 ;;

        --)         shift ; break ;;

        *)          echo 'Unknown option!' ; exit 1 ;;
    esac
done

spc -R -c "$CFGFILE" "$@"
rm -f "$CFGFILE"
cas
sumber
1
BTW, jika Anda menggunakan, supercatAnda bisa memodifikasi skrip yang Anda posting untuk menghasilkan file konfigurasi sementara berdasarkan argumen baris perintah, dan kemudian memanggil spc -c /path/to/your/temp/config. Ini akan memungkinkan Anda untuk dengan mudah menentukan warna yang berbeda untuk pola yang berbeda pada baris perintah.
cas
juga btw, saya menulis skrip pembungkus sederhana untuk melakukan itu. saya harus masuk kerja sekarang tetapi saya akan membersihkannya, menambahkan beberapa komentar, dll dan mempostingnya hari ini.
cas
5

Berikut ini skrip tujuan umum untuk mewarnai pola regex (mungkin perlu diperbaiki):

#! /bin/bash

color_to_num () {
  case $1 in
    black)  echo 0;;
    red)    echo 1;;
    green)  echo 2;;
    yellow) echo 3;;
    blue)   echo 4;;
    purple) echo 5;;
    cyan)   echo 6;;
    white)  echo 7;;
    *)      echo 0;;
  esac
}

# default values for foreground and background colors
bg=
fg=
bold="$(tput bold)"
italics=""
boundary=""

while getopts f:b:sli option; do
  case "$option" in
    f) fg="$OPTARG";;
    b) bg="$OPTARG";;
    s) bold="";;
    l) boundary=".*";;
    i) italics="$(tput sitm)";;
  esac
done

shift $(($OPTIND - 1))

pattern="$*"

if [ -n "$fg" ]; then
  fg=$(tput setaf $(color_to_num $fg))
fi
if [ -n "$bg" ]; then
  bg=$(tput setab $(color_to_num $bg))
fi

if [ -z "$fg$bg" ]; then
  fg=$(tput smso)
fi

sed "s/${boundary}${pattern}${boundary}/${bold}${italics}${fg}${bg}&$(tput sgr0)/g"

Beri nama hilite.shdan gunakan dengan cara ini:

$ ./BIN_PROGRAM | hilite.sh -f green PASS | hilite.sh -f red FAIL

$ # Here is an example one liner
$ echo -e "line 1: PASS\nline 2: FAIL" | hilite.sh -f green PASS | hilite.sh -f red FAIL
Trevor Boyd Smith
sumber
Saya membuat ini community wikikarena solusi saya tidak bekerja.
Trevor Boyd Smith
Cara mudah untuk menguji adalah membuat skrip lain yang menggemakan teks dengan kata kunci "LULUS" dan "GAGAL". Itu kemudian akan disebut dengan skrip ini.
Trevor Boyd Smith
Agak keluar dari topik, tetapi saya harus menunjukkan bahwa mengurai output $BINvia evalsubstitusi perintah mungkin rapuh, rumit, dan benar-benar berbahaya. STDOUT adalah stream dan umumnya dimaksudkan untuk diproses oleh stream like tools. Mencoba untuk menangkap seluruh aliran dalam suatu variabel tidak terlalu efisien. Juga, evalsangat kuat , jadi gunakan saja jika Anda benar-benar tahu apa yang Anda lakukan.
jw013
Saya mengganti script dengan yang berfungsi.
angus
@angus, IMO skrip yang benar-benar bagus dan mengesankan.
Trevor Boyd Smith
3

Menanamkan string sewenang-wenang (seperti tputoutput) ke dalam sedekspresi pengganti bermasalah karena Anda harus memastikan (dengan melarikan diri) string tersebut adalah sedsintaks yang valid , yang mana lebih banyak kerumitan yang sebaiknya dihindari. Saya akan menggunakan awksebagai gantinya. Sebagai contoh:

{ echo line 1: PASS; echo line 2: FAIL; } | 
    awk -v "red=$(tput setaf 1)" -v "green=$(tput setaf 2)" \
        -v "reset=$(tput sgr0)" '
    { for (i = 1; i <= NF; i++) {
           if ($i == "FAIL") printf "%s", red "FAIL" reset;
           else if ($i == "PASS") printf "%s", green "PASS" reset;
           else printf "%s", $i

           if (i == NF) printf "%s", ORS
           else printf "%s", OFS 
      }}'

Kuncinya adalah untuk menetapkan tputurutan ke awkvariabel, dilakukan di sini menggunakan -vopsi.

jw013
sumber
Saya menjalankan program Anda dan melakukan apa yang diperlukan. Sabas! Tapi sayangnya saya bukan guru awk jadi saya kesulitan memahami apa yang sedang terjadi. Perbaiki saya di mana saya salah. Untuk setiap baris baru, awk dijalankan? Loop for dalam kode sumber awk sedang melakukan: "untuk semua token di baris"? lalu memproses setiap token?
Trevor Boyd Smith
Awk berpikir dalam hal bidang dan catatan. Secara default, rekaman adalah baris teks dan bidang bukan spasi. Sebuah awkskrip terdiri dari satu set blok (barang-barang antara {}di tingkat atas). Setiap blok dikaitkan dengan suatu kondisi - dalam posting saya di atas tidak ada karena saya ingin bertindak tanpa syarat pada setiap baris input. Awk beroperasi dengan membaca catatan dari file atau input standar (dalam hal ini STDIN b / c tidak ada nama file yang diberikan), dan mencocokkannya dengan setiap blok secara berurutan, menjalankan blok pada catatan jika kondisinya cocok.
jw013
2

gunakan printf:

printf "\e[%sm%s\e[00m\n" <some_number> <text_in_colour>

misalnya.

printf "\e[%sm%s\e[00m\n" 32 yodle

yang terakhir \nmenambahkan karakter baris baru.

untuk melihat kemungkinan nilai coba sesuatu seperti:

for i in {0..9} {30..38} {90..98} {100..108};
do
    printf "%d:\e[%sm%s\e[00m\n" $i "$i" yodle;
done

selain warna Anda dapat menambahkan pengubah seperti huruf tebal atau garis bawah atau berwarna dengan latar belakang berwarna dengan menggabungkan angka. Untuk membuat teks biru dengan latar belakang abu-abu yang digarisbawahi dan dipukul melalui penggunaan:

printf "\e[%sm%s\e[00m\n" "4;9;34;107" yodle

Bersulang,

/ B2S

Born2Smile
sumber
2

Jika Anda senang menginstal skrip BASH dan ack, hhlighterpaket tersebut memiliki warna default yang berguna dan antarmuka yang mudah https://github.com/paoloantinori/hhighlighter :

sorot contoh

Anda dapat menggunakannya seperti itu untuk menyorot baris yang dimulai dengan FAIL:

h -i 'FAIL.*'

atau yang mengandung FAIL:

h -i '.*FAIL.*'

atau untuk berbagai entri log umum:

h -i '.*FAIL.*' '.*PASS.*' '.*WARN.*'

Dan tentu saja, untuk satu warna (merah) dengan grep polos:

$ printf 'Pass: good job\nFail: bad job\n' | grep -Ei --colour=auto '^|fail.*'

The ^cocok setiap baris, tetapi adalah matcher khusus dan mencetak seluruh baris. Ekspresi yang akan disorot didefinisikan setelah a |. Ekspresi lebih lanjut dapat ditambahkan selama dipisahkan |.

Andy
sumber