Сообщаем, указывает ли дескриптор файла на терминальное устройство
Программа может определить, связан ли файловый дескриптор с tty-устройством, используя isatty()
стандартную функцию C (которая обычно выполняет безобидный tty-специфичный ioctl()
системный вызов, который будет возвращаться с ошибкой, когда 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 с pipe / fifo, можно использовать fstat()
системный вызов , который возвращает структуру, st_mode
поле которой содержит тип и разрешения файла, открытого на этом fd. S_ISFIFO()
Стандарт Си макро может быть использовано на этой st_mode
области , чтобы определить , является ли ФД труба / FIFO.
Нет стандартной утилиты, которая может это сделать fstat()
, но есть несколько несовместимых реализаций stat
команды, которая может это сделать. zsh
«ы stat
встроенный в stat -sf "$fd" +mode
который возвращает режим в виде строки представления, первый символ представляет тип ( p
для трубы). GNU stat
может сделать то же самое stat -c %A - <&"$fd"
, но также должен stat -c %F - <&"$fd"
сообщать только о типе . С BSD stat
: 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
использует псевдо-терминальную пару для захвата вывода программы, поэтому стандартный вывод программы (и stdin и stderr) будет псевдо-терминальным устройством.
Когда stdout подключен к терминальному устройству, обычно все еще существует некоторая буферизация, но она основана на линии. printf
/ puts
и co не будет ничего писать, пока не будет выведен символ новой строки. Для других типов файлов буферизация осуществляется блоками (по несколько килобайт).
Есть несколько вариантов , чтобы отключить буферизацию , которые обсуждаются в ряде Q & As здесь (поиск unbuffer или stdbuf , Может не перенаправление вывод покроя дает несколько подходов) , либо с помощью псевдо-терминала , как можно сделать socat
/ script
/ expect
/ unbuffer
( expect
скрипт) / zsh
«s zpty
или путем введения кода в исполняемый файл , чтобы отключить буферизацию как это делается в GNU или файле FreeBSD stdbuf
.