出力から色を削除する


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ですか?

スクリプト全体の色付けを完全に無効にする方法があるのでしょうか。


ノード/ NPMの場合は、使用することができますstrip-ansigithub.com/chalk/strip-ansiを
ジョシュアピンター

回答:


164

Wikipediaよると、使用し[m|K]ているsedコマンドのはm(colorコマンド)およびK(「erase part of line」コマンド)を処理するように特別に設計されています。スクリプトは、絶対カーソル位置を60(^[[60G)に設定して、sed行がカバーしない行内のすべてのOKを取得しようとしています。

(正しくは、パイプ文字と一致させようとしないため、[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サポートとして)には、2つだけではなく、より多くのパラメーターが必要になるという違いがあります。私の正規表現は2つをサポートしています。の最初の?アウトを変更すると*役立つはずです。処理sgr0は可能ですが、検索に基づいて、このハックな正規表現ベースの回答の範囲外になる可能性があります。
ジェフボウマン

sed
さて

7
3番目の値(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は確かにエコーで動作するので、s / \ x1B // gは動作しません。


6
OSX(BSD sed)では、拡張正規表現の-E代わりに使用します-r。その他の情報はここにあります
アッサンバー

私は(そうでなければそれでもいくつかのコントロールをスキップ{1,3}していた)に置き換える必要{,3}がありました、あなたの解決策に感謝します!
アクションレス

6
セミコロンで区切られた複数の数字になる可能性があるため(背景色、太字、斜体などの場合)。このコマンドは私にとってはsed -r "s/[[:cntrl:]]\[([0-9]{1,3};)*[0-9]{1,3}m//g"
うまくいき

これは(私がテストしたものの多く)、unbufferで実行されたAnsible出力で動作しました。
マーティン、

23

私見、これらの回答のほとんどは、エスケープコードの内容を制限しようとしています。その結果、それらは[38;5;60m(256色モードからのフォアグラウンドANSIカラー60)などの一般的なコードが欠落することになります。

また-rGNU拡張機能を有効にするオプションも必要です。これらは必須ではありません。彼らはただ正規表現を読みやすくします。

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"、最後に追加してください。これは、任意の制御文字0fに対して、不要な文字の16進数で置き換えることで機能します


これは、Azure az cliプリティファイド出力から文字列の色にうまく機能しました。
volvox

@eligを修正しました。いくつかのエディターが私のすべてのダッシュを奇妙なユニコードバージョンで置き換えることから始まり|、sed ]内、sed 内の文字クラス内、および'単一引用符で囲まれたbash文字列内の不適切なエスケープの束から、いくつかの問題が判明しました。現在、非常に基本的なテストケースで機能しています。
meustrus

20

Mac OSXまたはBSDの場合

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

1
奇妙なことに、これはdebianには問題なく機能しましたが、上記のものは機能しませんでした。
cy8g3n

これは部分的に機能しました。ただし、ファイルをExcelで開いた場合、この特殊文字「?」が引き続き表示されます。各行の終わりに。
doudy_05

@ doudy_05 -Esedのフラグを渡して、拡張正規表現を有効にしてください。
アレクサンダージンチェンコ

14

また、時々SIキャラクターが登場するという問題もありました。

これは、たとえば次の入力で発生しました。 echo "$(tput setaf 1)foo$(tput sgr0) bar"

SI文字(シフトイン)(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 2014年

はい、LFとCR(コード)は制御コードです。あなたが複数の行に興味があるなら、これは解決策ではないかもしれません。JAVAプログラムを実行しているようですので、色はそこから管理されていると思います。そうでない場合は、コンソールの設定(つまり、端末の設定/配色)や、「色」をサポートする各コマンドのオプション、つまりls --color = never
Dale_Reagan

3
単に色を取り除くだけではないにしても、その優雅さからこの答えが好きです。ありがとう!
Johann Philipp Strathausen 2017

7
実際にはコードがそこにあります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/
To Kra

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

テキストストリームから一般的なANSIコードを除外するための純粋なBashのはるかに単純な関数:

# 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:Bashパラメーターの拡張

1
これは機能しません。でテストしtldrます。(私はzshを使用しているため、それが原因である可能性もあります。)
HappyFace

実際、ZshはBashの拡張グロビングをextglob理解しないか、おそらく文字列の置換を完全に理解しません。
Léaのグリ

zshのextendedglobを有効にしました...文字列の置換もposixである必要がありますか?
HappyFace

文字列の置換はPOSIXではありません。sedZshで動作する、ここで説明した方法を使用できます。
Léaのグリ

このソリューションには、テキストをラインバッファリングするという利点があります。私はsedで試しましたが、それは私のパイプをブロックバッファリングしていました。
ギジェルモプランディ

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

さて、このソリューションはさらに複雑ではないかもしれません。
アレクサンダージンチェンコ

1

物議を醸すアイデアは、このプロセス環境の端末設定を再構成して、端末が色をサポートしていないことをプロセスに通知することです。

のようなものTERM=xterm-mono ./somescriptが私の頭に浮かびます。特定のOSを備えたYMMVと、ターミナルの色設定を理解するスクリプトの機能。


-7

これは私にとってはうまくいきます:

./somescript | cat

3
somescript実装方法によって異なります。標準出力がttyであることを認識する場合と認識しない場合があります。(攻撃者という言葉は、実際には端末固有のエスケープコードをプログラムにハードコードし、他の端末やスクリプトで使用すると恐ろしく壊れます)。
Toby Speight 2017

トビーに感謝します。テストにはdjangoのmanage.pyを使用しましたが、あなたが言ったことは意味があります。
スパイダーラマ2017
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.