Xóa mã màu ANSI khỏi luồng văn bản


73

Kiểm tra đầu ra từ

perl -e 'use Term::ANSIColor; print color "white"; print "ABC\n"; print color "reset";'

trong trình soạn thảo văn bản (ví dụ vi:) hiển thị như sau:

^[[37mABC
^[[0m

Làm thế nào để loại bỏ mã màu ANSI khỏi tệp đầu ra? Tôi cho rằng cách tốt nhất sẽ là dẫn đầu ra thông qua một trình soạn thảo luồng.

Những điều sau đây không hoạt động

perl -e 'use Term::ANSIColor; print color "white"; print "ABC\n"; print color "reset";' | perl -pe 's/\^\[\[37m//g' | perl -pe 's/\^\[\[0m//g'

Không phải là một câu trả lời cho câu hỏi, nhưng bạn cũng có thể dẫn đầu ra đến morehoặc less -Rcó thể hiểu mã thoát là màu thay vì trình soạn thảo văn bản.
terdon

Câu trả lời:


98

Các ký tự ^[[37m^[[0mlà một phần của chuỗi thoát ANSI (mã CSI) . Xem thêm các thông số kỹ thuật .

Sử dụng GNU sed

sed 's/\x1b\[[0-9;]*m//g'
  • \x1b(hoặc \x1B) là ký tự đặc biệt thoát
    ( sedkhông hỗ trợ thay thế \e\033)
  • \[ là nhân vật thứ hai của chuỗi thoát
  • [0-9;]* là giá trị màu (s) regex
  • m là nhân vật cuối cùng của chuỗi thoát

Trên macOS, sedlệnh mặc định không hỗ trợ các ký tự đặc biệt \enhư được chỉ ra bởi slmsteamer25 trong các bình luận. Sử dụng thay thế gsedmà bạn có thể cài đặt bằng cách sử dụng brew install gnu-sed.

Ví dụ với dòng lệnh của OP:   (OP có nghĩa là Poster gốc)

perl -e 'use Term::ANSIColor; print color "white"; print "ABC\n"; print color "reset";' | 
      sed 's/\x1b\[[0-9;]*m//g'

Tom Hale đề nghị loại bỏ tất cả các chuỗi thoát khác bằng cách sử dụng [a-zA-Z]thay vì chỉ chữ cái mcụ thể cho chuỗi thoát chế độ đồ họa (màu sắc). Nhưng [a-zA-Z]có thể quá rộng và có thể loại bỏ quá nhiều. Michał FaleńskiMiguel Mota đề xuất chỉ loại bỏ một số chuỗi thoát bằng cách sử dụng [mGKH][mGKF]tương ứng. Britton Kerin cho biết Kcũng phải được sử dụng ngoài mviệc xóa màu khỏi gcclỗi / cảnh báo (đừng quên chuyển hướng gcc 2>&1 | sed...).

sed 's/\x1b\[[0-9;]*m//g'           # Remove color sequences only
sed 's/\x1b\[[0-9;]*[a-zA-Z]//g'    # Remove all escape sequences
sed 's/\x1b\[[0-9;]*[mGKH]//g'      # Remove color and move sequences
sed 's/\x1b\[[0-9;]*[mGKF]//g'      # Remove color and move sequences
Last escape
sequence
character   Purpose
---------   -------------------------------
m           Graphics Rendition Mode (including Color)
G           Horizontal cursor move
K           Horizontal deletion
H           New cursor position
F           Move cursor to previous n lines

Sử dụng perl

Phiên bản sedcài đặt trên một số hệ điều hành có thể bị giới hạn (ví dụ: macOS). Lệnh perlnày có ưu điểm là thường dễ cài đặt / cập nhật hơn trên nhiều hệ điều hành. Adam Katz đề nghị sử dụng \e(giống như \x1b) trong PCRE .

Chọn regex của bạn tùy thuộc vào số lượng lệnh bạn muốn lọc:

perl -pe 's/\e\[[0-9;]*m//g'          # Remove colors only
perl -pe 's/\e\[[0-9;]*[mG]//g'
perl -pe 's/\e\[[0-9;]*[mGKH]//g'
perl -pe 's/\e\[[0-9;]*[a-zA-Z]//g'
perl -pe 's/\e\[[0-9;]*m(?:\e\[K)?//g' # Adam Katz's trick

Ví dụ với dòng lệnh của OP:

perl -e 'use Term::ANSIColor; print color "white"; print "ABC\n"; print color "reset";' \
      | perl -pe 's/\e\[[0-9;]*m//g'

Sử dụng

Như được chỉ ra bởi nhận xét của Stuart Cardall , seddòng lệnh này được sử dụng bởi dự án Ultimate Nginx Bad Bot (1000 sao) để làm sạch báo cáo email ;-)


2
Cảm ơn sedlệnh và giải thích. :)
Redsandro

2
Một số mã màu (ví dụ: thiết bị đầu cuối Linux) chứa tiền tố, ví dụ như 1;31mvậy tốt hơn ;để thêm vào biểu thức chính của bạn: cat colored.log | sed -r 's/\x1b\[[0-9;]*m//g'hoặc chúng sẽ không bị tước.
Redsandro

1
cái này được sử dụng rất tốt trong github.com/mitchellkrogza/nginx-ultimate-bad-bot-blocker/blob/ mẹo để dọn dẹp báo cáo email.
Stuart Cardall

2
Hãy nhớ rằng phiên bản OSX sedkhông hoạt động với ví dụ được hiển thị, gsedtuy nhiên phiên bản này có.
slm

2
Thêm ngữ cảnh cho nhận xét của slm về OSX sed: nó không hỗ trợ các ký tự điều khiển như \ x1b. Ví dụ: stackoverflow.com/a/14881851/93345 . Bạn có thể nhận lệnh gsed qua brew install gnu-sed.
hấp25


10

Những gì được hiển thị ^[không ^[; đó là ký tự ASCII ESC, được tạo bởi Eschoặc Ctrl[( ^ký hiệu có nghĩa là phím Ctrl).

ESClà 0x1B thập lục phân hoặc 033 bát phân, vì vậy bạn phải sử dụng \x1Bhoặc \033trong biểu thức chính của mình:

perl -pe 's/\033\[37m//g; s/\033[0m//g'

perl -pe 's/\033\[\d*(;\d*)*m//g'

6

Nếu bạn thích thứ gì đó đơn giản, bạn có thể sử dụng mô-đun dải-ansi ( bắt buộc phải có Node.js ):

$ npm install --global strip-ansi-cli

Sau đó sử dụng nó như thế này:

$ strip-ansi < colors.o

Hoặc chỉ cần vượt qua trong một chuỗi:

$ strip-ansi '^[[37mABC^[[0m'

Đây là một cách sử dụng vô ích cat( UUOC ) - strip-ansi colors.oít nhất có thể làm được strip-ansi < colors.o.
Scott

1
@Scott Chắc chắn, bạn cũng có thể làm strip-ansi < colors.o, nhưng từ kinh nghiệm mọi người quen thuộc hơn với đường ống. Tôi đã cập nhật câu trả lời.
Sindre Sorhus

giải pháp đơn giản tốt
Penghe Geng


2

Câu hỏi "đã trả lời" không hiệu quả với tôi, vì vậy tôi đã tạo regex này thay vào đó để loại bỏ các chuỗi thoát được tạo bởi mô-đun Perl Term :: ANSIColor.

cat colors.o | perl -pe 's/\x1b\[[^m]+m//g;

Regex của Grawity sẽ hoạt động tốt, nhưng sử dụng + 's dường như cũng hoạt động tốt.


4
(1) Ý của bạn là The "answered" questiongì? Bạn có nghĩa là câu trả lời được chấp nhận? (2) Lệnh này không hoạt động - thậm chí nó không thực thi - bởi vì nó có một trích dẫn (không cân bằng) chưa từng có. (3) Đây là một cách sử dụng vô ích cat( UUOC ) - nên có thể làm được . (4) Ai đã từng nói bất cứ điều gì về các mã trong một tập tin? perl -pe command colors.o.o
Scott

2

Tôi tin rằng đây là một loại bỏ có thẩm quyền của tất cả các chuỗi thoát ANSI :

perl -pe '
  s/\e\[[\x30-\x3f]*[\x20-\x2f]*[\x40-\x7e]//g;
  s/\e[PX^_].*?\e\\//g;
  s/\e\][^\a]*(?:\a|\e\\)//g;
  s/\e[\[\]A-Z\\^_@]//g;'

(Xin lưu ý perl rằng, giống như nhiều ngôn ngữ khác (nhưng không sed), chấp nhận \elà ký tự thoát Esc, \x1bhoặc \033theo mã, thể hiện trong thiết bị đầu cuối như ^[. Tôi đang sử dụng nó ở đây vì nó có vẻ trực quan hơn.)

Lệnh perl này, mà bạn có thể chạy tất cả trên một dòng nếu bạn thích, có bốn thay thế trong đó:

Phần đầu tiên đi sau các chuỗi CSI (các chuỗi mã thoát bắt đầu bằng "Trình tự trình tự điều khiển" Esc[, bao gồm nhiều hơn các chuỗi Chọn đồ họa tạo thành mã màu và các trang trí văn bản khác).

Sự thay thế thứ hai loại bỏ các chuỗi còn lại liên quan đến các ký tự kéo dài và kết thúc bằng ST (Bộ kết thúc chuỗi, Esc\). Việc thay thế thứ ba là điều tương tự nhưng cũng cho phép điều hành chỉ huy hệ thống chuỗi kết thúc với một BEL ( \x07, \007, thường \a).

Sự thay thế thứ tư loại bỏ các lối thoát còn lại.

Đồng thời xem xét loại bỏ các ký tự ASCII có độ rộng bằng không khác như BEL và các ký tự điều khiển C0 và C1 tối nghĩa khác . Tôi đã và đang sử dụng s/[\x00-\x1f\x7f-\x9f\xad]+//g, bao gồm XóaDấu gạch nối mềm . Điều này không bao gồm các ký tự có độ rộng bằng 0 được mã hóa cao hơn của Unicode nhưng tôi tin rằng nó hoàn toàn dành cho ASCII (Unicode \x00- \xff). Nếu bạn làm điều này, loại bỏ những cái cuối cùng vì chúng có thể được tham gia vào chuỗi dài hơn.


1

"tput sgr0" để lại ký tự điều khiển này ^ (B ^ [
Đây là phiên bản sửa đổi để xử lý vấn đề đó.

perl -pe 's/\e[\[\(][0-9;]*[mGKFB]//g' logfile.log

Cảm ơn vì điều này ... điều này đã giúp tôi thoát khỏi điều tput sgr0đó mà các giải pháp khác dường như không bao giờ có thể thoát khỏi.
TxAG98

0

Tôi gặp vấn đề tương tự với việc xóa các ký tự được thêm vào từ việc thu thập đầu ra tương tác thông qua putty và điều này đã giúp:

cat putty1.log | perl -pe 's/\x1b.*?[mGKH]//g'

3
Đây là một cách sử dụng vô ích cat( UUOC ) - nên có thể làm được . perl -pe command putty1.log
Scott

0

Đây là những gì làm việc cho tôi (đã thử nghiệm trên Mac OS X)

perl -pe 's/\[[0-9;]*[mGKF]//g'
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.