출력에서 색상 제거


140

색상으로 출력을 생성하는 스크립트가 있으며 ANSI 코드를 제거해야합니다.

#!/bin/bash

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

./somescript

출력은 (로그 파일)입니다 :

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

나는 ESC 캐릭터를 여기에 넣는 방법을 몰랐다 @.

스크립트를 다음과 같이 변경했습니다.

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

그러나 이제 나에게 (로그 파일로) 제공합니다.

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

이걸 어떻게 제거 할 수 @[60G있습니까?

전체 스크립트의 색상을 완전히 비활성화하는 방법이 있습니까?


노드 / 고궁 박물원를 들어, 당신은 사용할 수 있습니다 strip-ansi: github.com/chalk/strip-ansi를 .
Joshua Pinter

답변:


165

위키 백과에 따르면[m|K]에서 sed사용중인 명령은 특별히 처리 할 수 있도록 설계되어있다 m(색상 명령)과 K(이하 "라인의 삭제 부분"명령). 스크립트가 절대 커서 위치를 60 ( ^[[60G) 으로 설정 하여 한 줄의 모든 OK를 얻지 sed못합니다.

( 파이프 문자와 일치하지 않기 때문에 [m|K]아마도 (m|K)또는 [mK]일 것입니다 . 그러나 지금은 중요하지 않습니다.)

명령에서 해당 최종 일치를 [mGK]또는 (m|G|K)로 전환하면 해당 추가 제어 시퀀스를 잡을 수 있습니다.

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

29
BSD / OSX 사용자 : 일반적으로 sed에 -r 옵션이 없습니다. brew install gnu-sed가능한 버전을 설치합니다. 로 실행하십시오 gsed.
Nicolai S

1
내가하면 echo "$(tput setaf 1)foo$(tput sgr0) bar" | sed -r "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[mGK]//g" | cat -A, 나는 얻는다 : foo^O bar$그래서 일부 문자가 올바르게 제거되지 않은 것 같아요. 수정하는 방법을 알고 있습니까?
edi9999

1
@ edi9999 내가 알 수있는 한, 16 가지 이상의 색 설정 ( setaf지원으로)은 두 개 이상의 매개 변수가 필요 하다는 차이점이 있습니다 . 내 정규식은 두 가지를 지원합니다. 첫 번째 변경 ?에 대한 아웃 *SHOULD 도움말을. 처리 sgr0는 가능하지만 검색을 기반으로이 해키 정규 표현식 기반의 범위를 벗어나는 가능성이 높습니다.
Jeff Bowman

좋아, sed"shift in"문자를 제거하기 위해 파이프에 a 를 추가하는 답을 추가했다
edi9999

7
세 번째 값 (ala [38;5;45m) 이있을 수 있으므로 안정적으로 작동하지 않습니다 . 이 대안 답변은 작동합니다. unix.stackexchange.com/a/55547/168277
davemyron

30

다른 답변에서 괜찮은 결과를 얻을 수 없었지만 다음이 저에게 효과적이었습니다.

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

제어 문자 "^ ["만 제거하면 나머지 색상 데이터 (예 : "33m")가 남았습니다. 색상 코드와 "m"을 포함하여 트릭을 수행했습니다. \ x1B [31m은 확실히 echo와 함께 작동하기 때문에 s / \ x1B // g가 작동하지 않습니다.


6
OSX (BSD sed)에서는 확장 정규식 -E대신에 사용하십시오 -r. 더 많은 것을 여기서
Assambar

난 대체했다 {1,3}{,3}, (그렇지 않으면 여전히 컨트롤을 생략했다) 솔루션에 대한 감사합니다!
actionless

6
그것들은 세미콜론으로 분리 된 여러 숫자 일 수 있기 때문에 (배경색, 굵은 체, 이탤릭체 등). 이 명령은 나를 위해 일했다 :sed -r "s/[[:cntrl:]]\[([0-9]{1,3};)*[0-9]{1,3}m//g"
saeedgnu

이 (내가 테스트 한 많은 것 중)은 unbuffer로 실행 된 Ansible 출력으로 작동했습니다.
마틴

23

IMHO, 이러한 답변의 대부분은 이스케이프 코드 내부의 내용을 제한하기 위해 너무 열심히 노력합니다. 결과적으로 [38;5;60m(256 색상 모드의 전경 ANSI 색상 60) 과 같은 공통 코드가 누락 됩니다.

또한 GNU 확장-r 을 가능하게 하는 옵션이 필요합니다 . 이것들은 필요하지 않습니다. 그들은 정규식을 더 잘 읽습니다.

다음은 256 색 이스케이프를 처리하고 GNU가 아닌 시스템에서 작동하는 간단한 답변입니다 sed.

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

이것은로 시작하고 [, 소수와 세미콜론을 포함하며, 문자로 끝나는 모든 것을 잡을 것입니다 . 이것은 일반적인 ANSI 이스케이프 시퀀스 중 하나를 잡아야합니다 .

재미를 위해, 모든 가능한 ANSI 이스케이프 시퀀스에 대한 더 크고 일반적인 (그러나 최소한의 테스트) 솔루션이 있습니다 .

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

(그리고 @ edi9999의 SI 문제 | sed "s/\x0f//g"가있는 경우 끝에 추가 하십시오. 원치 않는 문자의 16 진수 로 바꾸면 모든 제어 문자에서 작동합니다 0f)


이 것은 Azure az cli prettified 출력에서 ​​색상을 문자열로 처리하는 데 효과적이었습니다.
volvox

@elig를 수정했습니다. 모든 대시를 이상한 유니 코드 버전으로 바꾸는 편집기에서 시작하여 여러 가지 문제가 있었지만 |sed, sed ]의 문자 클래스 및 '작은 따옴표로 묶인 bash 문자열 로 부적절한 이스케이프가 발생했습니다 . 그것은 매우 기본적인 테스트 사례를 위해 나를 위해 일하고 있습니다.
meustrus

20

Mac OSX 또는 BSD 사용

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

1
이상하게도, 이것은 데비안에서는 잘 작동했지만 다른 것들은 그렇지 않았습니다.
cy8g3n

이것은 부분적으로 효과가있었습니다. 그러나 Excel에서 파일을 열면 여전히이 특수 문자 "?"가 나타납니다. 각 줄의 끝에.
doudy_05

@ doudy_05 -E확장 정규 표현식을 활성화하려면 sed에 플래그 를 전달하십시오 .
Alexander Zinchenko

14

또한 때때로 SI 캐릭터가 등장한다는 문제가있었습니다.

예를 들어이 입력으로 발생했습니다. echo "$(tput setaf 1)foo$(tput sgr0) bar"

다음은 SI 문자를 제거하는 방법입니다 (shift in) (0x0f).

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

2
이 답변이 왜 그렇게 적은 크레딧을 받는지 잘 모르겠습니다. 이것은 나를 위해 일하는 유일한 사람입니다.
m8mble

8

흠, 이것이 당신에게 효과가 있는지 확실하지 않지만 'tr'은 제어 코드를 '제거'(삭제) 합니다.

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

32
갑자기 그것은 또한 새로운 라인을 제거합니다
ruX

예, LF 및 CR (코드)은 제어 코드입니다. 하나 이상의 라인에 관심이 있다면 이것은 해결책이 아닐 수 있습니다. JAVA 프로그램을 실행중인 것으로 보이므로 색상이 여기에서 관리되는 것 같습니다. 그렇지 않으면 당신은 당신의 콘솔 설정 (즉, 터미널 설정 / 색상) 및 / 또는 각 명령에 대한 옵션에서 볼 필요가있을 것이다 그 지원 '색상', 즉 LS --color = 결코
Dale_Reagan

3
나는 단순히 색상을 제거하는 것 이상으로 우아함을 좋아합니다. 감사!
Johann Philipp Strathausen

7
실제로, 볼이 코드를 보자 LS -l + 명령 :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/
로 크라

7

나는 비슷한 문제가 있었다. 내가 찾은 모든 솔루션은 색상 코드에서 잘 작동했지만 추가 된 문자는 제거하지 않았습니다 "$(tput sgr0)"(속성 재설정).

예를 들어, davemyron주석 에서 해결책 을 취 하면 아래 예제의 결과 문자열 길이는 6이 아니라 9입니다.

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

제대로 작동하려면 정규식을 sgr0( " \E(B")로 추가 된 순서와 일치하도록 확장해야합니다 .

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

@Jarodiv-가장 포괄적 인 접근 방식에 감사드립니다. 이 주제에 제공된 모든 답변은 ANSI / VT100 제어 시퀀스 (예 : "\ e [31mHello World \ e [0m") 만 처리하지만 TPUT 텍스트 형식에 의해 야기 된 어떠한 것도 수정하지 않습니다 (예 : tput smso / tput setaf X / tput rmso / tput sgr0). 결과적으로 모든 'sed'실행 후 로그에 다른 엉망이 남아있었습니다. 이것은 내 유스 케이스에 대한 순수한 솔루션입니다!
익명의

5

순수 Bash에서 텍스트 스트림에서 일반적인 ANSI 코드를 필터링하는 훨씬 간단한 기능 :

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

보다:

  1. linuxjournal.com : 확장 글 로빙
  2. gnu.org : 배시 파라미터 확장

1
작동하지 않습니다. 로 테스트하십시오 tldr. (저는 zsh를 사용하기 때문에
그로 인한

실제로 Zsh는 Bash의 확장 된 글로브를 이해하지 못 extglob하거나 아마도 문자열 대체를 전혀 이해하지 못할 것입니다.
Léa Gris

zsh의 확장 글로브를 활성화했습니다 ... 문자열 교체도 posix 여야합니까?
HappyFace

문자열 교체는 POSIX가 아닙니다. sedZsh와 함께 작동하는 여기에 언급 된 다른 방법을 사용할 수 있습니다 .
레아 Gris

이 솔루션은 텍스트를 라인 버퍼링하는 장점이 있습니다. 나는 sed로 시도했지만 파이프를 차단하는 것이 었습니다.
Guillermo Prandi

3

@ jeff-bowman의 솔루션은 일부 색상 코드를 제거하는 데 도움이되었습니다. 좀 더 제거하기 위해 정규식에 또 다른 작은 부분을 추가했습니다.

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

여기 순수한 Bash 솔루션이 있습니다.

다른 이름으로 저장 strip-escape-codes.sh하고 실행 가능하게 한 다음 실행하십시오 <command-producing-colorful-output> | ./strip-escape-codes.sh.

이것은 모든 ANSI 이스케이프 코드 / 시퀀스를 제거합니다. 만 색상을 제거하려는 경우, 교체 [a-zA-Z]와 함께 "m".

배쉬> = 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

배쉬 <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

이 솔루션은 훨씬 덜 복잡 할 수 있습니다.
Alexander Zinchenko

1

논란의 여지가있는 아이디어는 프로세스가 터미널이 색상을 지원하지 않음을 프로세스에 알리도록이 프로세스 환경에 대한 터미널 설정을 재구성하는 것입니다.

TERM=xterm-mono ./somescript내 마음에 뭔가가 온다. 터미널 색상 설정을 이해하는 특정 OS 및 스크립트 기능을 갖춘 YMMV


-7

이것은 나를 위해 작동합니다 :

./somescript | cat

3
somescript구현 방법에 따라 다릅니다 . 표준 출력이 tty임을 인식하거나 인식하지 못할 수 있습니다. (범죄자들은 ​​실제로 터미널 특정 이스케이프 코드를 프로그램에 하드 코딩하고 다른 터미널이나 스크립트에서 사용될 때 끔찍하게 침입합니다).
Toby Speight

고마워 토비. django의 manage.py를 사용하여 테스트했지만 말한 내용은 의미가 있습니다.
spiderlama
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.