Есть много программ, печатающих что-нибудь в терминал. Но их можно сильно разнообразить: можно покрасить текст, двигать курсор или переписать какой-нибудь текст поверх старого. Благодаря этому в Git красивые прогресс-бары, а Vim и Nano позволяют редактировать текст внутри терминала, как будто это происходит в обычном блокноте.
Существуют библиотеки, которые помогают в такой работе с терминалом. Но куда круче научиться делать это самостоятельно. В этой статье мы рассмотрим, что можно сделать простой командой print
в Python.
Большинство программ взаимодействуют с терминалом через управляющие коды ANSI. Это специальные инструкции для терминала. В терминалах разных систем поддерживаются разные коды. В Википедии есть список поддерживаемых кодов. В этой статье мы научимся работать с терминалами Unix систем: Ubuntu или OS-X. Но не на Windows, это отдельное приключение.
Начнём с простого вывода в консоль:
Так выглядит обычный, не покрашенный текст.
Самое простое, что можно сделать с текстом, это покрасить его. ANSI коды для этого выглядят так:
- Красный:
\u001b[31m
- Вернуть как было:
\u001b[0m
С комбинации \u001b
начинаются большинство ANSI кодов. Вот как покрасить Hello, World!
:
Если присмотреться, можно заметить, что покрасилась не только фраза Hello, World!
, но и всё что под ней. Терминал получил команду "Теперь выводи всё красным", поэтому он покрасил всё, что мы вводили далее. Как вы видите, он прекратил "красный" вывод, когда получил команду "Верни как было": \u001b[0m
.
Чтобы получилось аккуратно, лучше ставить команду "Верни как было" сразу после фразы:
С этим разобрались, а как ещё можно красить? У большинства терминалов есть 8 базовых цветов:
Цвет | Код |
---|---|
Чёрный | \u001b[30m |
Красный | \u001b[31m |
Зелёный | \u001b[32m |
Жёлтый | \u001b[33m |
Синий | \u001b[34m |
Пурпурный | \u001b[35m |
Голубой | \u001b[36m |
Белый | \u001b[37m |
Сброс цвета | \u001b[0m |
Чтобы сделать цвет ярче, можно прибавить к коду ;1
. Получается ещё 8 цветов:
Цвет | Код |
---|---|
Яркий чёрный | \u001b[30;1m |
Яркий красный | \u001b[31;1m |
Яркий зелёный | \u001b[32;1m |
Яркий жёлтый | \u001b[33;1m |
Яркий синий | \u001b[34;1m |
Яркий пурпурный | \u001b[35;1m |
Яркий голубой | \u001b[36;1m |
Яркий белый | \u001b[37;1m |
Сброс цвета | \u001b[0m |
Всего в ANSI 256 цветов. Они составляются так: \u001b[38;5;КОДm
, где вместо КОД
— число от 0 до 255:
Работает так же, только коды другие:
Цвет | Код |
---|---|
Чёрный | \u001b[40m |
Красный | \u001b[41m |
Зелёный | \u001b[42m |
Жёлтый | \u001b[43m |
Синий | \u001b[44m |
Пурпурный | \u001b[45m |
Голубой | \u001b[46m |
Белый | \u001b[47m |
Сброс цвета такой же: \u001b[0m
.
Либо можно собрать один из 256 доступных по схеме \u001b[48;5;КОДm
, где вместо КОД
— число от 0 до 255:
Некоторые виды ANSI-кодов могут двигать курсор внутри терминала:
Направление | Код |
---|---|
Вверх | \u001b[ШАГA |
Вниз | \u001b[ШАГB |
Вправо | \u001b[ШАГC |
Влево | \u001b[ШАГD |
Вместо ШАГ
нужно подставить нужное число, например, \u001b[10A
— переведёт курсор на 10 строк вверх. Вот так это выглядит:
Мы вывели код, который поднимает курсор терминала на 10 строчек вверх, а потом напечатался текст. Как и ожидалось, он оказался выше, чем сама команда, которую мы вводили.
Перемещение курсора по экрану позволяет выводить один текст поверх другого, но это не всегда просто сделать:
print('Первая надпись на экране')
print('Это вторая надпись на экране')
print('\u001b[2A')
print('Третья надпись')
В результате получим абракадабру. Одна надпись наложилась поверх другой, но не затерла её полностью:
Первая надпись на экране
Третья надписьпись на экране
Эту проблему можно решить добавлением пробелов к коротким строкам, чтобы все получились одной ширины:
print('Первая надпись на экране')
print('Это вторая надпись на экране')
print('\u001b[2A')
print('Третья надпись ')
Это работает, но очень неудобно: сложно менять текст сообщений и легко ошибиться с количеством пробелов. Если вы можете себе позволить очистить экран полностью, то воспользуйтесь спец.символом для очистки экрана '\033[2J'
:
print('Это первая надпись на экране')
print('\033[2J') # очистит экран
print('Вторая надпись')
Теперь всё будет работать как надо:
Вторая надпись