Dlaczego Ctrl-D (EOF) opuszcza powłokę?

68

Czy dosłownie „kończysz plik”, wprowadzając tę ​​sekwencję zmiany znaczenia, tzn. Czy interaktywna sesja powłoki jest postrzegana przez powłokę jako rzeczywisty strumień plików, jak każdy inny strumień plików? Jeśli tak, to który plik?

Czy też sygnał Ctrl+ to Dtylko symbol zastępczy, co oznacza, że ​​„użytkownik zakończył wprowadzanie danych i możesz zakończyć”?

Geeb
źródło
6
Do twojej wiadomości, w bash możesz set -o ignoreeofzmienić to zachowanie.
Keith
Miałem ten sam problem. Mój błąd polegał na tym, że przypadkowo przypisałem skrót profilu konsoli do „Ctrl + d”. Nie moja najdumniejsza chwila.
Brian Simonsen

Odpowiedzi:

78

^DZnaków (znany również jako \04lub 0x4, Koniec transmisji w Unicode) jest wartością domyślną dla eofspecjalnego parametru znak kontrolny terminalu lub sterownika pseudo-terminala w jądrze (a dokładniej z ttydyscypliną linia dołączone do szeregowego lub pseudo- urządzenie tty ). To c_cc[VEOF]o termiosstrukturze przekazywane do TCSETS / TCGETS ioctljeden problemy z urządzeniem końcowym, aby wpływać na zachowanie kierowcy.

Typowe polecenie, które je wysyła, ioctlsto sttypolecenie.

Aby pobrać wszystkie parametry:

$ stty -a
prędkość 38400 bodów; rzędy 58; kolumny 191; linia = 0;
intr = ^ C; quit = ^ \; kasowanie = ^ ?; kill = ^ U; eof = ^ D ; eol = <undef>; eol2 = <undef>; swtch = <undef>; start = ^ Q; stop = ^ S; susp = ^ Z; rprnt = ^ R; werase = ^ W; lnext = ^ V; kolor = ^ O;
min = 1; czas = 0;
-parenb -parodd cs8 -hupcl -cstopb cread -clocal -crtscts
-ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff -iuclc -ixany -imaxbel iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl echoke

Ten eofparametr jest istotny tylko wtedy, gdy urządzenie końcowe znajduje się w icanontrybie.

W tym trybie sterownik terminala (nie emulator terminala) implementuje bardzo prosty edytor linii , w którym można wpisać, Backspaceaby usunąć znak, Ctrl-Uaby usunąć całą linię ... Gdy aplikacja czyta z urządzenia końcowego, nie widzi nic, dopóki Naciśnięcie Returnw tym momencie read()zwraca pełną linię w tym ostatnim LFznaku (domyślnie sterownik terminala przekłada się również CRwysłana z terminala na Returncelu LF).

Teraz, jeśli chcesz wysłać to, co do tej pory wpisałeś bez naciskania Enter, tam możesz wpisać eofznak. Po otrzymaniu tego znaku z emulatora terminala sterownik terminala przesyła bieżącą treść wiersza, aby aplikacja wykonująca readgo otrzymała go takim, jaki jest (i nie będzie zawierała LFznaku końcowego ).

Teraz, jeśli bieżąca linia była pusta i pod warunkiem, że aplikacja będzie w pełni czytać wcześniej wprowadzone linie, readzwróci 0 znaków.

Oznacza to koniec pliku dla aplikacji (kiedy czytasz z pliku, czytasz, dopóki nie będzie już nic więcej do odczytania). Dlatego nazywa się to eofznakiem, ponieważ wysłanie go powoduje, że aplikacja widzi, że nie ma już żadnych danych wejściowych.

Teraz nowoczesne powłoki, po ich wyświetleniu, nie ustawiają terminala w icanontrybie, ponieważ implementują własny edytor linii, który jest znacznie bardziej zaawansowany niż wbudowany sterownik terminala. Jednak w swoim własnym edytorze liniowym , aby uniknąć mylenia użytkowników, nadają one ^Dznakowi (lub jakiemukolwiek ustawieniu terminala eofjakieś znaczenie) temu samemu znaczeniu (oznaczać eof).

Stéphane Chazelas
źródło
Kiedy zacząłem czytać ten komentarz, wiedziałem, że napisał go Stephane :) Ty, Stephane, jesteś moim bohaterem Bash i nie jestem sarkastyczny. Chciałbym zjeść z tobą lunch i wybrać mózg, jeśli kiedykolwiek będziesz w Nowym Jorku, kupuję.
Gregg Leventhal
@GreggLeventhal. Dzięki. Jednak szanse, że w najbliższym czasie pójdę do Nowego Jorku, są niewielkie.
Stéphane Chazelas
Jest EOT nawet w 7-bitowym ASCII
Bananguin
9

CTRL_D to tylko sygnał informujący, że to koniec strumienia tekstowego. Nie kończysz na nim pliku, kończysz strumień wejściowy, wpisując go. CTRL_D nie oznacza żadnego znaku ani bajtu, jak można to sprawdzić za pomocą narzędzia hexdump:

# cat >test.txt
asdf# hexdump -C test.txt 
00000000  61 73 64 66                                       |asdf|
00000004
# ll test.txt 
-rw-r--r-- 1 root root 4 Jan 21 11:55 test.txt
Thorsten Staerk
źródło
5
Powodem, dla którego kończy powłokę jest to, że jest ona zasadniczo procesem, który akceptuje dane wejściowe i robi z nimi różne rzeczy. Kiedy powiesz, że nie będzie już żadnych danych wejściowych, powłoka nie ma nic więcej do roboty.
Jenny D
Zdaję sobie sprawę, że sekwencja EOF nie jest zawarta, powiedzmy, w pliku tekstowym i jest generowana przez system operacyjny w celu zgłoszenia braku danych do odczytania. Myślę, że tak naprawdę pytam, czy sesja terminalu interaktywnego jest postrzegana przez powłokę jako rzeczywisty strumień plików, jak każdy inny strumień plików.
Geeb
Właśnie edytowałem oryginalne pytanie, aby wyjaśnić.
Geeb
2
tak, strumień, który przechodzi do bash, jest strumieniem wejściowym jak każdy inny. CTRL_D sygnalizuje, że strumień wejściowy jest na końcu i bash może wyjść.
Thorsten Staerk