Jak sprawdzić, czy moja powłoka działa w terminalu?

22

Chcę wykonać jakąś akcję tylko wtedy, gdy moja powłoka jest „podłączona” do terminala, tj. Tylko wtedy, gdy moje standardowe wejście pochodzi z wejścia terminala, a moje standardowe wyjście (i standardowy błąd? Może to nie ma znaczenia) zostanie wydrukowane / echo terminal.

Jak mogę to zrobić bez bezpośredniego polegania na specyfikach GNU / Linux /proc/self?

einpoklum - przywróć Monikę
źródło
Podobne: unix.stackexchange.com/q/22162/117549
Jeff Schaller

Odpowiedzi:

33

isattyjest funkcją sprawdzającą to , a -tflaga testpolecenia czyni to dostępnym ze skryptu powłoki:

-t deskryptor pliku

To prawda, jeśli liczba deskryptor file_descriptor jest otwarty i jest związane z terminalem. False, jeśli file_descriptor nie jest prawidłowy numer deskryptor pliku, lub jeśli numer deskryptor file_descriptor nie jest otwarta lub jeśli jest otwarta, ale nie jest związane z terminalem.

Możesz sprawdzić, czy FD 0 (standardowe wejście) jest TTY za pomocą:

test -t 0

Możesz zrobić to samo dla FD 1 i 2, aby sprawdzić strumienie wyjściowe i strumienie błędów lub wszystkie:

test -t 0 -a -t 1 -a -t 2

Polecenie zwraca 0 (sukces), jeśli deskryptory są podłączone do terminala, w przeciwnym razie ma wartość false.

testjest również dostępny jako [polecenie „testu wspornika”:

 if [ -t 0 ] ; then ...

jest idiomatycznym sposobem na napisanie tego warunkowego.

Michael Homer
źródło
8

Wyobrażam sobie, że to duplikat, ale nie mogę go znaleźć. Posługiwać się

[ -t 0 ]

i

[ -t 1 ]

odpowiednio sprawdzić, czy standardowe wejście i wyjście są podłączone do terminala. man testma szczegóły.

Stephen Kitt
źródło
7

Tylko dodatkowa uwaga na podstawie już udzielonych dobrych odpowiedzi. Zauważ, że [ -t 0 ]testy, w których deskryptor pliku 0 jest otwarty, to plik, który jest plikiem urządzenia z dyscypliną linii tty (zazwyczaj odbywa się to poprzez sprawdzenie, czy nieszkodliwe termio (s) ioctl () się powiedzie).

Nie musi to również oznaczać, że na drugim końcu znajduje się terminal lub emulator terminala (z prawdziwym użytkownikiem, który pisze na klawiaturze) (choć w ogromnej większości przypadków i prawdopodobnie większości z nich zależy), to wystarczająco przybliżenie).

Urządzenia tty i pty mogą być również wykorzystywane do przesyłania danych lub jako mechanizm komunikacji międzyprocesowej.

Na przykład można zrobić:

(stty raw -echo; myscript) < /dev/ttyS0

Karmić to, co otrzymano przez RS232 do myscript.

echo test | ssh -tt host myscript

miałby myscriptstdin będący urządzeniem pty (z sshddrugim końcem, a ostatecznie (przez połączenie ssh) nie terminalem, ale zasilaną przez niego rurą echo)

Aby dodatkowo sprawdzić, czy na drugim końcu linii RS232 lub pty znajduje się terminal, możesz również sprawdzić, czy $TERMzmienna jest ustawiona i niepusta ( [ -n "$TERM" ]), i wysłać sekwencję ucieczki raportu o stanie urządzenia za pomocą tego fd i sprawdzić, czy otrzymałeś odpowiedź (oprócz [ -t 0 ]i [ -n "$TERM" ]).

printf >&0 '\e[5n'

Odpowiada na to \e[0nprzez większość terminali.

Teraz jest z tym kilka problemów, więc nie zalecałbym tego, z wyjątkiem sytuacji, w której chcesz to sprawdzić, ponieważ chcesz uruchomić wizualną aplikację TUI (w takim przypadku lepiej byłoby użyć bibliotek takich jak ncurses, i zamiast DSR, wolisz wysłać sekwencję ucieczki identyfikującą urządzenie, aby zapytać o typ terminala bardziej precyzyjnie niż za pośrednictwem $TERM):

  • Na szczęście w większości przypadków, gdy stdin nie jest terminalem, zostanie otwarty w trybie tylko do odczytu, co spowodowałoby printfawarię, ale w przypadku, gdy stdin jest urządzeniem tty otwartym w trybie odczytu i zapisu, będzie to miało efekt uboczny wysłania tej sekwencji na drugi koniec. Na przykład w naszym powyższym przykładzie ssh, który faktycznie wyśle ​​sekwencję do terminala (ale odpowiedź nie pojawi się na standardowym wejściu)
  • Trudno jest rzetelnie i przenośnie odczytać odpowiedź. Musisz tymczasowo zmienić dyscyplinę linii tty i czytać jeden bajt na raz. Musisz także określić limit czasu, w którym jeśli odpowiedź nie zostanie wyświetlona, ​​poddasz się i zdecydujesz, że nie ma terminala. Jeśli chcesz wziąć pod uwagę osoby wybierające połączenie satelitarne, oznacza to długi czas oczekiwania.
  • Czytanie z terminala, gdy jest w tle, spowoduje zawieszenie skryptu sygnałem SIGTTIN.
Stéphane Chazelas
źródło