Shell nie pokazuje wpisanych poleceń, działa „reset”, ale co się stało?

57

Mój problem polega na tym, że powłoka Bash przestaje pokazywać znaki, które do niej wpisuję. Czyta jednak polecenia.

Z tym problemem spotkałem się już kilka razy i nie rozumiem, co go powoduje. Wiem, jak to rozwiązać, ale nie podoba mi się to, kiedy „wuduję” swoją drogę wyjścia z problemów.

Opiszę dwa sposoby, w jakie napotkałem ten problem:

Pracuję nad pewnym procesem, http://pythonpaste.org/script/, a czasami, kiedy go zatrzymuję lub psuje kontrolę, wraca do powłoki. Kiedy idę i wpisuję polecenia w powłoce, znaki, które wpisuję, nie pojawiają się. Po naciśnięciu Enter polecenia przesyłane. Na przykład:

  • Piszę „ls”
  • Widzę tylko pusty monit i nic więcej
  • Naciskam Enter i wyświetla się lista plików, innymi słowy: polecenie jest wykonywane
  • po wydaniu polecenia „reset” powłoka znów zaczyna normalnie działać

Drugi sposób to się dzieje, gdy wydajemy takie polecenie:

$ grep foo * -l | xargs vim

Używam grep, aby znaleźć pliki, które mają określony wzorzec, a następnie chcę otworzyć wszystkie pliki wynikające z grep. Działa to jak urok (choć nie tak szybko, jak się spodziewałem). Ale kiedy wychodzę z Vima, moja powłoka przestaje pokazywać znaki, które do niej wpisuję. Polecenie resetu rozwiązuje problem.

Domyślam się, że oba problemy mają przyczynę leżącą u podstaw, ale jestem trochę zakłopotany tym, jak i czym jest ten powód.

Samo poszukiwanie tego problemu jest problematyczne, ponieważ opis jest niejasny i nie ma dla niego trudnych warunków wyszukiwania.

Edytować

Dając

stty --all

polecenie zgodnie z żądaniem Johna S. Grubera dało następujące dane wyjściowe (białe znaki edytowane dla czytelności)

speed 0 baud;
rows 53;
columns 186;
line = 0;
intr = <undef>;
quit = <undef>;
erase = <undef>;
kill = <undef>; 
eof = <undef>;
eol = <undef>; 
eol2 = <undef>; 
swtch = <undef>; 
start = <undef>; 
stop = <undef>; 
susp = <undef>;
rprnt = <undef>; 
werase = <undef>; 
lnext = <undef>; 
flush = <undef>; 
min = 0; 
time = 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
Niels Bom
źródło
2
Kiedy tak się stanie, wpisz stty --alli wpisz wyniki w swoim pytaniu. Echo jest wyłączaną cechą tty. Vim zrobi to, gdy jest uruchomiony, i przełączy terminal również w tryb surowy. Po wyjściu powinien zresetować ustawienia terminala. Kiedy vim działa, nie chcesz powtarzać ipolecenia, które przełącza edytor w tryb wstawiania, na przykład. Te ustawienia mówią urządzeniu tty, jak powinno przetwarzać to, co wpisujesz. Podczas działania vima dba o echo tego, co powinno zostać powtórzone itp.
John S Gruber
Mam te same objawy, kiedy zatrzymuję Zope (z CTRL + C), kiedy jest uruchomiony na pierwszym planie i jestem w sesji debugowania ipdb.
Mark van Lent
@MarkvanLent Myślę, że też mam ten problem
Niels Bom,
@JohnSGruber Dodałem wynik stty --alldo mojego pytania. Z góry dziękuję!
Niels Bom,

Odpowiedzi:

68

Podczas uruchamiania powłoki lub większości programów w powłoce wszystko, co wpiszesz, jest wysyłane z powrotem do terminala użytkownika przez podsystem tty jądra. Istnieje również inna specjalna obsługa usuwania znaków, Ctrl + R, Ctrl + Z i tak dalej.

Niektóre programy (w szczególności edytora), które działają z wiersza poleceń, nie potrzebują tego ani nie chcą. Z tego powodu sygnalizują jądro wywołaniem IOCTL przeciwko urządzeniu tty (terminalowi), że nie chcą tego zachowania. Nie chcą też, aby znaki specjalne robiły specjalne rzeczy. Zamiast tego pytają jądro o tryb „raw”. W szczególności edytory takie jak vim wyłączają różne „ustawienia echa”. Wszystko to dotyczy prawdziwych terminali tty na liniach szeregowych komputera, wirtualnych terminali w Alt + Ctrl + F1 lub naprawdę wirtualnych terminali, które otrzymujesz, gdy uruchamiasz coś takiego jak gnome-terminal pod GUI.

