web-dev-qa-db-ja.com

出力から色を削除する

色付きの出力を生成するスクリプトがあり、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も削除するにはどうすればよいですか?

スクリプト全体の色付けを完全に無効にする方法はありますか?

111
Pawel P.

ウィキペディアによる 、使用しているsedコマンドの[m|K]は、m(カラーコマンド)およびKを処理するように特別に設計されています(「行の一部を消去」コマンド)。スクリプトは、カーソルの絶対位置を60(^[[60G)に設定して、sed行ではカバーされない行のすべてのOKを取得しようとしています。

(適切に、[m|K]はおそらく(m|K)または[mK]である必要があります。パイプ文字に一致させようとしているわけではありません。しかし、今はそれは重要ではありません。)

コマンドの最後の一致を[mGK]または(m|G|K)に切り替えると、追加の制御シーケンスをキャッチできるはずです。

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

私は他のどの答えからもまともな結果を得ることができませんでしたが、次のことがうまくいきました:

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

制御文字「^ [」のみを削除すると、残りの色データ(「33m」など)が残ります。カラーコードと「m」を含めると、うまくいきました。\x1B [31mは確かにエコーで動作するため、s/\ x1B // gが動作しないことに戸惑っています。

23
JoeAndrieu

Mac OSXまたはBSD用

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

時々、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"
11
edi9999

うーん、これがうまくいくかどうかはわかりませんが、 'tr'は 'strip'(削除)制御コード-試してください:

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

私見、これらの答えのほとんどは、エスケープコード内にあるものを制限するために一生懸命に努力します。その結果、[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"を最後に追加します。これは、 任意の制御文字 で、0fを望ましくない文字の16進数に置き換えることで機能します)

9
meustrus

同様の問題がありました。私が見つけた解決策はすべて、カラーコードに対してはうまく機能しましたが、"$(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}" )"
7
Jarodiv

テキストストリームから一般的な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パラメーター展開
3
Léa Gris

@ 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)
3
zstolar

これを行う必要がある場合within Bashスクリプト、次の関数を使用できます。

# Strip escape codes/sequences [$1: input, $2: target variable]
function strip_escape_codes() {
    local input="${1//\"/\\\"}" output="" i char within_code=0
    for ((i=0; i < ${#input}; ++i)); do
        char="${input:i:1}"                     # get current character
        if (( ${within_code} == 1 )); then      # if we're currently within an escape code, check if end of
            case "${char}" in                   # code is reached, i.e. if current character is a letter
                [a-zA-Z]) within_code=0 ;;      # we're no longer within an escape code
            esac
            continue
        fi
        if [[ "${char}" == $'\e' ]]; then       # if current character is '\e', we've reached an escape code
            within_code=1                       # now we're within an escape code
            continue
        fi
        output+="${char}"                       # if none of the above applies, add current character to output
    done
    eval "$2=\"${output}\""                     # assign output to target variable
}

元の質問のユースケースに一致する例を次に示します。 example.shとして保存し、<command-producing-colored-output> | example.shを実行します。

#!/bin/bash

# copy&paste function strip_escape_codes here

while read -r line; do
    strip_escape_codes "${line}" stripped
    echo "${stripped}"
done
1
Maxxim