スクリプト出力から制御文字(コンソールコード/色を含む)を削除する


68

「スクリプト」コマンドを使用して、コマンドラインで対話型セッションを記録できます。ただし、これにはすべての制御文字カラーコードが含まれます。「col -b」で制御文字(バックスペースなど)を削除できますが、カラーコードを削除する簡単な方法が見つかりません。

コマンドラインは通常の方法で使用するため、そこで色を無効にしないでください。スクリプト出力から色を削除するだけです。また、私は遊んで、物事を修正するための正規表現を見つけることができることを知っていますが、よりシンプルな(そしてより信頼性の高い-正規表現を開発するときにわからないコードがある場合はどうすればよいですか?)

問題を表示するには:

spl62 tmp:スクリプト
スクリプトが開始されました、ファイルはtypescriptです
spl62 lepl:ls
add-licence.sed build-example.sh commit-test push-docs.sh
add-licence.sh build.sh delete-licence.sed setup.py
asn build-test.sh delete-licence.sh src
build-doc.sh clean doc-src test.ini
spl62 lepl:終了
スクリプトが完了しました、ファイルはtypescriptです
spl62 tmp:cat -v typescript
スクリプトは木曜日に開始2011年6月9日09:47:27 AM CLT
spl62 lepl:ls ^ M
^ [[0m ^ [[00madd-licence.sed ^ [[0m ^ [[00; 32mbuild-example.sh ^ [[0m ^ [[00mcommit-test ^ [[0m ^ [[00; 32mpush-docs.sh ^ [[0m ^ M
^ [[00; 32madd-licence.sh ^ [[0m ^ [[00; 32mbuild.sh ^ [[0m ^ [[00mdelete-licence.sed ^ [[0m ^ [[00msetup.py ^ [[0m ^ M
^ [[01; 34masn ^ [[0m ^ [[00; 32mbuild-test.sh ^ [[0m ^ [[00; 32mdelete-licence.sh ^ [[0m ^ [[01; 34msrc ^ [[0m ^ M
^ [[00; 32mbuild-doc.sh ^ [[0m ^ [[00; 32mclean ^ [[0m ^ [[01; 34mdoc-src ^ [[0m ^ [[00mtest.ini ^ [[0m ^ M
spl62 lepl:exit ^ M

2011年6月9日木曜日09:47:29 AM CLTにスクリプトが実行されました
spl62 tmp:col -b <タイプスクリプト 
スクリプトは木曜日に開始2011年6月9日09:47:27 AM CLT
spl62 lepl:ls
0m00madd-licence.sed0m 00; 32mbuild-example.sh0m 00mcommit-test0m 00; 32mpush-docs.sh0m
00; 32madd-licence.sh0m 00; 32mbuild.sh0m 00mdelete-licence.sed0m 00msetup.py0m
01; 34masn0m 00; 32mbuild-test.sh0m 00; 32mdelete-licence.sh0m 01; 34msrc0m
00; 32mbuild-doc.sh0m 00; 32mclean0m 01; 34mdoc-src0m 00mtest.ini0m
spl62 lepl:終了

2011年6月9日木曜日09:47:29 AM CLTにスクリプトが実行されました

回答:


57

次のスクリプトは、(ctlseqsに基づいて)すべてのANSI / VT100 / xterm制御シーケンスを除外する必要があります。最小限のテストを行います。一致または不一致を報告してください。

#!/usr/bin/env perl
## uncolor — remove terminal escape sequences such as color changes
while (<>) {
    s/ \e[ #%()*+\-.\/]. |
       \e\[ [ -?]* [@-~] | # CSI ... Cmd
       \e\] .*? (?:\e\\|[\a\x9c]) | # OSC ... (ST|BEL)
       \e[P^_] .*? (?:\e\\|\x9c) | # (DCS|PM|APC) ... ST
       \e. //xg;
    print;
}

既知の問題点:

  • 不正なシーケンスについて文句を言いません。それはこのスクリプトの目的ではありません。
  • DCS / PM / APC / OSCへの複数行の文字列引数はサポートされていません。
  • 128〜159の範囲のバイトは、制御文字として解析される場合がありますが、これはめったに使用されません。これは、非ASCII制御文字を解析するバージョンです(これにより、UTF-8を含む一部のエンコーディングで非ASCIIテキストが破損します)。
#!/usr/bin/env perl
## uncolor — remove terminal escape sequences such as color changes
while (<>) {
    s/ \e[ #%()*+\-.\/]. |
       (?:\e\[|\x9b) [ -?]* [@-~] | # CSI ... Cmd
       (?:\e\]|\x9d) .*? (?:\e\\|[\a\x9c]) | # OSC ... (ST|BEL)
       (?:\e[P^_]|[\x90\x9e\x9f]) .*? (?:\e\\|\x9c) | # (DCS|PM|APC) ... ST
       \e.|[\x80-\x9f] //xg;
    print;
}

両方の答えに感謝します。良い答えとして何かを作るべきだと感じましたが、どちらも正規表現を与えますが、それは避けたいと思いました。形式の参照を提供するため、これを選択しました。
アンドリュークック

@andrew:私の正規表現は十分に柔軟であるため、現在存在するほとんどすべての端末で動作し、おそらく明日既存の端末でも動作するはずです。私はそれをあまりテストしていないので、バグがあるかもしれませんが、制御シーケンスはいくつかの一般的なパターンに従うので、アプローチは健全です。
ジル 'SO-悪であるのをやめる'

このスクリプトの使用方法を提供してください。パイプ入力が必要ですか?または位置引数?
トレバーボイドスミス

@TrevorBoydSmithどちらも入力に対して機能し、出力は通常のテキストユーティリティのように常に標準出力に出力されます。
ジル 'SO-悪であるのをやめる'

これは、as(\ xe2 \ x98 \ xba)などのマルチバイト文字をマングルします。[\ x80- \ x9f]句は中間バイトを取り除きます。
ジェフリー

31

Gillesの回答を更新して、キャリッジリターンを削除し、前の文字のバックスペース消去も行います。これは、Cygwinで生成されたタイプスクリプトにとって私にとって重要でした。

#!/usr/bin/perl
while (<>) {
    s/ \e[ #%()*+\-.\/]. |
       \r | # Remove extra carriage returns also
       (?:\e\[|\x9b) [ -?]* [@-~] | # CSI ... Cmd
       (?:\e\]|\x9d) .*? (?:\e\\|[\a\x9c]) | # OSC ... (ST|BEL)
       (?:\e[P^_]|[\x90\x9e\x9f]) .*? (?:\e\\|\x9c) | # (DCS|PM|APC) ... ST
       \e.|[\x80-\x9f] //xg;
       1 while s/[^\b][\b]//g;  # remove all non-backspace followed by backspace
    print;
}

+1私はあなたのスクリプトと@Gillesのメッセージでこのメッセージを気に入ったとき、OPと同じ質問で投稿をすでに入力していました。あなたの両方のために+1
miracle173

10

sedこの場合に使用します。

行う:

cat -v typescript | sed -e "s/\x1b\[.\{1,5\}m//g"

sed -e "s / search / replace / g"は標準のものです。正規表現は次のように説明されています。

\x1bカラーコードの前のエスケープと \[一致し、最初のオープンブラケットと .\{1,5\}一致し、任意の1文字の1〜5と一致します。\シェルがそれらをマングルするのを防ぐために、中括弧に入れなければなりません。 m正規表現の最後の文字-通常は色コードの後ろに付きます。 //すべてを置き換える対象の空の文字列。 g行ごとに複数回一致します。


3
この正規表現はストリップしすぎて(の代わりにfoo\e[1m(1m = {なりfoo = {ますfoo(m = {)、置換.により[0-9;]正確です。
Lekensteyn

交換.\{1,5\}[^m]\{1,5\}その方法-も、これはその後も依然としてのみ「グラフィック表現」コード(で終わるものを除去することに注意m) -基本的に色、反転、太字およびイタリックスタイルを(該当する場合)。
ハヌ

これは、削除されない\x1b(B(錆の色出力に含まれる)
ideasman42

1
なぜそれで\x1bはありませんか\033
ストライプ

それはあるかもしれない\u001b代わりに\x1b
yunzen


6
# The "sed -r" trick does not work on every Linux, I still dunno why:
DECOLORIZE='eval sed "s,${END}\[[0-9;]*[m|K],,g"'

=>使用方法:

<commands that type colored output> | ${DECOLORIZE}

テスト済み:-AIX 5.x / 6.1 / 7.1-Linux Mandrake / Mandriva / SLES / Fedora-SunOS


3

scriptreplay画面で実行し、スクロールバックバッファーをファイルにダンプすることで問題を解決しました。

次のexpectスクリプトがこれを行います。

最大250.000行のログファイルでテストされています。作業ディレクトリには、スクリプトログ、行に「1 10」の10.000.000倍の「time」というファイル、およびスクリプトが必要です。のようなコマンドライン引数としてスクリプトファイルの名前が必要./name_of_script name_of_scriptlogです。

#!/usr/bin/expect -f 

set logfile [lindex $argv 0]

if {$logfile == ""} {puts "Usage: ./script_to_readable.exp \$logfile."; exit}

set timestamp [clock format [clock sec] -format %Y-%m-%d,%H:%M:%S]
set pwd [exec pwd]
if {! [file exists ${pwd}/time]} {puts "ERROR: time file not found.\nYou need a file named time with 10.000.000 times the line \"1 10\" in the working directory for this script to work. Please provide it."; exit}
set wc [exec cat ${pwd}/$logfile | wc -l]
set height [ expr "$wc" + "100" ]
system cp $logfile ${logfile}.tmp
system echo $timestamp >> ${logfile}.tmp
set timeout -1
spawn screen -h $height -S $timestamp 
send "scriptreplay -t time -s ${logfile}.tmp 100000 2>/dev/null\r"
expect ${timestamp} 
send "\x01:hardcopy -h readablelog.${timestamp}\r"

send "exit\r"

system sed '/^$/d' readablelog.$timestamp >> readablelog2.$timestamp
system head -n-2 readablelog2.$timestamp >> ${logfile}.readable.$timestamp
system rm -f readablelog.$timestamp readablelog2.$timestamp ${logfile}.tmp

タイムファイルは次の方法で生成できます。

for i in $(seq 1 10000000); do echo "1 10" >> time; done

タイムファイルを生成するコマンドは、数分間100%のCPU使用率を生成し、終了後、メモリ使用率は100%になり、コマンドを実行すると「fork:cannot allocate memory」が発生しました。そして、期待通りに機能しませんでした。
barteks2x

タイミングファイルを生成するはるかに簡単な方法があります。フィールドは「delay blocksize」であるため、単に「0 <entirefile>」にして、遅延なくすべてをダンプしない理由はありません。スクリプトのサイズから最初の行(tail -n +2 typescript|wc -c)を引いたものを取得し、でタイミングファイルを作成することで、これを行うことができますecho "0 "`tail -n +2 typescript|wc -c` > timing。基本的には瞬時に実行され、scriptreplayスクリプト全体が可能な限り高速で再生されます。
FeRD

1

同じ問題の解決策を探しているときに、この質問を見つけました。もう少し掘り下げて、このリンクのLive Journalでこのスクリプトを見つけました。私は完璧に働いた。また、この問題とその解決方法についての非常に優れた記事でもあります。間違いなく読む価値があります。 http://jdimpson.livejournal.com/7040.html

#!/usr/bin/perl -wp

# clean up control characters and other non-text detritus that shows up 
# when you run the "script" command.

BEGIN {
# xterm titlebar escape sequence
$xtermesc = "\x1b\x5d\x30\x3b";

# the occurence of a backspace event (e.g. cntrl H, cntrol W, or cntrl U)
$backspaceevent = "\x1b\\\x5b\x4b"; # note escaping of third character

# ANSI color escape sequence
$ansiesc = qr/\x1b\[[\d;]*?m/;

# technically, this is arrow-right. For some reason, being used against
# very long backspace jobs. I don't fully understand this, as evidenced
# by the fact that is off by one sometimes.
$bizarrebs = qr/\x1b\[C/;

# used as part of the xterm titlebar mechanism, or when
# a bell sounds, which might happen when you backspace too much.
$bell = "\x07"; # could use \a

$cr = "\x0d"; # could use \r

$backspace = "\x08"; # could use \b
}

s/$xtermesc.+?$bell//g;
s/[$cr$bell]//g;
s/${backspaceevent}//g;
s/$ansiesc//g;
while (s/(.)(?=$backspace)//) { s/$backspace//; } # frickin' sweet 
# For every ^H delete the character immediately left of it, then delete the ^H.
# Perl's RE's aren't R, so I wonder if I could do this in one expression.
while (s/(..)(?=$bizarrebs)//) { s/$bizarrebs//; }

1

スクリプト出力をプレーンテキストに変換するための専用ツールを使用することをお勧めします。プレーンテキストは、カスタム正規表現よりも常にサポートされ、十分にテストされています。だから、これは私のために仕事をしました:

$ cat typescript | ansi2txt | col -bp > typescript.txt.bp    
$ cat -v typescript.txt.bp

スクリプトコマンドはtypescriptファイルansi2txtにキャプチャします-カラーコード、バックスペースなどのエスケープを含むANSIコードを通常のテキストに変換しますが、いくつかのエスケープがまだ残っていることがわかりました。col -bp-それらを完全に削除しました。

これを最新のUbuntuディスコでテストしましたが、動作します。


1

Ubuntu ansi2txtcolorized-logsパッケージにはコマンドがあります。ANSIカラーコードは適切に削除されますが、放出によって生成されるプログレスバー^H^M、所定の位置にテキストを上書きする文字などは処理されません。 それらcol -bを扱うことができるので、最良の結果を得るには、2つを組み合わせることができます

cat typescript | ansi2txt | col -b

0

ターミナルでcat出力を表示するには、使用するだけで十分であることがわかりましたscript。これは、出力を別のファイルにリダイレクトするときに役立ちませんが、、、またはテキストエディターとは異なりcat -v、結果を読みやすくcol -bします。

色を削除するか、結果をファイルに保存するcatには、テキストエディターまたは別のcatコマンドに出力を手動でコピーして貼り付けます。

cat > endResult << END
<paste_copied_text_here>
END

1
あなたでしたscriptランはOPの場合のように、付属のカラーコードで出力が含まれていますか?
ジェフシャラー

を使用catすると元の色が表示されますが、手動でコピーして貼り付けると削除できます。OPはとを使用cat -vしましたがcol -b、どちらも適切にフォーマットされた最終結果ではなくコードを示します。回答を編集しました。
ロジャーデュック

-2

trと:cntrl:を使用する最後の回答のフォローアップ

sed "/^[[:cntrl:]]/d" output.txt

viによって生成されるすべての行は制御文字で始まるため、これは私にとってはうまくいくようです。また、空白行とタブで始まる行を削除することもありますが、それは私がやっていることに対しては機能します。\ n \ m \ t以外の制御文字に一致する方法があるかもしれません。

特定の制御文字を検索できるかもしれませんが、viで生成されるすべてのジャンク行は^ [のような形式で始まるように見えます。hexdumpは最初の文字が1bであることを教えてくれるので、これもうまくいくようです

sed "/^\x1b/d" output.txt

これは上記の回答に似ていますが、コマンドを実行した後、ユーザーが入力したかのように一部のジャンク文字がコマンドラインに既に追加されているため、正しく機能しません。


1
回答は順序を変更できるため、「最後の回答」はありません。参照する回答の下にある「共有」ボタンを使用し、それを回答のリンクとして含める必要があります。もちろん、あなたの答えがコメント以上のものであると仮定します。今、あなたが参照しているいくつかの答えのどれを特定することはできません。
ロアイマ

1
「できれば…」はい、できますが、制御文字始まるすべての行削除します。たとえば、ls --color(質問に示されているように)出力では、ソリューションは情報を含むほぼすべての行を削除します。良くない。しかし、の無駄な使用を除外してくれてありがとうcat。:-)⁠
G-マン

:iscntrl:であるが:isspace:ではない文字クラスを作成する方法はありますか?^ [[:iscntrl:]-[:isspace]]のような構文かもしれませ
ん-snaran

-4

tr -文字の翻訳または削除

cat typescript | tr -d [[:cntrl:]]

Unix Stackexchangeへようこそ!答えを出すとき、あなたの答えなぜなのかについての説明をすることが望ましい。
スティーブンラウチ


3
これは01;34m、たとえばa を削除せず、行末を削除するため、実際には正しく機能しませんnewline (\n)
sorontar
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.