Terminal przestał działać po wywołaniu Vima za pomocą xargs

30

Czasami próbowałem wywołać Vima przy użyciu xargs:

find . -name '*.java' | xargs vim

… Jaki rodzaj prac:

  1. Gdy uruchamia się Vim, na krótko pojawia się następujące ostrzeżenie:

    Vim: Warning: Input is not from a terminal
    
  2. Edycja działa - :filespoprawnie wylicza wszystkie .javapliki zgodnie z oczekiwaniami.
  3. Mogę zapisać i zrezygnować.

Jednak po wyjściu z Vima mój terminal jest zablokowany:

  • Cokolwiek napiszę w wierszu poleceń powłoki, nie jest powtarzane.
  • Zwroty karetki w ogóle się nie pojawiają, a linie pojawiają się tylko czasami.

Trwa to do momentu wydania reset(1)polecenia ponownego zainicjowania terminala.

Czy to błąd Vima, czy może istnieje bardziej satysfakcjonujące wyjaśnienie, dlaczego współpracuje on z terminalem w ten sposób? Widziałem, jak to się dzieje w Vimie do wersji 7.3 (wersja nie wydaje się mieć znaczenia) w Linuksie i różnych Uniksach.

Mam świadomość jednego obejścia, a mianowicie vim $(find . -name '*.java'). Inne obejścia byłyby mile widziane, ale to nie jest moje główne pytanie.

200_sukces
źródło
W pewnym sensie mam ochotę wypełnić tę stronę tak wieloma pytaniami, jak to możliwe, ale ... na to pytanie udzielono odpowiedzi dziesiątki razy w ciągu roku na SO / SU i gdzie indziej: xargsużywa manekina stdin, z którego nie może korzystać Vim. wszystko później.
romainl
1
@romainl Nie jestem aktywny na tych stronach i nigdy nie widziałem, żeby o to pytano - szczerze mówiąc.
200_success
Powiązane: superuser.com/questions/336016/… - być może ktoś może skondensować najlepsze odpowiedzi na świetną odpowiedź.
muru
2
Świetne pytanie - przytrafiło mi się to wiele razy. Nie używam też innych stron SO - jeśli jest to związane z vimem, chciałbym je tutaj znaleźć.
craigp

Odpowiedzi:

21

Dzieje się tak, gdy vim jest wywoływany i jest podłączony do wyjścia poprzedniego potoku, zamiast terminala i otrzymuje inne nieoczekiwane dane wejściowe (takie jak NUL). To samo dzieje się po uruchomieniu:, vim < /dev/nullwięc resetpolecenie w tym przypadku pomaga. Wyjaśnia to dobrze grawitacja u administratora .

Jeśli używasz finddo przekazywania nazw plików do edycji, nie potrzebujesz xargs, po prostu użyj -execna przykład:

find . -name '*.java' -exec vim {} +

Jeśli chcesz użyć xargs, na Unix / macOS powinieneś użyć -oparametru, takiego jak:

find . -name '*.java' | xargs -o vim

-oPonownie otwórz stdin jako / dev / tty w procesie potomnym przed wykonaniem polecenia. Jest to przydatne, jeśli chcesz, aby xargs uruchamiał interaktywną aplikację.

lub:

find . -name "*.java" -type f -print0 | xargs -o -0 vim

Uwaga: Użycie -print0/ -0będzie obsługiwać nazwy plików z białymi spacjami.


find+ BSDxargs

W systemach Unix / macOS możesz wypróbować następujące obejście:

find . -name '*.java' | xargs -J% sh -c 'vim < /dev/tty $@'

Możesz także użyć składni zastępowania poleceń , na przykład:

vim $(find . -name '*.java')
vim `find . -name '*.java`

Alternatywnie użyj GNU parallelzamiast xargswymusić alokację tty, na przykład:

find . -name '*.java' | parallel -X --tty vi

Uwaga: parallelw systemach Unix / OSX nie będzie działać, ponieważ ma inne parametry i nie obsługuje tty.

Wiele innych popularnych komend zapewnia alokację pseudo-tty a także (jak -tw ssh), więc sprawdzić o pomoc.

Inną sugestią byłoby użycie:

Związane z:

kenorb
źródło
Mój GNU xargsnie ma -J. Wydaje się, że jest to opcja MacOS (BSD), która nie występuje w wersji GNU.
Wstrzymano do odwołania.
12

Sugestia obejścia: użyj bufora jako nawigatora systemu plików

Użyj vim -polecenia, aby odczytać listę ścieżek ze standardowego wejścia. Vim :help --wyjaśnia to: 1

Rozpocznij edycję nowego bufora, który jest wypełniony tekstem czytanym ze standardowego wejścia. Polecenia, które normalnie byłyby odczytywane ze stdin, będą teraz odczytywane ze stderr. Przykład:

find . -name "*.c" -print | vim -

