Renkleri çıktıdan kaldırma


141

Ben renkler ile çıktı üreten bazı komut dosyası var ve ANSI kodlarını kaldırmak gerekir.

#!/bin/bash

exec > >(tee log)   # redirect the output to a file but keep it on stdout
exec 2>&1

./somescript

Çıktı (günlük dosyasında):

java (pid  12321) is running...@[60G[@[0;32m  OK  @[0;39m]

ESC karakterini buraya nasıl koyacağımı bilmiyordum @, yerine koydum .

Senaryoyu şöyle değiştirdim:

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

Ama şimdi bana veriyor (günlük dosyasında):

java (pid  12321) is running...@[60G[  OK  ]

Bunu nasıl kaldırabilirim @[60G?

Belki de tüm komut dosyası için renklendirmeyi tamamen devre dışı bırakmanın bir yolu var mı?


Düğüm / npm için şunları kullanabilirsiniz strip-ansi: github.com/chalk/strip-ansi .
— Joshua Pinter

Yanıtlar:


166

Vikipedi'ye göre , [m|K]içinde sedkullandığınız komuta özellikle sap için tasarlanmıştır m(renk komutu) ve K( "hattının silme parçası" komutu). Komut dosyanız, satırınız kapsamadığı ^[[60Gtüm OK'leri almak için mutlak imleç konumunu 60 ( ) olarak ayarlamaya çalışıyor sed.

(Düzgün, [m|K]muhtemelen olmalı (m|K)ya da [mK], çünkü bir boru karakteriyle eşleşmeye çalışmıyorsunuz. Ama bu şu anda önemli değil.)

Komutunuzdaki son eşleşmeyi [mGK]veya olarak değiştirirseniz (m|G|K), bu ekstra kontrol sırasını yakalayabilmeniz gerekir.

./somescript | sed -r "s/\x1B\[([0-9]{1,3}(;[0-9]{1,2})?)?[mGK]//g"

29
BSD / OSX kullanıcıları: Genellikle sed için -r seçeneğimiz yoktur. brew install gnu-sedyetenekli bir sürüm yükler. İle çalıştırın gsed.
— Nicolai S

1
Yaparsam echo "$(tput setaf 1)foo$(tput sgr0) bar" | sed -r "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[mGK]//g" | cat -A, anladım: foo^O bar$Sanırım bazı karakterler doğru şekilde kaldırılmadı, değil mi? Nasıl düzeltileceğini biliyor musun?
— edi9999

1
@ edi9999 Anlayabildiğim kadarıyla fark, 16 rengin ( setafdestek olarak) ötesindeki renk ayarlarının sadece ikiden fazla parametre gerektirmesidir; benim normal ifade iki destekler. İlk ?çıkışını değiştirmek *yardımcı olacaktır. Elleçleme sgr0mümkündür, ancak bu kibirli normal ifade tabanlı cevabın kapsamı dışında büyüyecek bir araştırmaya dayanmaktadır.
— Jeff Bowman

Tamam, sed"shift in" karakterini kaldırmak için boruya bir ekleyen bir cevap ekledim
— edi9999

7
Üçüncü bir değer (ala [38;5;45m) olabileceğinden bu güvenilir bir şekilde çalışmaz . Bu alternatif cevap unix.stackexchange.com/a/55547/168277
— davemyron

30

Diğer cevapların hiçbirinden iyi sonuçlar alamadım, ancak aşağıdakiler benim için çalıştı:

somescript | sed -r "s/[[:cntrl:]]\[[0-9]{1,3}m//g"

Yalnızca "^ [" kontrol karakterini kaldırdım, kalan renk verisini, örneğin "33m" bıraktı. Renk kodu ve "m" dahil hile yaptı. Ben s / \ x1B // g ile şaşkın çünkü \ x1B [31m kesinlikle yankı ile çalışır.


6
OSX'te (BSD sed), genişletilmiş normal ifade -Eyerine kullanın -r. Burada
— Assambar

Ben değiştirmek {1,3}zorunda kaldı {,3}(aksi takdirde hala bazı kontroller atlanıyor), çözüm için teşekkürler!
— eylemsiz

6
Noktalı virgüllerle ayrılmış birden çok sayı olabileceğinden (arka plan rengi, kalın, italik vb. İçin). Bu komut benim için çalıştı:sed -r "s/[[:cntrl:]]\[([0-9]{1,3};)*[0-9]{1,3}m//g"
— saeedgnu

Bu (test ettiğim birçoğunun) tamponu ile çalıştırılan Ansible çıktı ile çalıştı.
— Martin

23

IMHO, bu cevapların çoğu kaçış kodunun içindekileri kısıtlamak için çok uğraşıyor. Sonuç olarak, bunlar gibi ortak kodları kaçırırlar [38;5;60m(256 renk modundan ön plan ANSI rengi 60).

Ayrıca GNU uzantılarını-r etkinleştiren seçeneği de gerektirirler . Bunlar gerekli değildir; sadece normal ifadeyi daha iyi okuturlar.

256 renkten kaçışları ele alan ve GNU olmayan sistemlerde çalışan daha basit bir cevap sed:

./somescript | sed 's/\x1B\[[0-9;]\+[A-Za-z]//g'

Bu, ile başlayan [, ondalık sayı ve noktalı virgül içeren her şeyi yakalar ve bir harfle biter. Bu, yaygın ANSI kaçış dizilerinden herhangi birini yakalamalıdır .

Eğlence için, akla gelebilecek tüm ANSI kaçış dizileri için daha büyük ve daha genel (ancak minimal olarak test edilmiş) bir çözüm :

./somescript | sed 's/\x1B[@A-Z\\\]^_]\|\x1B\[[0-9:;<=>?]*[-!"#$%&'"'"'()*+,.\/]*[][\\@A-Z^_`a-z{|}~]//g'

(ve @ edi9999'un SI sorununuz varsa, | sed "s/\x0f//g"sonuna ekleyin ; bu , istenmeyen karakterin onaltılısıyla değiştirerek herhangi bir kontrol karakteri için çalışır 0f)


Bu, Azure az cli önceden hazırlanmış çıktıdan renk çıkarmak için güzel çalıştı.
— volvox

@Elig düzeltildi. Bazı editörlerin tüm tirelerimi garip unicode sürümleri ile değiştirmesiyle başlayarak bir dizi sorunu olduğu ortaya çıktı, aynı zamanda |sed'de, ]sed'de bir karakter sınıfının içinde ve 'tek tırnaklı bir bash dizesinde bir kaç yanlış kaçış . Şimdi benim için çok basit bir test vakası için çalışıyor.
— meustrus

20

Mac OSX veya BSD kullanımı için

./somescript | sed $'s,\x1b\\[[0-9;]*[a-zA-Z],,g'

1
Garip, bu debian için iyi çalıştı ama yukarıdaki diğer değildi.
— cy8g3n

Bu kısmen işe yaradı. Ancak, excel'de bir dosya açarsam, hala bu özel karakteri "?" her satırın sonunda.
— doudy_05

@ doudy_05 Genişletilmiş regexp'yi -Eetkinleştirmek için sed için bayrak geçirmeye çalışın .
— Alexander Zinchenko

14

Bazen SI karakterinin ortaya çıktığı problemim de vardı.

Örneğin, bu girdiyle oldu: echo "$(tput setaf 1)foo$(tput sgr0) bar"

SI karakterini soymanın bir yolu da (kaydırma) (0x0f)

./somescript | sed -r "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[mGK]//g" | sed "s/\x0f//g"

2
Bu cevabın neden bu kadar az kredi aldığından emin değilim. Bu benim için çalışan tek ...
— m8mble

8

Hmm, bunun sizin için işe yarayıp yaramayacağından emin değilim, ancak 'tr' kontrol kodlarını 'silecek' (silecek) - deneyin:

./somescript | tr -d '[:cntrl:]'

32
Aniden yeni satırları da kaldırıyor
— ruX

Evet, LF ve CR (kodlar) kontrol kodlarıdır; Birden fazla satırla ilgileniyorsanız, bu bir çözüm olmayabilir. Bir JAVA programı çalıştırdığınız göründüğünden, renklerin oradan yönetildiğini tahmin edeceğim; Aksi takdirde, konsol kurulumunuza (yani terminal ayarları / renk şeması) ve / veya 'renkleri' destekleyen her komut için seçeneklere bakmanız gerekir, örn. Ls
— --color

3
Bu yanıtı, sadece renkleri kaldırmaktan daha fazlasını yapsa bile, zarafeti için seviyorum. Teşekkürler!
— Johann Philipp Strathausen

7
aslında orada kodlar izin, ls -l + emrinizi bakın: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/
— Kra

7

Benzer bir sorun yaşadım. Bulduğum tüm çözümler renk kodları için iyi çalıştı, ancak "$(tput sgr0)"(özellikleri sıfırlayarak) tarafından eklenen karakterleri kaldırmadı .

Örneğin, davemyron tarafından yapılan açıklamada aşağıdaki örnekte elde edilen dizenin uzunluğunu almak 6 değil 9'dur:

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

Düzgün çalışması için normal ifadenin sgr0(" \E(B") tarafından eklenen sıraya uyacak şekilde genişletilmesi gerekiyordu :

string_sed="$( sed -r "s/\x1B(\[[0-9;]*[JKmsu]|\(B)//g" <<< "${string}" )"

@Jarodiv - en kapsamlı yaklaşım için teşekkürler. Bu konuda sağlanan tüm yanıtlar SADECE ANSI / VT100 Kontrol sekansları (örn: "\ e [31mHello World \ e [0m") ile ilgilidir, ancak TPUT metin formatlamasının (ör: tput smso / tput setaf X) neden olduğu herhangi bir şeyi düzeltmeyin / tput rmso / tput sgr0). Sonuç olarak tüm 'sed' infazlarından sonra kütüklerde başka karışıklıklar kaldı. Bu benim kullanımlarım için saf bir çözüm!
— meçhul

5

Bir metin akışındaki ortak ANSI kodlarını filtrelemek için saf Bash'ta çok daha basit işlev:

# 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
}

Görmek:

  1. linuxjournal.com: Genişletilmiş Globbing
  2. gnu.org: Bash Parametre Genişlemesi

1
Bu işe yaramıyor. İle test edin tldr. (Ben zsh kullanmak rağmen bu yüzden de olabilir.)
— HappyFace

Gerçekten de, Zsh, Bash'in genişletilmiş küresini anlamayacak extglobya da muhtemelen dize değişimini tamamen anlamayacaktır.
— Léa Gris

Genişletilmiş zggb etkinleştirmek mi ... Dize değiştirme de posix olmalı?
— HappyFace

Dize değiştirme POSIX değil. sedBurada Zsh ile çalışacak alternatif yöntemlerden herhangi birini kullanabilirsiniz .
— Léa Gris

Bu çözüm, metnin satır arabelleğe alınması avantajına sahiptir. Sed ile denedim ama benim boru blok tamponlama oldu.
— Guillermo Prandi

3

@ jeff-bowman'ın çözümü, bazı renk kodlarından kurtulmama yardımcı oldu. Biraz daha kaldırmak için normal ifadeye küçük bir parça daha ekledim:

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)

2

İşte saf bir Bash çözümü.

Farklı kaydet strip-escape-codes.sh, çalıştırılabilir yap ve sonra çalıştır <command-producing-colorful-output> | ./strip-escape-codes.sh.

Bunun tüm ANSI çıkış kodlarını / dizilerini kaldırdığını unutmayın . Yalnızca renkleri şerit istiyorsanız, yerini [a-zA-Z]ile "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

Bu çözüm daha da karmaşık olabilir.
— Alexander Zinchenko

1

Tartışmalı fikir, işlemin terminalin renkleri desteklemediğini bilmesini sağlamak için bu işlem ortamı için terminal ayarlarını yeniden yapılandırmak olacaktır.

TERM=xterm-mono ./somescriptAklıma böyle bir şey geliyor. YMMV'ye özel işletim sisteminiz ve komut dosyanızın terminal renk ayarlarını anlama yeteneği ile.


-7

Bu benim için çalışıyor:

./somescript | cat

3
Bu nasıl somescriptuygulandığına bağlıdır . Standart çıktının bir tty olduğunu fark edebilir veya etmeyebilir. (Suçlu kelimeler aslında terminale özgü çıkış kodlarını programa sabitler ve diğer terminallerde veya komut dosyalarında kullanıldığında korkunç bir şekilde kırılır).
— Toby Speight

Teşekkürler Toby. Test etmek için django's manage.py kullandım, ancak söyledikleriniz mantıklı.
— spiderlama
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.