Как программа узнает, подключен ли стандартный вывод к терминалу или каналу?

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

Моя проблема заключалась в том, что я думал, что имя сеанса было именем сокета, но это две разные вещи. Я назвал сеанс «0» для 0-го окна, но на самом деле РОЗЕТКА называется «по умолчанию», несмотря на указанное мной имя сеанса.

Чтобы получить список сокетов tmux, запустите: lsof -U | grep "^ tmux"
Я обнаружил, что из этого ответа:
https://stackoverflow.com/questions/11333291/is-it-possible-to-find-tmux-sockets-currently-in-use

Выше было полезно увидеть фактические имена сокетов.

Это то, что вы указываете в первом приглашении. Я поставил «0», что было названием моей сессии, но это не сработало. «default» - это то, что там нужно, несмотря на то, что я назвал сессию.

Затем, во втором запросе, я ввел (окно index-0, панель index-1):
: 0,1

Вуаля! Ну наконец то! Это сработало. Замечательно, теперь редактирование одновременно !

12
27.04.2019, 05:37
1 ответ

Указание, указывает ли файловый дескриптор на терминальное устройство

Программа может определить, связан ли файловый дескриптор с tty-устройством, используяisatty()стандартную функцию C (, которая, как правило, выполняет безобидный -специфический ioctl()системный вызов tty, возвращающий сообщение ошибка, когда fd не указывает на устройство tty ).

Утилита [/ testможет сделать это с помощью своего оператора -t.

if [ -t 1 ]; then
  echo stdout is open to a terminal
fi

Отслеживание вызовов функций libc в системе GNU/Linux:

$ ltrace [ -t 1 ] | cat
[...]
isatty(1)                                      = 0
[...]

Отслеживание системных вызовов:

$ strace [ -t 1 ] | cat
[...]
ioctl(1, TCGETS, 0x7fffd9fb3010)        = -1 ENOTTY (Inappropriate ioctl for device)
[...]

Говорит, указывает ли он на трубу

Чтобы определить, связан ли fd с каналом/fifo, можно использовать системный вызовfstat(), который возвращает структуру, поле st_modeкоторой содержит тип и разрешения файла, открытого на этом fd.. Стандартный макросS_ISFIFO()C можно использовать в этом поле st_mode, чтобы определить, является ли fd каналом/fifo.

Не существует стандартной утилиты, которая может выполнять fstat(), но есть несколько несовместимых реализаций команды stat, которые могут это делать. zshвстроенная функция statс stat -sf "$fd" +mode, которая возвращает режим в виде строкового представления, первый символ которого представляет тип(pдля канала ). GNU statможет сделать то же самое с stat -c %A - <&"$fd", но также имеет stat -c %F - <&"$fd"для сообщения только типа . С BSDstat:stat -f %St <&"$fd"или stat -f %HT <&"$fd".

Сообщить, доступен ли поиск

Приложения, как правило, не заботятся о том, является ли stdout каналом. Их может заботить возможность поиска (, хотя обычно они не решают, следует ли буферизовать или нет ).

Чтобы проверить, является ли fd доступным для поиска (каналы, сокеты, устройства tty недоступны для поиска, обычные файлы и большинство блочных устройств обычно ), можно попытаться выполнить относительныйlseek()системный вызов с смещение 0 (так безобидно ). dd— это стандартная утилита, представляющая собой интерфейс к lseek(), но ее нельзя использовать для этого теста.поскольку реализации вообще не будут вызывать lseek(), если вы запросите смещение 0.

Оболочки zshи ksh93имеют встроенные операторы поиска, хотя:

$ strace -e lseek ksh -c ': 1>#((CUR))' | cat
lseek(1, 0, SEEK_CUR)                   = -1 ESPIPE (Illegal seek)
ksh: 1: not seekable
$ strace -e lseek zsh -c 'zmodload zsh/system; sysseek -w current -u 1 0 || syserror'
lseek(1, 0, SEEK_CUR)                   = -1 ESPIPE (Illegal seek)
Illegal seek

Отключение буферизации

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

Когда стандартный вывод направляется на терминальное устройство, как правило, сохраняется некоторая буферизация, но она построчная. printf/ putsи co не будут ничего писать до тех пор, пока не будет выведен символ новой строки. Для других типов файлов буферизация осуществляется блоками (по несколько килобайт ).

Существует несколько вариантов отключения буферизации, которые обсуждаются в нескольких вопросах и ответах здесь (поиск unbuffer или stdbuf , Не удается перенаправить вывод дает несколько подходов )либо с использованием псевдотерминала -, как это можно сделать с помощью socat/ script/ expect/unbuffer(скрипта expect)/ zshzptyили внедрив код в исполняемый файл для отключения буферизации, как это делается в GNU или FreeBSD stdbuf.

30
27.01.2020, 19:55

Теги

Похожие вопросы