Saya memiliki beberapa skrip yang menghasilkan keluaran dengan warna dan saya perlu menghapus kode ANSI.
#!/bin/bash
exec > >(tee log) # redirect the output to a file but keep it on stdout
exec 2>&1
./somescript
Outputnya adalah (dalam file log):
java (pid 12321) is running...@[60G[@[0;32m OK @[0;39m]
Saya tidak tahu bagaimana meletakkan karakter ESC di sini, jadi saya menempatkannya @
.
Saya mengubah skrip menjadi:
#!/bin/bash
exec > >(tee log) # redirect the output to a file but keep it on stdout
exec 2>&1
./somescript | sed -r "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]//g"
Tapi sekarang memberi saya (dalam file log):
java (pid 12321) is running...@[60G[ OK ]
Bagaimana saya juga bisa menghapus ini ' @[60G
?
Mungkin ada cara untuk sepenuhnya menonaktifkan pewarnaan untuk seluruh skrip?
strip-ansi
: github.com/chalk/strip-ansi .Jawaban:
Menurut Wikipedia , yang
[m|K]
dalamsed
perintah yang Anda gunakan secara khusus dirancang untuk menanganim
(perintah warna) danK
(yang "menghapus bagian dari baris" perintah). Skrip Anda mencoba menyetel posisi kursor absolut ke 60 (^[[60G
) untuk mendapatkan semua OK dalam satu baris, yangsed
tidak dicakup baris Anda .(Sebenarnya,
[m|K]
mungkin harus(m|K)
atau[mK]
, karena Anda tidak mencoba mencocokkan karakter pipa. Tapi itu tidak penting sekarang.)Jika Anda mengalihkan pertandingan terakhir itu dalam perintah Anda ke
[mGK]
atau(m|G|K)
, Anda harus bisa menangkap urutan kontrol ekstra itu../somescript | sed -r "s/\x1B\[([0-9]{1,3}(;[0-9]{1,2})?)?[mGK]//g"
sumber
brew install gnu-sed
akan menginstal versi yang mampu. Jalankan dengangsed
.echo "$(tput setaf 1)foo$(tput sgr0) bar" | sed -r "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[mGK]//g" | cat -A
, saya mendapatkan:foo^O bar$
Jadi saya kira beberapa karakter tidak dihapus dengan benar, bukan? Apakah Anda tahu cara mengoreksi?setaf
pendukung) memerlukan lebih banyak parameter daripada hanya dua; regex saya mendukung dua. Mengganti yang pertama?
untuk*
seharusnya membantu. Penanganansgr0
dimungkinkan tetapi berdasarkan pencarian, kemungkinan itu tumbuh di luar cakupan jawaban berbasis regex yang hacky ini.sed
ke pipa untuk menghapus karakter "shift in"[38;5;45m
). Jawaban alternatif ini berfungsi unix.stackexchange.com/a/55547/168277Saya tidak bisa mendapatkan hasil yang layak dari jawaban lain, tetapi yang berikut berhasil untuk saya:
somescript | sed -r "s/[[:cntrl:]]\[[0-9]{1,3}m//g"
Jika saya hanya menghapus kontrol char "^ [", itu meninggalkan sisa data warna, misalnya "33m". Memasukkan kode warna dan "m" berhasil. Saya bingung dengan s / \ x1B // g tidak berfungsi karena \ x1B [31m pasti berfungsi dengan echo.
sumber
-E
sebagai pengganti-r
regex yang diperpanjang. Lebih lanjut bisa ditemukan di sini{1,3}
ke{,3}
(jika tidak, masih melewatkan beberapa kontrol), terima kasih atas solusi Anda!sed -r "s/[[:cntrl:]]\[([0-9]{1,3};)*[0-9]{1,3}m//g"
IMHO, sebagian besar jawaban ini berusaha terlalu keras untuk membatasi apa yang ada di dalam kode pelarian. Akibatnya, mereka kehilangan kode umum seperti
[38;5;60m
(ANSI warna latar depan 60 dari mode 256 warna).Mereka juga membutuhkan
-r
opsi yang mengaktifkan ekstensi GNU . Ini tidak diperlukan; mereka hanya membuat ekspresi reguler menjadi lebih baik.Berikut adalah jawaban sederhana yang menangani pelarian 256 warna dan berfungsi pada sistem dengan non-GNU
sed
:./somescript | sed 's/\x1B\[[0-9;]\{1,\}[A-Za-z]//g'
Ini akan menangkap apa pun yang dimulai dengan
[
, memiliki sejumlah desimal dan titik koma, dan diakhiri dengan huruf. Ini harus menangkap salah satu urutan escape ANSI yang umum .Untuk funsies, berikut adalah solusi yang lebih besar dan lebih umum (tapi minimal teruji) untuk semua escape sequence ANSI :
./somescript | sed 's/\x1B[@A-Z\\\]^_]\|\x1B\[[0-9:;<=>?]*[-!"#$%&'"'"'()*+,.\/]*[][\\@A-Z^_`a-z{|}~]//g'
(dan jika Anda memiliki masalah SI @ edi9999, tambahkan
| sed "s/\x0f//g"
ke bagian akhir; ini berfungsi untuk semua karakter kontrol dengan mengganti0f
dengan hex dari karakter yang tidak diinginkan)sumber
|
di sed,]
di dalam kelas karakter di sed, dan'
dalam string bash yang dikutip tunggal. Sekarang ini berfungsi untuk saya untuk kasus uji yang sangat dasar.\+
akan membuat tanda plus menjadi literal, tetapi saya pikir itu berarti menjadi pengubah "setidaknya satu" dari rentang sebelumnya.sed
tanpa-r
opsi,+
diperlakukan sebagai literal dan\+
diperlakukan sebagai pengubah, yang bertentangan dengan sebagian besar penggunaan modern.Untuk penggunaan Mac OSX atau BSD
./somescript | sed $'s,\x1b\\[[0-9;]*[a-zA-Z],,g'
sumber
-E
bendera sed untuk mengaktifkan regexp diperpanjang.Saya juga sempat bermasalah, kadang karakter SI muncul.
Itu terjadi misalnya dengan masukan ini:
echo "$(tput setaf 1)foo$(tput sgr0) bar"
Berikut cara untuk juga menghapus karakter SI (shift in) (0x0f)
./somescript | sed -r "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[mGK]//g" | sed "s/\x0f//g"
sumber
Hmm, tidak yakin apakah ini akan berhasil untuk Anda, tetapi 'tr' akan 'strip' (hapus) kode kontrol - coba:
./somescript | tr -d '[:cntrl:]'
sumber
rwxr-xr-x 1 tokra admin 22 Oct 18 14:21 [0m[01;36m/usr/local/opt/gradle[0m -> [01;34m../Cellar/gradle/4.2.1[0m/
Saya punya masalah serupa. Semua solusi yang saya temukan berfungsi dengan baik untuk kode warna tetapi tidak menghapus karakter yang ditambahkan oleh
"$(tput sgr0)"
(mengatur ulang atribut).Mengambil, misalnya, solusi dalam komentar oleh davemyron , panjang string yang dihasilkan pada contoh di bawah ini adalah 9, bukan 6:
#!/usr/bin/env bash string="$(tput setaf 9)foobar$(tput sgr0)" string_sed="$( sed -r "s/\x1B\[[0-9;]*[JKmsu]//g" <<< "${string}" )" echo ${#string_sed}
Agar berfungsi dengan baik, regex harus diperluas agar juga cocok dengan urutan yang ditambahkan oleh
sgr0
("\E(B
"):string_sed="$( sed -r "s/\x1B(\[[0-9;]*[JKmsu]|\(B)//g" <<< "${string}" )"
sumber
Fungsi yang jauh lebih sederhana dalam Bash murni untuk memfilter kode ANSI umum dari aliran teks:
# Strips common ANSI codes from a text stream shopt -s extglob # Enable Bash Extended Globbing expressions ansi_filter() { local line local IFS= while read -r line || [[ "$line" ]]; do echo "${line//$'\e'[\[(]*([0-9;])[@-n]/}" done }
Lihat:
sumber
tldr
. (Meskipun saya menggunakan zsh jadi mungkin juga karena itu.)extglob
tidak akan memahami perluasan globing Bash atau mungkin juga tidak akan memahami penggantian string sama sekali.sed
disebutkan di sini yang akan bekerja dengan Zsh.Solusi @ jeff-bowman membantu saya menyingkirkan BEBERAPA kode warna. Saya menambahkan sebagian kecil lagi ke regex untuk menghapus lagi:
sed -r "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[mGK]//g" # Original. Removed Red ([31;40m[1m[error][0m) sed -r "s/\x1B\[([0-9];)?([0-9]{1,2}(;[0-9]{1,2})?)?[mGK]//g" # With an addition, removed yellow and green ([1;33;40m[1m[warning][0m and [1;32;40m[1m[ok][0m) ^^^^^^^^^ remove Yellow and Green (and maybe more colors)
sumber
Inilah solusi Bash murni.
Simpan sebagai
strip-escape-codes.sh
, buat dapat dieksekusi, lalu jalankan<command-producing-colorful-output> | ./strip-escape-codes.sh
.Perhatikan bahwa ini menghapus semua kode / urutan escape ANSI. Jika Anda hanya ingin menghapus warna, ganti
[a-zA-Z]
dengan"m"
.Bash> = 4,0:
#!/usr/bin/env bash # Strip ANSI escape codes/sequences [$1: input string, $2: target variable] function strip_escape_codes() { local _input="$1" _i _char _escape=0 local -n _output="$2"; _output="" for (( _i=0; _i < ${#_input}; _i++ )); do _char="${_input:_i:1}" if (( ${_escape} == 1 )); then if [[ "${_char}" == [a-zA-Z] ]]; then _escape=0 fi continue fi if [[ "${_char}" == $'\e' ]]; then _escape=1 continue fi _output+="${_char}" done } while read -r line; do strip_escape_codes "${line}" line_stripped echo "${line_stripped}" done
Bash <4.0:
#!/usr/bin/env bash # Strip ANSI escape codes/sequences [$1: input string, $2: target variable] function strip_escape_codes() { local input="${1//\"/\\\"}" output="" i char escape=0 for (( i=0; i < ${#input}; ++i )); do # process all characters of input string char="${input:i:1}" # get current character from input string if (( ${escape} == 1 )); then # if we're currently within an escape sequence, check if if [[ "${char}" == [a-zA-Z] ]]; then # end is reached, i.e. if current character is a letter escape=0 # end reached, we're no longer within an escape sequence fi continue # skip current character, i.e. do not add to ouput fi if [[ "${char}" == $'\e' ]]; then # if current character is '\e', we've reached the start escape=1 # of an escape sequence -> set flag continue # skip current character, i.e. do not add to ouput fi output+="${char}" # add current character to output done eval "$2=\"${output}\"" # assign output to target variable } while read -r line; do strip_escape_codes "${line}" line_stripped echo "${line_stripped}" done
sumber
Ide kontroversialnya adalah mengkonfigurasi ulang pengaturan terminal untuk lingkungan proses ini agar proses mengetahui bahwa terminal tidak mendukung warna.
Sesuatu seperti
TERM=xterm-mono ./somescript
muncul di benak saya. YMMV dengan OS spesifik Anda dan kemampuan skrip Anda untuk memahami pengaturan warna terminal.sumber
Saya menemukan pertanyaan / jawaban ini mencoba melakukan sesuatu yang mirip dengan OP. Saya menemukan beberapa sumber berguna lainnya dan menghasilkan skrip log berdasarkan itu. Posting di sini seandainya dapat membantu orang lain.
Menggali tautan membantu memahami beberapa pengalihan yang tidak akan saya coba dan jelaskan karena saya sendiri baru mulai memahaminya.
Penggunaan akan membuat keluaran berwarna ke konsol, sambil menghapus kode warna dari teks menuju ke file log. Ini juga akan menyertakan stderr di logfile untuk setiap perintah yang tidak berfungsi.
Edit: menambahkan lebih banyak penggunaan di bagian bawah untuk menunjukkan cara masuk dengan berbagai cara
#!/bin/bash set -e DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" . $DIR/dev.conf . $DIR/colors.cfg filename=$(basename ${BASH_SOURCE[0]}) # remove extension # filename=`echo $filename | grep -oP '.*?(?=\.)'` filename=`echo $filename | awk -F\. '{print $1}'` log=$DIR/logs/$filename-$target if [ -f $log ]; then cp $log "$log.bak" fi exec 3>&1 4>&2 trap 'exec 2>&4 1>&3' 0 1 2 3 exec 1>$log 2>&1 # log message log(){ local m="$@" echo -e "*** ${m} ***" >&3 echo "=================================================================================" >&3 local r="$@" echo "=================================================================================" echo -e "*** $r ***" | sed -r "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[mGK]//g" echo "=================================================================================" } echo "=================================================================================" >&3 log "${Cyan}The ${Yellow}${COMPOSE_PROJECT_NAME} ${filename} ${Cyan}script has been executed${NC}" log $(ls) #log $(<command>) log "${Green}Apply tag to image $source with version $version${NC}" # log $(exec docker tag $source $target 3>&2) #prints error only to console # log $(docker tag $source $target 2>&1) #prints error to both but doesn't exit on fail log $(docker tag $source $target 2>&1) && exit $? #prints error to both AND exits on fail # docker tag $source $target 2>&1 | tee $log # prints gibberish to log echo $? # prints 0 because log function was successful log "${Purple}Push $target to acr${NC}"
Berikut tautan lain yang membantu:
sumber
Ada juga alat khusus untuk menangani urutan pelolosan ANSI: ansifilter . Gunakan
--text
format keluaran default untuk menghapus semua urutan escape ANSI (catatan: tidak hanya mewarnai).ref: https://stackoverflow.com/a/6534712
sumber
Tidak yakin apa yang ada di
./somescript
dalamnya tetapi jika urutan pelolosan tidak di-hardcode, Anda dapat menyetel jenis terminal untuk menghindarinyaMisalnya, jika Anda mencoba
Anda akan melihatnya tidak menghasilkan keluaran sementara
tidak (untuk xterm-256color).
sumber
Ini bekerja untuk saya:
sumber
somescript
implementasinya. Mungkin atau mungkin tidak mengenali bahwa keluaran standarnya adalah tty. (Kata-kata pelanggar sebenarnya adalah kode pelarian khusus terminal kode keras ke dalam program, dan rusak secara mengerikan ketika digunakan pada terminal lain atau dalam skrip).