Przywykłem do tego:
someprogram >output.file
Robię to za każdym razem, gdy chcę zapisać dane wyjściowe generowane przez program do pliku. Zdaję sobie również sprawę z dwóch wariantów przekierowania IO :
someprogram 2>output.of.stderr.file
(dla stderr)someprogram &>output.stderr.and.stdout.file
(dla obu stdout + stderr łącznie)
Dzisiaj natknąłem się na sytuację, która nie wydawała mi się możliwa. Używam następującego polecenia xinput test 10
i zgodnie z oczekiwaniami mam następujące dane wyjściowe:
użytkownik @ nazwa hosta: ~ $ xinput test 10 naciśnij klawisz 30 wydanie klucza 30 naciśnij klawisz 40 wydanie klucza 40 naciśnij klawisz 32 wydanie klucza 32 naciśnij klawisz 65 wydanie klucza 65 naciśnij klawisz 61 wydanie klucza 61 naciśnij klawisz 31 ^ C użytkownik @ nazwa hosta: ~ $
Spodziewałem się, że dane wyjściowe można jak zwykle zapisać w pliku takim jak using xinput test 10 > output.file
. Ale kiedy sprzeczne z moimi oczekiwaniami plik output.file pozostaje pusty. Dotyczy to również xinput test 10 &> output.file
upewnienia się, że nie umknie mi coś na stdout lub stderr.
Jestem naprawdę zdezorientowany i dlatego pytam tutaj, czy xinput
program może mieć sposób na uniknięcie przekierowania danych wyjściowych?
aktualizacja
Spojrzałem na źródło. Wygląda na to, że dane wyjściowe są generowane przez ten kod (patrz fragment kodu poniżej). Wydaje mi się, że wynik byłby generowany przez zwykły printf
// w pliku test.c static void print_events (Wyświetl * dpy) { Wydarzenie XEvent; while (1) { XNextEvent (dpy & Event); // [... niektóre inne typy zdarzeń są tutaj pomijane ...] if ((Event.type == key_press_type) || (Event.type == key_release_type)) { pętla int; XDeviceKeyEvent * key = (XDeviceKeyEvent *) & Event; printf („klucz% s% d”, (Event.type == key_release_type)? ”release”: „naciśnij”, key-> kod dostępu); for (loop = 0; loopaxes_count; loop ++) { printf („a [% d] =% d”, key-> first_axis + loop, key-> axis_data [loop]); } printf ("\ n"); } } }
Zmodyfikowałem do tego źródło (patrz następny fragment poniżej), co pozwala mi mieć kopię wyjścia na stderr. To wyjście jestem w stanie przekierować:
// w pliku test.c static void print_events (Wyświetl * dpy) { Wydarzenie XEvent; while (1) { XNextEvent (dpy & Event); // [... niektóre inne typy zdarzeń są tutaj pomijane ...] if ((Event.type == key_press_type) || (Event.type == key_release_type)) { pętla int; XDeviceKeyEvent * key = (XDeviceKeyEvent *) & Event; printf („klucz% s% d”, (Event.type == key_release_type)? ”release”: „naciśnij”, key-> kod dostępu); fprintf (stderr, „klucz% s% d”, (Event.type == key_release_type)? „release”: „naciśnij”, key-> kod dostępu); for (loop = 0; loopaxes_count; loop ++) { printf („a [% d] =% d”, key-> first_axis + loop, key-> axis_data [loop]); } printf ("\ n"); } } }
Obecnie moim pomysłem jest to, że być może po przekierowaniu program traci zdolność monitorowania zdarzeń zwolnienia klawisza.
źródło
setvbuf(stdout, (char *) NULL, _IONBF, NULL)
. Może to również jest interesujące !?stdbuf -o0
robi, gdystdbug -oL
przywraca linia buforowanie jak gdy wyjście idzie do terminala.stdbuf
wymusza na aplikacji wywołaniesetvbuf
przy użyciuLD_PRELOAD
lewy.unbuffer test 10 > file
(unbuffer
jest częściąexpect
narzędzi)Polecenie może bezpośrednio pisać, aby
/dev/tty
zapobiec regularnemu przekierowaniu.źródło
/dev/tty
w systemie Linux, użyjscript -c ./demo demo.log
(odutil-linux
).Wygląda na to, że
xinput
odrzuca dane wyjściowe do pliku, ale nie odrzuca danych wyjściowych do terminala. Aby to osiągnąć, prawdopodobniexinput
użyj wywołania systemowegosprawdzanie, czy skrypt filedescriptor, który ma zostać otwarty, odnosi się do terminala, czy nie.
Natknąłem się na to samo zjawisko jakiś czas temu w programie o nazwie
dpic
. Po przejrzeniu źródła i debugowaniu usunąłem powiązane wierszeisatty
i wszystko działało zgodnie z oczekiwaniami.Ale zgadzam się z tobą, że to doświadczenie jest bardzo niepokojące;)
źródło
isatty
przeprowadzonych testów. Wyjście jest generowane przezprintf
funkcję (myślę, że jest to standardowa C). Dodałem trochęfprintf(stderr,"output")
i jest to możliwe, aby przekierować + dowodzi, że cały kod jest naprawdę uruchamiany w przypadku xinput. Dziękuję za sugestię, przecież był to pierwszy szlak tutaj.W twoim
test.c
pliku możesz opróżnić buforowane dane używając(void)fflush(stdout);
bezpośrednio po twoichprintf
instrukcjach.W wierszu poleceń możesz włączyć wyjście buforowane wierszem, uruchamiając
xinput test 10
pseudo terminal (pty) za pomocąscript
polecenia.źródło
Tak. Zrobiłem to nawet w czasach DOS, kiedy programowałem w pascal. Myślę, że zasada ta nadal obowiązuje:
To zepsuło wszelkie rury.
źródło
con
to nazwa DOS dla tego, co wywołuje unix/dev/tty
, tj. terminal (kontrolujący).