Удаление контрольных символов (включая коды / цвета консоли) из вывода скрипта


68

Я могу использовать команду «script» для записи интерактивного сеанса в командной строке. Однако сюда входят все управляющие символы и цветовые коды. Я могу удалить управляющие символы (например, backspace) с помощью «col -b», но я не могу найти простой способ удаления цветовых кодов.

Обратите внимание, что я хочу использовать командную строку обычным способом, поэтому не хочу отключать цвета там - я просто хочу удалить их из вывода скрипта. Кроме того, я знаю, что могу поиграть и попытаться найти регулярное выражение, чтобы исправить ситуацию, но я надеюсь, что есть более простое (и более надежное - что, если есть код, о котором я не знаю, когда разрабатываю регулярное выражение?).

Чтобы показать проблему:

spl62 tmp: скрипт
Скрипт запущен, файл машинописный
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: выход
Скрипт готов, файл машинописный
spl62 tmp: cat -v машинопись
Сценарий начался в четверг 09 июня 2011 09:47:27 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: выход ^ M

Сценарий сделан в четверг 09 июня 2011 09:47:29 CLT
spl62 tmp: col -b <машинопись 
Сценарий начался в четверг 09 июня 2011 09:47:27 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: выход

Сценарий сделан в четверг 09 июня 2011 09:47:29 CLT

Ответы:


57

Следующий скрипт должен отфильтровывать все управляющие последовательности ANSI / VT100 / xterm для (на основе ctlseqs ). Минимально проверено, пожалуйста, сообщите о любом недостаточном или чрезмерном совпадении.

#!/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 управляющие символы (это будет искажать не-ASCII-текст в некоторых кодировках, включая UTF-8).
#!/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: мое регулярное выражение достаточно гибкое, и я ожидаю, что оно будет работать практически с любым существующим терминалом, а также, возможно, с любым завтрашним терминалом. Я не очень много тестировал, поэтому могут быть ошибки, но подход обоснован, поскольку последовательности управления следуют нескольким общим схемам.
Жиль "ТАК - перестать быть злым"

Пожалуйста, укажите, как использовать этот скрипт. это требует ввода трубы? или позиционные аргументы?
Тревор Бойд Смит

@TrevorBoydSmith Либо будет работать для ввода, и вывод всегда на стандартный вывод, как типичные текстовые утилиты.
Жиль "ТАК - перестань быть злым"

Это искажает многобайтовые символы, такие как ☺ (\ xe2 \ x98 \ xba). Предложение [\ x80- \ x9f] удаляет средний байт.
Джеффри

31

Обновление ответа Жиля, чтобы также убрать возврат каретки и удалить назад символы, которые были важны для меня для машинописи, сгенерированной в 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. +1 для вас обоих
чудо173

10

Я бы использовал sedв этом случае.

делать:

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

sed -e "s / search / replace / g" является стандартным материалом. регулярное выражение объясняется как показано ниже:

\x1bсовпадение с Escape, предшествующим цветному коду; \[совпадение первой открытой скобки; .\{1,5\}совпадение от 1 до 5 любого отдельного символа. Придется \использовать фигурные скобки, чтобы оболочка не повредила их. mпоследний символ в регулярном выражении - обычно трейлинг цветовой код. //пустая строка для того, чтобы заменить все. gсопоставьте его несколько раз в строке.


3
Это регулярное выражение слишком много ( foo\e[1m(1m = {становится foo = {вместо foo(m = {), замена .на [0-9;]более точным.
Лекенстейн

Заменить .\{1,5\}с [^m]\{1,5\}для этого - но обратите внимание , что даже тогда еще только удаляет «графические выдач» коды (те , которые заканчиваются в m) - в основном цвет, реверс, полужирный и курсивный стили (где это применимо).
Ханну

Это не удаляет \x1b(B(включено в вывод цвета ржавчины)
ideasman42

1
Почему это \x1bи нет \033?
atripes

Это может быть \u001bвместо\x1b
юнзен


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экран и выгрузив буфер прокрутки в файл.

Следующий ожидаемый скрипт сделает это за вас.

Он был протестирован для лог файлов с 250 000 строк. В рабочем каталоге вам нужен ваш скрипт-файл, файл с именем time, в котором 10.000.000 раз строка «1 10», и скрипт. Мне нужно имя вашего файла сценария в качестве аргумента командной строки, например ./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% -ную загрузку ЦП в течение нескольких минут, и после того, как она закончила, мое использование памяти было 100%, и выполнение команды привело к «fork: не может выделить память». И это не сработало так, как ожидалось.
barteks2x

Существует гораздо более простой способ создания файла синхронизации. Поля " delay blocksize", поэтому нет причин не просто сделать это " 0 <entirefile>" и выгрузить все без задержки. Вы можете сделать это, взяв размер скрипта минус первую строку ( tail -n +2 typescript|wc -c) и создав файл синхронизации с помощью echo "0 "`tail -n +2 typescript|wc -c` > timing. Это будет в основном мгновенно и scriptreplayвоспроизведет весь сценарий с максимально возможной скоростью.
Февраль

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

команда script записывает в файл машинописи ansi2txt - преобразует код ANSI с экранированием, таким как цветовые коды, символы возврата и т. д., в обычный текст, однако я обнаружил, что пара экранировок все еще остается. col-bp - удалил их полностью.

Я проверил это на последней дискотеке Ubuntu, и это работает.


1

В пакете есть ansi2txtкоманда colorized-logsна Ubuntu. Он удаляет цветовые коды ANSI, но не имеет ничего общего с такими индикаторами, как индикаторы выполнения, которые генерируются с помощью emit ^Hили ^Mсимволы для замены текста на месте. col -bможет иметь дело с тем , поэтому для достижения наилучших результатов вы можете объединить два

cat typescript | ansi2txt | col -b

0

Я обнаружил, что просто использовать catбыло все, что мне нужно, чтобы просмотреть вывод scriptв терминале. Это не помогает , когда перенаправив вывод в другой файл, но делает результат чтения, в отличие от cat -v, col -bили в текстовом редакторе.

Чтобы устранить цвета или сохранить результаты в файл, вручную скопируйте и вставьте выходные данные catв текстовый редактор или в другую catкоманду, например:

cat > endResult << END
<paste_copied_text_here>
END

1
Ваш scriptпробег включал вывод с прикрепленными цветовыми кодами, как в случае ОП?
Джефф Шаллер

Используя 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-Man

Есть ли способ создать класс символов, который: iscntrl: но не: isspace :? Может быть, какой-то синтаксис, такой как ^ [[: iscntrl:] - [: isspace]]
snaran

-4

tr - переводить или удалять символы

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

Добро пожаловать в Unix Stackexchange! Когда вы даете ответ, предпочтительно дать какое-то объяснение, ПОЧЕМУ ваш ответ тот.
Стивен Раух


3
Это на самом деле не будет работать правильно, так как это не удалит, 01;34mнапример, и удалит конец строки newline (\n).
Соронтар
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.