Mam problem z debugowaniem programu segfault, ponieważ potrzebuję wyjścia bezpośrednio przed segfault, ale tracę go, jeśli przesyłam dane wyjściowe do pliku. Zgodnie z tą odpowiedzią: /unix//a/17339/22615 dzieje się tak , ponieważ bufor wyjściowy programu jest opróżniany natychmiast po podłączeniu do terminala, ale tylko w niektórych punktach po podłączeniu do potoku. Kilka pytań tutaj:
W jaki sposób program określa, do czego podłączony jest jego stdout?
W jaki sposób polecenie „skrypt” wywołuje takie samo zachowanie, jak podczas zapisywania programu w terminalu?
Czy można to osiągnąć bez polecenia skryptu?
Odpowiedzi:
Mówienie, jeśli deskryptor pliku wskazuje urządzenie końcowe
Program może stwierdzić, czy deskryptor pliku jest powiązany z urządzeniem tty, używając
isatty()
standardowej funkcji C (która ogólnie poniżej wykonuje niewinneioctl()
wywołanie systemowe specyficzne dla tty , które zwróci błąd z błędem, gdy fd nie wskaże urządzenia tty) .Narzędzie
[
/test
może to zrobić za pomocą swojego-t
operatora.Śledzenie wywołań funkcji libc w systemie GNU / Linux:
Śledzenie wywołań systemowych:
Mówienie, jeśli wskazuje na rurę
Aby ustalić, czy fd jest powiązany z potokiem / fifo, można użyć
fstat()
wywołania systemowego , które zwraca strukturę, którejst_mode
pole zawiera typ i uprawnienia pliku otwartego na tym fd. W tym polu można użyćS_ISFIFO()
standardowego makra C ,st_mode
aby ustalić, czy fd jest potokiem / fifo.Nie ma standardowego narzędzia, które mogłoby to zrobić
fstat()
, ale istnieje kilka niekompatybilnych implementacjistat
polecenia, które może to zrobić.zsh
jeststat
wbudowany wstat -sf "$fd" +mode
które powraca do trybu jako ciąg znaków, który pierwszy znak oznacza rodzaj (p
na rurę). GNUstat
może zrobić to samostat -c %A - <&"$fd"
, ale musi równieżstat -c %F - <&"$fd"
zgłosić ten typ sam. Z BSDstat
:stat -f %St <&"$fd"
lubstat -f %HT <&"$fd"
.Mówienie, jeśli to możliwe
Aplikacje na ogół nie dbają o to, czy stdout jest fajką. Mogą się martwić, że jest to widoczne (choć ogólnie nie decyduje się na buforowanie, czy nie).
Aby sprawdzić, czy można zobaczyć fd (potoki, gniazda, urządzenia tty nie są widoczne, zwykłe pliki i większość urządzeń blokowych ogólnie jest), można spróbować wykonać względne
lseek()
wywołanie systemowe z przesunięciem 0 (tak nieszkodliwe).dd
jest standardowym narzędziem, które jest interfejsem,lseek()
ale nie można go użyć do tego testu, ponieważ implementacje nie zadzwoniłybylseek()
wcale, jeśli poprosiłbyś o przesunięcie 0.Te
zsh
iksh93
powłok posiada wbudowane poszukuje operatorów choć:Wyłączanie buforowania
script
Rozkaz wykorzystuje parę Pseudoterminal uchwycić wyjście programu, tak standardowe wyjście programu (i standardowe wejście i stderr) będzie urządzenie pseudoterminal.Kiedy standardowe wyjście znajduje się na urządzeniu końcowym, nadal istnieje ogólne buforowanie, ale jest ono oparte na linii.
printf
/puts
i co nie napisze nic, dopóki nie zostanie wypisany znak nowej linii. W przypadku innych typów plików buforowanie odbywa się według bloków (o wielkości kilku kilogramów).Istnieje kilka opcji, aby wyłączyć buforowanie, które zostały omówione w szeregu pytań i jak tutaj (szukaj unbuffer lub stdbuf , Nie można przekierować dane wyjściowe cięcie daje kilka podejść) albo za pomocą pseudo-terminal, jak można to zrobić przez
socat
/script
/expect
/unbuffer
(expect
skrypt) /zsh
”zpty
lub przez wstrzyknięcie kodu do pliku wykonywalnego, aby wyłączyć buforowanie, tak jak zrobiono to w GNU lub FreeBSDstdbuf
.źródło
/proc
katalogu i dla każdego/proc/<integer>/
katalogu wyszukiwanie/proc/<integer>/fd/
i znajdowanie deskryptora pliku, który ma ten sam numer i-węzła wpipefs
serverfault.com/q/48330/363611 Jest to jednak przydatne tylko w skryptach, gdy nie można użyć opisanych wywołań systemowych w odpowiedzi Stephane'a, i jest to bardziej obejście niż właściwe rozwiązanie IMHOlseek
odniesie sukces na terminalach i innych urządzeniach znakowych, i po prostu ponownie ustawi licznik, który jest zwiększany przy każdym udanym read (). Nie wiem, czy to czyni je „widocznymi”.