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.