Почему вывод «столбца» смещен с помощью цветного ввода ANSI?

Я работаю над командной строкой, которая извлекает некоторые данные ( curl ), извлекает соответствующие поля ( awk ) и форматирует их ( столбец ).

Он работает хорошо, хотя он очень уродлив (но весь мой скрипт начинается с «слишком длинного и уродливого» однострочного шрифта), но когда я пытаюсь получить цветную колонку, вы ошибаетесь.

  • Tweak perl скрипт для чтения человеком dmesg
  • Как использовать шаблон с переменными в awk
  • Как получить количество байтов в одной строке файла?
  • Как изменить цвет фона приложений curses?
  • Сравнение 3 строк и 2 строк в BASH
  • Удалять строки из файлов с разделителями табуляции на основе общего столбца с другим файлом
  • Это простая (уменьшенная) версия, которая работает :

    curl "http://webservices.rm.ingv.it/fdsnws/event/1/query?lat=42.35&lon=13.4&maxradius=5.0&starttime=2016-01-01T00:00:00&endtime=2016-12-31T23:59:59&minmag=5&format=text&orderby=time-asc" 2>/dev/null \ | awk 'BEGIN { FS= "|"; OFS= "|" } {print $1, $2, $5, $10, $11, $13}' \ | column -t -s '|' 

    Теперь я хочу подчеркнуть некоторые поля, а затем добавить некоторый код escape ANSI в awk:

     curl "http://webservices.rm.ingv.it/fdsnws/event/1/query?lat=42.35&lon=13.4&maxradius=5.0&starttime=2016-01-01T00:00:00&endtime=2016-12-31T23:59:59&minmag=5&format=text&orderby=time-asc" 2>/dev/null \ | awk 'BEGIN { FS= "|" ; OFS= "|" } \ $13~/Rieti/||/Perugia/ {$13="\033[1;31m"$13"\033[0m"} \ $11~/[0-9]+/ && $11 > 5.8 {$11="\033[1;33m"$11"\033[0m"} {print $1, $2, $5, $10, $11, $13 }' \ | column -t -s '|' 

    Теперь выравнивание неверно (см. Рисунок).

    введите описание изображения здесь

    Зачем? И как я могу это исправить?

    ОБНОВИТЬ

    Я уже видел вопрос « Проблема с командами столбца и цветовыми кодами», но не решает проблему, потому что его ответы применяются и работают в случае полностью цветной линии.

    В моем случае я не могу применять или адаптировать ответы (или я не могу), потому что:

    1. Проблема ограничена случаем, когда цвет столбца $ 11 окрашен независимо от последующего столбца.
    2. Я не вижу хороший или элегантный способ добавить цветовой код после столбца.
      Если я отправлю вывод столбца в awk для теста, я не знаю, как проинструктировать awk для правильного разделения полей (если поля были разделены большим пространством, я мог бы использовать регулярное выражение, но в некоторых случаях разделение выполняется на одном пространстве, и awk не знали бы, как распознавать пробелы между словами и пространствами как Сепараторы полей).

    Единственное, что я вижу, это то, что если я переместил код сброса с присвоения блоку печати, первая строка была бы лучше отстоящей, например, версия с равным выходом (см. Ниже, \033[0m подчеркнута во второй командной строке): введите описание изображения здесь

    Затем, как мы можем это исправить? Есть другой способ, более элегантный, чтобы раскрасить, как я?

    (Я знаю, я могу сделать это лучше с некоторыми строками perl, но мне это интересно)

  • максимум столбца с совпадающим идентификатором
  • Как эффективно разделить большой текстовый файл без разделения многострочных записей?
  • Используйте FOR Loop внутри END-блока команды awk
  • Grep с диапазоном и пропускает три фильтра
  • разделение дампа MySQL с помощью awk
  • Присоедините два файла на основе столбца
  • One Solution collect form web for “Почему вывод «столбца» смещен с помощью цветного ввода ANSI?”

    Могут быть три простых способа исправить это:

    1. всегда используйте escape-последовательности в этих столбцах, чтобы поддерживать равную длину
    2. поместите эскапады в свои собственные столбцы (4 дополнительных столбца), хотя это добавляет дополнительные пробелы в выходе
    3. формат после column , как вы предложили

    Некоторые другие соображения можно найти здесь: Инструмент оболочки для «tablify» входных данных, содержащих escape-коды ANSI .

    Для первого варианта вместо использования только \033[1;31m для красного использования \033[31;1m для красного и \033[31;0m для "не красный" или обычный – код 0 отменяет любой предыдущий код, даже тех, кто в той же последовательности. Затем все столбцы имеют одинаковую длину escape-кодов.

     BEGIN { FS=OFS="|" } function colour(ss,cc) { return "\033[" cc ";1m" ss "\033[0m"; } function notcolour(ss,cc) { return "\033[" cc ";0m" ss "\033[0m"; } { if ($13~/(RI|PG)/) { $13=colour($13,31) } else { $13=notcolour($13,31) } if (($11+0) > 5.8) { $11=colour($11,33) } else { $11=notcolour($11,33) } print $1, $2, $5, $10, $11, $13 } 

    (Существует ряд незначительных упрощений и исправлений, примененных в вышеупомянутом, также, в том числе, чтобы соответствовать изменениям исходных данных.)

    Проблема с этим подходом заключается в том, что это зависит от вашей column и libc . (Мой column от util-linux-2.23.2) не проверяет код возврата из wcswidth() который равен -1, если найдены непечатные данные вместо фактической ширины; это действительно испортит форматирование таблицы. В последней версии от util-linux-2.30.1 используются новые libsmartcols, которые решают эту проблему, но это происходит путем замены непечатаемых версией \x hex-encoded – так что вы полностью теряете исходные экраны: / Что вы можете исправить с неэлегантным:

     curl ... | awk ... | column -t -s '|' | while read -r line; do printf "$line\n"; done 

    где printf интерпретирует printf последовательности. Вы можете заменить \033 на \\x1b в своем собственном коде для того же эффекта. Я не уверен, что вы используете Linux.)

    Для третьего варианта вам понадобится column который поддерживает -o для установки разделителя вывода, по умолчанию это два пробела. Установите его на « | », затем вы можете использовать это:

     curl ... | column -t -s "|" -o "|" | awk ' BEGIN { FS="|" } function colour(ss,cc) { return sprintf("\033[%i;1m%s\033[0m",cc,ss) } { if ($13~/(RI|PG)/) { $13=colour($13,31) } if (($11+0) > 5.8) { $11=colour($11,33) } print $1, $2, $5, $10, $11, $13 }' 

    Хитрость здесь заключается в том, что мы используем column с вводом и выводом с разделителями каналов, он фиксирует ширину, и мы можем безопасно обрабатывать это с помощью awk , сохраняя все важные пространства. Если ваша column не поддерживает -o вы можете подделать ее с помощью:

     curl ... | sed -e 's/|/^|/g' | column -t -s^ | awk ... 

    Это удваивает разделитель до « ^| », column использует ^ и awk использует | , Это делает предположение, что ^ не входит в данные, конечно. Вместо этого может работать жесткая вкладка.

    Я думаю, что теперь вы знаете «почему», но чтобы быть ясным:

    • column может наименовать октеты (или символы) наивно с помощью strlen() / wcslen() , это не будет соответствовать длине, отображаемой терминалом
    • column может рассчитывать длину, используя isprint() , также неверную с выводами терминала
    • column может отказаться (как и мой) в любом столбце, когда встречаются непечатные

    Хотя удаление цветовых кодовых последовательностей является достаточно простой проблемой, нет надежного способа обойти это без наличия в терминале эмулятора терминала ANSI.

    Linux и Unix - лучшая ОС в мире.