Takie programy powinny resetować wszystkie tryby, które zmieniają na wirtualnym terminalu, z którego korzystają przed wyjściem, na przykład poprzez wprowadzenie polecenia wyjścia z edytora lub na przykład odebrania sygnału (z Control + C).

Jeśli nie zrobią tego poprawnie, tty pozostaje w zabawnym stanie, który odkryłeś. Ponieważ programy nie mogą zresetować terminala, resetpolecenie zostało napisane, aby umożliwić użytkownikowi odzyskanie.

Zakładam, że przerwanie nie działa z uruchomionym oprogramowaniem Pythona. Sądzę, że ten program nie ma szansy na zresetowanie terminala lub po prostu tego nie robi.

W przypadku vim, kiedy uruchomię twój przykład, otrzymuję to samo zachowanie, które opisujesz. Widzę także komunikat „Vim: Ostrzeżenie: Dane wejściowe nie pochodzą z terminala” (znika po zresetowaniu). Wynika to z faktu, że vim nie jest uruchamiany normalnie z powłoki. Zamiast tego polecenia „grep” i „xargs” używają standardowego wejścia, zwykle zajmowanego przez tty, do przekazywania nazw plików z greptto xargs.

W opublikowanym wyjściu z stty -amożemy zobaczyć „-echo”, również potwierdzające, że to jest problem. Jeśli miałbyś zabić Vima w taki sposób, że nie byłby w stanie z wdziękiem poradzić sobie z sygnałem, prawdopodobnie zobaczyłbyś ten sam problem.

Problem opisano w innym miejscu na https://stackoverflow.com/questions/3852616/xargs-with-command-that-open-editor-leaves-shell-in-weird-state .

Rozwiązaniem w przypadku vima jest uniknięcie xargs i użycie zamiast tego:

 vim $(grep foo * -l)

Tutaj lista plików jest budowana przez powłokę, podobnie jak xargs, ale powłoka wywołuje vim, który jest bezpośrednio podłączony do tty. Do pliku wyjściowego błędu wysyłany jest komunikat ostrzegawczy, a vim poprawnie ustawia i resetuje ustawienia tty.

Więcej referencji tutaj i kolejna interesująca tutaj . Inne interesujące rozwiązanie podano w odpowiedzi na https://stackoverflow.com/questions/8228831/hy-does-locate-filename-xargs-vim-cause-strange-terminal-behaviour .

John S Gruber
źródło
Dzięki za dokładne wyjaśnienie. Kompletny powód, dla którego to nie działa, wygląda jak dość głęboki rabbitol (tty, ioctl itp.), Więc nie mogę powiedzieć, że rozumiem całkowicie, ale to już nie jest voodoo, więc jeszcze raz dziękuję!
Niels Bom,
Aby zakończyć, mogę wykonać grep foo * -l | vim -bez problemów. Myślę więc, że problem nie dotyczy grep i xargs, ale tylko xargs. Zgodziłbyś się?
Niels Bom,
1
To nie jest problem z grep lub xargs. Problem polega na tym, że standard nie jest już ustawiony na tty. To się nie udaje również „prawda | vi / tmp / afile1. W jednym z odniesień wspomniano, że vim ustawia stdin na stdout (wciąż tty), ponieważ w tych situtations ustawiono stdin na / dev / null. Kiedy to zrobi, vim może zapamiętać i zresetować echo i inne ustawienia, ale tego nie robi. Myślę, że to jest problem z vimem.
John S Gruber,
Było to bardzo pomocne, ponieważ wpadłem na to. To wydawało się losowe, ale założę się, że zawsze tak było, kiedy próbowałem zrobić coś z vi, które nie wychodziło czysto lub używało fajki.
Michael Mathews,
1
Dziękuję Ci! W końcu wymyśliłem, jak odzyskać system po bash w OS X po ctrl-c do git add -p!
Steve Jansen
0

Założyłbym nowego użytkownika w systemie (mam na myśli utworzenie nowego, czystego użytkownika i zalogowanie się tam) i sprawdzenie, czy problem nie istnieje. Jeśli nie, to albo Twój terminal, albo ustawienia X11.

Cegła suszona na słońcu
źródło
Dodałem nowego użytkownika i przetestowałem to za pomocą grep foo * -l | xargs vimpolecenia. Problem nadal istnieje. Nie do końca rozumiem, jak moje ustawienia X11 mogą wpłynąć na to, jak mój terminal reaguje btw. Czy mógłbyś to rozwinąć? Dzięki!
Niels Bom,