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

22

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

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

einpoklum - восстановить Монику
источник
Похожие: unix.stackexchange.com/q/22162/117549
Джефф Шаллер

Ответы:

33

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

-t file_descriptor

Истинно, если номер дескриптора файла file_descriptor открыт и связан с терминалом. False, если file_descriptor не является допустимым номером дескриптора файла, или если номер дескриптора файла file_descriptor не открыт, или если он открыт, но не связан с терминалом.

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

test -t 0

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

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

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

testтакже доступна в качестве [команды для «брекет-теста»:

 if [ -t 0 ] ; then ...

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

Майкл Гомер
источник
8

Я представляю, что это дубликат, но я не могу его найти. использование

[ -t 0 ]

а также

[ -t 1 ]

соответственно проверить, подключены ли стандартный вход и выход к терминалу. man testесть детали.

Стивен Китт
источник
7

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

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

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

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

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

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

echo test | ssh -tt host myscript

будет иметь myscript«ы стандартного ввода будучи в PTy устройство (с sshdна другом конце, и в конце концов (через соединение SSH) не терминал, а трубку , питаемую echo)

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

printf >&0 '\e[5n'

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

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

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