Как мне проверить, работает ли моя оболочка в терминале?

Вопрос или проблема

Я хочу выполнить какое-то действие только в том случае, если моя оболочка “подключена” к терминалу, т.е. только если мой стандартный ввод поступает от ввода терминала, а мой стандартный вывод (и стандартная ошибка? возможно, это не важно) выводится/отображается на терминале.

Как я могу это сделать, не полагаясь на особенности GNU/Linux (такие как /proc/self) напрямую?

isatty – это функция для проверки этого, а -t флаг команды test делает это доступным из оболочки:

-t номер_файлового_дескриптора

Истина, если номер файлового дескриптора номер_файлового_дескриптора открыт и связан с терминалом. Ложь, если номер_файлового_дескриптора не является допустимым номером файлового дескриптора, или если номер файлового дескриптора номер_файлового_дескриптора не открыт, или если он открыт, но не связан с терминалом.

Вы можете проверить, является ли FD 0 (стандартный ввод) TTY с помощью:

test -t 0

Вы можете сделать то же самое для FD 1 и 2, чтобы проверить потоки вывода и ошибок, или для всех сразу:

test -t 0 -a -t 1 -a -t 2

Команда возвращает 0 (успешно), если дескрипторы подключены к терминалу, и ложь в противном случае.

test также доступен как команда [ для “квадратного теста”:

 if [ -t 0 ] ; then ...

это идиоматический способ написания этого условия.

Просто дополнительное замечание к отличным ответам, которые уже были даны. Обратите внимание, что [ -t 0 ] проверяет, что файловый дескриптор 0 открыт на файле, который является устройством с дисциплиной линии tty (обычно это делается путем проверки, что безвредный ioctl() termio(s) завершается успешно).

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

Устройства tty и pty также могут использоваться для передачи данных или в качестве механизма межпроцессного взаимодействия.

Например, можно сделать:

(stty raw -echo; myscript) < /dev/ttyS0

Чтобы передать то, что получено через RS232, в myscript.

echo test | ssh -tt host myscript

это обеспечит stdin myscript в виде устройства pty (с sshd на другом конце, и в конечном итоге (через ssh-соединение) не терминал, а труба, заполняемая echo)

Чтобы дополнительно проверить, что на другом конце этой линии RS232 или pty есть терминал, вы также можете проверить, что переменная $TERM установлена и непустая ([ -n "$TERM" ]) и отправить последовательность escape Отчет о состоянии устройства через этот fd и проверить, получаете ли вы ответ (в дополнение к [ -t 0 ] и [ -n "$TERM" ]).

printf >&0 '\e[5n'

На это большинство терминалов ответят \e[0n.

Теперь у этого есть несколько проблем, поэтому я не рекомендую делать это, кроме случаев, когда вы хотите проверить это, потому что хотите запустить визуальное TUI приложение (в этом случае вам лучше использовать такие библиотеки, как ncurses, вместо DSR, вам лучше отправить последовательность escape для идентификации устройства, чтобы более точно запросить тип терминала, чем через $TERM):

  • К счастью, в большинстве случаев, когда stdin не является терминалом, он будет открыт в режиме только для чтения, что приведет к сбою printf, но в случае, если stdin — это tty-устройство, открытое в режиме чтения и записи, это приведет к тому, что эта последовательность будет отправлена на другой конец. Например, в нашем примере ssh выше, это на самом деле отправит последовательность на терминал (но ответ не будет приходить на stdin)
  • Трудно надежно и переносимо читать ответ. Вам придется временно изменить дисциплину линии tty и читать по одному байту за раз. Вам также нужно будет задать тайм-аут, по истечении которого, если ответ не будет получен, вы откажетесь и решите, что терминала нет. Если вы хотите учитывать людей, подключающихся через спутниковые соединения, это означает долгий тайм-аут.
  • Чтение из терминала в фоновом режиме приведет к приостановке вашего скрипта с сигналом SIGTTIN.

Простое решение состоит в использовании команды tty -s.
Эта команда возвращает либо 0, либо 1.

if tty -s; then
    echo "Я на TTY"
else
    echo "Я НЕ на TTY"
fi

p.s.: У меня нет доступа к другим страницам man UNIX. Я могу гарантировать, что это работает в Linux.

Ответ или решение

Для выполнения действий только в том случае, если ваша оболочка ("shell") связана с терминалом, существует несколько подходов, которые можно использовать. Если вы хотите убедиться, что стандартный ввод (stdin) приходит от терминала, а стандартный вывод (stdout) и стандартный вывод ошибок (stderr) направлены на терминал, вам поможет следующий анализ.

Проверка терминала с помощью test и isatty

Наиболее распространенными способами проверки, связаны ли файловые дескрипторы с терминалом, являются использование команд test или встроенного оператора [. Чтобы проверить стандартный ввод, стандартный вывод и вывод ошибок, вы можете выполнить следующие команды:

  1. Проверка стандартного ввода (stdin):

    test -t 0
  2. Проверка стандартного вывода (stdout):

    test -t 1
  3. Проверка стандартного вывода ошибок (stderr):

    test -t 2

Если вы хотите проверить все три дескриптора одновременно, вы можете использовать:

test -t 0 -a -t 1 -a -t 2

Эти команды вернут 0 (успех), если указанные дескрипторы действительно связаны с терминалом, и 1 (неуспех) в противном случае.

Альтернативный способ: Использование tty

Еще одним простым и эффективным подходом является команда tty -s, которая возвращает 0, если стандартный ввод приходит от терминала, и 1 в противном случае. Пример использования:

if tty -s; then
    echo "Я на TTY"
else
    echo "Я НЕ на TTY"
fi

Эта команда является удобным способом, если вам нужно просто узнать, работает ли ваш скрипт в терминале.

Дополнительные проверки

Следует отметить, что использование команды test -t проверяет, открыт ли файловый дескриптор 0 в режиме устройства, обеспечивающего взаимодействие с терминалом (tty). Однако это не гарантирует, что на другом конце действительно находится пользователь, работающий с клавиатурой. Это может быть полезно в случаях, когда ваш ввод/вывод связан с tty или pty устройствами, которые могут также использоваться для межпроцессного взаимодействия.

Также следует учитывать, что в некоторых ситуациях значения переменной окружения $TERM могут помочь определить, связано ли ваше приложение с терминалом (например, при работе с TUI-приложениями).

Приведенные в этой статье методы являются общими и должны работать на большинстве UNIX-подобных систем и в оболочках, включая Bash. Эти подходы не зависят от специфичных для GNU/Linux реализаций, что делает их полезными для широкой аудитории разработчиков, работающих в различных окружениях.

Заключение

Подводя итог, можно сказать, что для проверки того, запущена ли ваша оболочка в терминале, вы можете использовать команду test, оператор [, либо команду tty. Эти методы помогут вам корректно определить, когда ваша программа взаимодействует с терминалом, что является важным для корректной работы скриптов и приложений.

Оцените материал
Добавить комментарий

Капча загружается...