Сообщаем, указывает ли дескриптор файла на терминальное устройство
Программа может определить, связан ли файловый дескриптор с 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.