Скажіть, чи дескриптор файлу вказує на термінальний пристрій
Програма може визначити, чи пов'язаний дескриптор файлу з пристроєм 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 з pipe / fifo, можна скористатися fstat()
системним викликом , який повертає структуру, st_mode
поле якої містить тип і дозволи файлу, відкритого на цьому fd. S_ISFIFO()
Стандарт Сі макро може бути використано на цій st_mode
області , щоб визначити , є чи ФД труба / FIFO.
Немає стандартної утиліти, яка може виконати fstat()
, але є кілька несумісних реалізацій stat
команди, яка може це зробити. zsh
's 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
' zpty
або шляхом введення коду у виконуваний файл, щоб відключити буферизацію, як це зроблено GNU або FreeBSD stdbuf
.