출력에서 색상 제거


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.