Jak wykryć ze skryptu powłoki, czy standardowe wyjście jest wysyłane do terminala lub czy jest przesyłane potokowo do innego procesu?
Przykład: chciałbym dodać kody ucieczki, aby pokolorować dane wyjściowe, ale tylko wtedy, gdy są uruchamiane interaktywnie, ale nie po potoku, podobnie jak to ls --color
robi.
Odpowiedzi:
W czystej powłoce POSIX
zwraca „terminal”, ponieważ dane wyjściowe są wysyłane do terminala, natomiast
zwraca „nie terminal”, ponieważ dane wyjściowe w nawiasach są przesyłane potokowo
cat
.-t
Flaga jest opisany na stronach człowieka jako... gdzie
fd
może być jedno ze zwykłych przypisań deskryptorów plików:źródło
-t
flaga jest określona w POSIX, a zatem powinna działać z każdą powłoką kompatybilną z POSIX (to znaczy nie jest rozszerzeniem bash). pubs.opengroup.org/onlinepubs/009695399/utilities/test.htmlfish
odpowiedzi powłoki. Używanietest
jest fajne, ale nie mogę wypróbować nawiasowego przykładu, ponieważ nie jest on obsługiwany. Próbowałem zawinąć go w analogiczny sposóbbegin; ...; end
, ale wydawało się, że to nie działa, i po prostu ponownie uruchomiłem pozytywny blok kodu. Pomyślałem, że będę musiał użyć,status
ale to nie wydaje się sprawdzać pod kątem instalacji. Chyba zasadniczo chcę sprawdzić, czy STDOUT poprzedniego polecenia / skryptu nie jest ustawiony na terminalu, dzięki tym wyjaśniającym odpowiedziom.Nie ma niezawodnego sposobu ustalenia, czy STDIN, STDOUT lub STDERR są przesyłane do / ze skryptu, głównie z powodu programów takich jak
ssh
.Rzeczy, które „normalnie” działają
Na przykład następujące rozwiązanie bash działa poprawnie w interaktywnej powłoce:
Ale nie zawsze działają
Jednak podczas wykonywania tego polecenia jako polecenia innego niż TTY
ssh
, strumienie STD zawsze wyglądają, jakby były przesyłane potokowo. Aby to zademonstrować, używając STDIN, ponieważ jest to łatwiejsze:Dlaczego jest to ważne
Jest to dość duża sprawa, ponieważ sugeruje, że skrypt bash nie ma sposobu, aby stwierdzić, czy
ssh
polecenie inne niż tty jest przesyłane potokowo, czy nie. Zauważ, że to niefortunne zachowanie zostało wprowadzone, gdy najnowsze wersjessh
zaczęły używać potoków dla STDIO innych niż TTY. Wcześniejsze wersje używały gniazd, które MOGĄ być odróżniane od wewnątrz bash przy użyciu[[ -S ]]
.Kiedy to ma znaczenie
To ograniczenie zwykle powoduje problemy, gdy chcesz napisać skrypt bash, który ma zachowanie podobne do skompilowanego narzędzia, takiego jak
cat
. Na przykładcat
umożliwia następujące elastyczne zachowanie podczas obsługi różnych źródeł wejściowych jednocześnie i jest wystarczająco inteligentny, aby określić, czy odbiera dane wejściowe w potoku niezależnie od tego, czyssh
używany jest tryb TTY czy wymuszony :Możesz zrobić coś takiego tylko wtedy, gdy możesz wiarygodnie ustalić, czy rury są zaangażowane, czy nie. W przeciwnym razie wykonanie polecenia, które czyta STDIN, gdy żadne wejście nie jest dostępne ani z potoków, ani z przekierowania spowoduje zawieszenie skryptu i oczekiwanie na wejście STDIN.
Inne rzeczy, które nie działają
Próbując rozwiązać ten problem, przyjrzałem się kilku technikom, które nie rozwiązały problemu, w tym takim, które obejmują:
stat
deskryptorów plików / dev / stdin[[ "${-}" =~ 'i' ]]
tty
itty -s
ssh
statusu przez[[ "$(ps -o comm= -p $PPID)" =~ 'sshd' ]]
Pamiętaj, że jeśli używasz systemu operacyjnego obsługującego
/proc
wirtualny system plików, możesz mieć szczęście podążając za dowiązaniami symbolicznymi do STDIO, aby ustalić, czy potok jest używany, czy nie. Jednak/proc
nie jest wieloplatformowym rozwiązaniem zgodnym z POSIX.Jestem niezwykle interesujący w rozwiązaniu tego problemu, więc proszę dać mi znać, jeśli pomyślisz o jakiejkolwiek innej technice, która może działać, najlepiej rozwiązaniach opartych na POSIX, które działają zarówno na Linuksie, jak i BSD.
źródło
stat
wywołania na / dev / stdin. A dlaczego działa"${-}"
czytty -s
nie? Zajrzałem także do kodu źródłowego,cat
ale nie zauważyłem, która część robi magię, której nie można zrobić w powłoce POSIX. Mógłbyś to rozwinąć?Polecenie
test
(wbudowanebash
) ma opcję sprawdzenia, czy deskryptor pliku jest tty.Zobacz „
man test
” lub „man bash
” i wyszukaj „-t
”źródło
help test
(ihelp help
więcej), a następnieinfo bash
więcej szczegółowych informacji. Te polecenia są świetne, jeśli kiedykolwiek skończysz pisać skrypty offline lub po prostu chcesz uzyskać szersze zrozumienie.Nie wspominasz o używanej powłoce, ale w Bash możesz to zrobić:
źródło
W Solarisie sugestia Dejay Claytona działa głównie. -P nie reaguje zgodnie z życzeniem.
bash_redir_test.sh wygląda następująco:
W systemie Linux działa świetnie:
W systemie Solaris:
źródło
Poniższy kod (przetestowany tylko w Linuksie bash 4.4) nie powinien być uważany za przenośny ani zalecany , ale ze względu na kompletność jest to:
Nie wiem dlaczego, ale wydaje się, że deskryptor pliku „3” jest w jakiś sposób tworzony, gdy funkcja bash ma potok STDIN.
Mam nadzieję, że to pomoże,
źródło