Następnie możesz użyć gflub, Ctrl-wCtrl-faby przejść do pliku odpowiednio w tym samym buforze lub w nowym podzielonym oknie.

Sugestia obejścia: lista argumentów

Innym świetnym sposobem jest użycie listy argumentów Vima. :argadd **/*.javaKomenda będzie zapełnić listę argumentów Vim jest ze wszystkich plików znajdujących się wewnątrz java bieżącym katalogu rekurencyjnie. Następnie można użyć :nexti :prevdo poruszania się pomiędzy plikami.


1 pierwszy -mówi Vimowi, że chcesz przeszukać pomoc dla opcji wiersza poleceń, drugi to tak naprawdę flaga wiersza poleceń, której szukasz. Przeczytaj :help help-contextwięcej takich sztuczek.

akshay
źródło
8

Poza tym resetmożesz spróbować:

stty sane

co również powinno sprawić, że twój terminal będzie znów użyteczny.

Zobacz tutaj o wyjaśnienia. I jakoś można to uznać za niewłaściwe zachowanie, przynajmniej Neovim nie ma obecnie tego problemu.

ryenus
źródło
To nie do końca odpowiada na pytanie, ale pomogło mi, więc +1.
Przywróć Monikę iamnotmaynard
Odpowiada to na moje pytanie;) Chociaż po przeczytaniu PO więcej chyba resetteż powinienem.
Sridhar Sarnobat
1

Powodem jest to, że xargszestawy stdindo /dev/null, natomiast vimpotrzeby stdin, aby być /dev/tty.


xargsRozwiązanie BSD (np. Mac):

echo -e 'file1\nfile2' | xargs -o vim

-oustawia proces stdinpotomny xarg ( vimw tym przypadku) na dev/tty.


xargsRozwiązanie GNU (np. Linux):

GNU xargsnie ma takiej -oopcji. Zamiast tego będziesz musiał zastosować bardziej skomplikowane obejście. (Uwaga: bardzo ważne jest, aby mieć końcowy zerociąg, nie zapomnij go.)

echo -e 'file1\nfile2' | xargs bash -c '</dev/tty vim "$@"' zero

Możesz także ustawić go jako alias:

alias vimin='xargs bash -c '\''</dev/tty vim "$@"'\'' zero'
echo -e 'file1\nfile2' | vimin

Szczegółowe objaśnienie rozwiązania GNU xargs

Podzielmy to krok po kroku:

echo -e 'file1\nfile2' | xargs bash -c '</dev/tty vim "$@"' zero

1. xargspo prostu dołącza stdinkoniec łańcucha, więc xargswykonamy to:

    bash -c '</dev/tty vim "$@"' zero file1 file2

2. Format dla bash -cto bash -c 'COMMAND_STRING' $0 $1 $2 etc.

"$@"rozwija się do parametrów pozycyjnych "$1", "$2"itp. Nie zawiera „$ 0”, ponieważ jest to specjalny parametr dla nazwy skryptu, a nie parametr pozycyjny. Właśnie dlatego musimy dodać fikcyjny ciąg zero(może to być dowolny ciąg), aby zajął miejsce $0. W przeciwnym razie stracisz pierwszy plik.

Po rozwinięciu uzyskujesz "$@":

    bash -c '</dev/tty vim file1 file2' 

3. bash -cwykona COMMAND_STRING:

    </dev/tty vim file1 file2 

</dev/ttyustawia stdinsię /dev/ttytak, że vimmogą pracować w trybie interaktywnym.

wisbucky
źródło
+1 To wydaje się być duplikatem odpowiedzi z największą liczbą głosów, ale tak nie jest. $0Zastępczy (tutaj „zero”) jest kluczem.
Wstrzymano do odwołania.
0

Nie znalazłem wszystkich tych odpowiedzi. Po zmaganiu się z problemem xargs najprostszym sposobem - dla mnie! - na wyszukiwanie i otwieranie w ogólnym polu jest:

vim -O `grep -lir mySearchTerm *`

Nie mam problemu korzystając findz xargsa grep, ale uważam, że składnia denerwujące. Jako codzienny programista, który używa vimterminala jako swojego IDE i stale przeszukuje pliki pod kątem właściwości, właśnie tego używałem.

Jest czas i miejsce w find . -path ./node_modules -prune -o -name '*.js' | xargs grep -i mySearchTermpołączeniu z otwieraniem plików za pomocą vima i innymi metodami. Dla mnie to rzadko.

Mam nadzieję, że to komuś pomoże.

Gavin
źródło
2
FWIW zaleca się, aby nie używać starszej notacji backticks i $(...)zamiast tego używać . Nie jest to tak ważne w wierszu poleceń, jak w skrypcie, ale myślę, że nadal lepiej jest używać tego w swoich odpowiedziach :) (odniesienia tutaj i tutaj )
statox