Dire se un descrittore di file punta a un dispositivo terminale
Un programma può dire se un descrittore di file è associato a un dispositivo tty usando la isatty()
funzione C standard (che generalmente sotto fa una ioctl()
chiamata di sistema specifica tty innocua che ritornerebbe con un errore quando il fd non punta a un dispositivo tty) .
L' utilità [
/ test
può farlo con il suo -t
operatore.
if [ -t 1 ]; then
echo stdout is open to a terminal
fi
Tracciare le chiamate della funzione libc su un sistema GNU / Linux:
$ ltrace [ -t 1 ] | cat
[...]
isatty(1) = 0
[...]
Traccia delle chiamate di sistema:
$ strace [ -t 1 ] | cat
[...]
ioctl(1, TCGETS, 0x7fffd9fb3010) = -1 ENOTTY (Inappropriate ioctl for device)
[...]
Dire se indica una pipa
Per determinare se un fd è associato a una pipe / fifo, è possibile utilizzare la fstat()
chiamata di sistema , che restituisce una struttura il cui st_mode
campo contiene il tipo e le autorizzazioni del file aperto su quel fd. La S_ISFIFO()
macro C standard può essere utilizzata su quel st_mode
campo per determinare se fd è una pipe / fifo.
Non esiste un'utilità standard in grado di eseguire una fstat()
, ma ci sono diverse implementazioni incompatibili di un stat
comando che può farlo. zsh
È stat
incorporato con il stat -sf "$fd" +mode
quale restituisce la modalità come rappresentazione di stringa il cui primo carattere rappresenta il tipo ( p
per pipe). GNU stat
può fare lo stesso con stat -c %A - <&"$fd"
, ma deve anche stat -c %F - <&"$fd"
riportare il tipo da solo. Con BSD stat
: stat -f %St <&"$fd"
o stat -f %HT <&"$fd"
.
Dire se è cercabile
In genere, alle applicazioni non importa se stdout è una pipe. A loro potrebbe interessare che sia cercabile (anche se generalmente non decidere se tamponare o meno).
Per verificare se un fd è ricercabile (pipe, socket, dispositivi tty non sono ricercabili, file regolari e la maggior parte dei dispositivi a blocchi lo sono in genere), si può tentare una lseek()
chiamata di sistema relativa con un offset di 0 (così innocuo). dd
è un'utilità standard che è un'interfaccia per lseek()
ma non può essere utilizzata per quel test, poiché le implementazioni non chiamerebbero lseek()
affatto se si chiedesse un offset di 0.
Le shell zsh
e ksh93
hanno incorporato gli operatori alla ricerca di:
$ 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
Disabilitare il buffering
Il script
comando usa una coppia pseudo-terminale per catturare l'output di un programma, quindi lo stdout del programma (e stdin e stderr) sarà un dispositivo pseudo-terminale.
Quando lo stdout è su un dispositivo terminale, generalmente c'è ancora un po 'di buffering, ma è basato sulla linea. printf
/ puts
e co non scriveranno nulla fino a quando non verrà emesso un carattere di nuova riga. Per altri tipi di file, il buffering è per blocchi (di qualche chilo byte).
Esistono diverse opzioni per disabilitare il buffering che sono discusse in un certo numero di domande e risposte qui (cercare unbuffer o stdbuf , Impossibile reindirizzare l'output di taglio fornisce alcuni approcci) utilizzando uno pseudo-terminale come può essere fatto da socat
/ script
/ expect
/ unbuffer
(uno expect
script) / zsh
' zpty
o iniettando codice nell'eseguibile per disabilitare il buffering come fatto da GNU o FreeBSD stdbuf
.