Мой незавершенный сценарий отображает раскрашенную таблицу с несколькими столбцами, но цветовые коды мешают форматированию. Цветовые коды не могут быть перемещены в строку формата, поскольку цвет некоторых столбцов меняется от строки к строке. В соответствующих вопросах и ответах (приведенных ниже) решения не приведены. Ниже я привел урезанные примеры и обходные пути.

Мое фактическое использование - это сценарий bash, отображающий таблицу из 11 столбцов с разными столбцами разных цветов, сгенерированный при циклическом просмотре множества файлов jpg, анализе различных данных exif и выводе результатов в виде строки в таблице, причем некоторые цвета также отличаются от строки для строки на основе результатов анализа exif.

Но, как я уже сказал, ниже я привел урезанные примеры обходных путей.

Вот упрощенный фрагмент отображаемой таблицы, демонстрирующий проблему:

# RedBlk defined in .bashrc.local as RedBlk="^[[0;31;40m"
# DefDef defined in .bashrc.local as DefDef="^[[0m"
(GrnBlk=$(tput setaf 2)
 YelBlk="\e[1;33m"
 echo "123456789 123456789"
 for ii in {8..13}; do
 case $ii in
   8|9) clr1=""; clr2="";;
    11) clr1=$RedBlk; clr2="";;
    12) clr1=$YelBlk; clr2=$GrnBlk;;
     *) clr1=$GrnBlk; clr2=$RedBlk;;
  esac
  printf "%6d %6b$DefDef %6b\n"   $((ii*2))   $clr1$ii    $clr2$((ii*4)) 
done)

.... с выводом:

123456789 123456789
    16      8     32
    18      9     36
    20 10 40
    22 11     44
    24 12 48
    26 13 52

Обратите внимание, что та же проблема возникает при использовании "^[[0;31;40m" или $(tput setaf 2) или "\e[1;33m".

Вот упрощенный пример:

(echo "123456789 123456789 123456789"
 printf "%20s\n" "Hello""Again"
 printf "%20s\n" $RedBlk"Hello"$DefDef"Again"
)

.... с выводом:

123456789 123456789 123456789
          HelloAgain
HelloAgain

Два обходных пути: 1) изменить ширину поля (например, с 20 до 20+${#RedBlk}+${#DefDef} = 20+10+4 в упрощенном примере) и 2) разделить строку и взломать формат:

(echo "123456789 123456789 123456789"
 printf "%20s\n"       "Hello""Again"
 printf "%34s\n"       $RedBlk"Hello"$DefDef"Again"
 printf "%s%15s%s%s\n" $RedBlk "Hello" $DefDef "Again"
)

.... с выводом:

123456789 123456789 123456789
      HelloAgain
      HelloAgain
      HelloAgain

Но оба обходных пути очень неуклюжи, учитывая фактическое использование.

Эти вопросы и ответы, хотя и связаны между собой, не дают решения:

https://stackoverflow.com/questions/67638971/how-to-get-color-and-width-formatting-with-printf

https://stackoverflow.com/questions/58519511/bash-printf-formated-output-with-colors

https://stackoverflow.com/questions/5412761/using-colors-with-printf

Как использовать printf и %s, когда есть цветовые коды?

Какие есть более простые решения?

Вот что я использую:

bash --version
GNU bash, version 4.4.12(1)-release (x86_64-pc-linux-gnu)

# which printf
/usr/bin/printf
# /usr/bin/printf --version
printf (GNU coreutils) 8.26

# /usr/bin/xterm -version
XTerm(327)
1
Mic 23 Сен 2021 в 04:03
Вы столкнулись с проблемой «невидимого персонажа». Строки раскрашиваемых символов занимают место в буфере, но не отображаются на экране. bash обрабатывает это в PROMPTING с \[ и \]. Внимательно следите как за положением в буфере, так и за положением на экране.
 – 
waltinator
23 Сен 2021 в 00:27
Я прочитал PROMPTING на справочной странице bash, но не могу понять, как использовать \[ и \] с printf, например printf "%10s\n" "\["$RedBlk'\]'"aaaa"\[$DefDef\] дает \[\]aaaa[]
 – 
Mic
23 Сен 2021 в 04:19
Я сказал, что они bash PROMPTING используются.
 – 
waltinator
23 Сен 2021 в 04:25

2 ответа

Одним из решений является динамическое создание строки формата на каждой итерации цикла, как в

 fmt=`printf  "%b"  "%6d "$clr1"%6d$DefDef "$clr2"%6d"$DefDef`
 printf "$fmt\n"   $((ii*2))   $ii    $((ii*4)) 

Полный:

(DefDef=$(tput init)
 RedBlk=$(tput setaf 1)
 GrnBlk=$(tput setaf 2)
 YelBlk="\e[1;33m"
 echo "123456789 123456789"
 for ii in {8..13}; do
 case $ii in
   8|9) clr1=""; clr2="";;
    11) clr1=$RedBlk; clr2="";;
    12) clr1=$YelBlk; clr2=$GrnBlk;;
     *) clr1=$GrnBlk; clr2=$RedBlk;;
 esac
 fmt=`printf  "%b"  "%6d "$clr1"%6d$DefDef "$clr2"%6d"$DefDef`
 printf "$fmt\n"   $((ii*2))   $ii    $((ii*4)) 
done)

.... с выводом:

123456789 123456789
    16      8     32
    18      9     36
    20     10     40
    22     11     44
    24     12     48
    26     13     52
0
Mic 23 Сен 2021 в 00:10

Другое решение состоит в том, чтобы окружить каждое поле последовательностями одинаковой длины COLOR_ON(color) и COLOR_OFF (color обычно равно black). Работайте с этой длиной.

0
waltinator 23 Сен 2021 в 04:31