Uwaga dodatkowa: Możesz wykonać tę operację całkowicie w vimie, nie używając find lub xargs w ogóle. Otwórz vima bez argumentów, a następnie uruchom :args **/*.txt<CR> ustawić argumenty vima z poziomu edytora.
Trevor Powell
3
@ TrevorPowell: Przez te wszystkie lata vim nigdy nie przestał mnie zadziwiać.
Kiedy wywołujesz program przez xargs, stdin programu (standardowe wejście) wskazuje na /dev/null. (Ponieważ xargs nie zna oryginalny stdin, robi kolejną najlepszą rzecz.)
$ true | xargs filan -s
0 chrdev / dev / null
1 tty / dev / pts / 1
2 tty / dev / pts / 1
$ true | xargs ls -l / dev / fd /
Vim oczekuje, że jego standardowe wejście będzie takie samo jak jego terminal sterujący, i wykonuje różne związane z terminalem ioctl bezpośrednio na stdin. Po zakończeniu /dev/null (lub dowolny deskryptor pliku nie będący tty), te ioctle są bez znaczenia i zwracają ENOTTY, która jest ignorowana.
Domyślam się bardziej konkretnej przyczyny: przy starcie Vim czyta i zapamiętuje stare ustawienia terminala i przywraca je przy wychodzeniu. W naszej sytuacji, gdy wymagane są „stare ustawienia” dla nie-tty fd (deskryptor pliku), Vim otrzymuje wszystkie wartości puste i wszystkie opcje są wyłączone, i niedbale ustawia je na swoim terminalu.
Możesz to zobaczyć, uruchamiając vim < /dev/null, wychodząc z niego, a następnie uruchamiając stty, który wygeneruje całą masę <undef> s. W systemie Linux działa stty sane sprawi, że terminal będzie ponownie użyteczny (chociaż to będzie straciłem takie opcje jak iutf8, prawdopodobnie powodując drobne kłopoty później).
Możesz to uznać za błąd w Vimie, ponieważ to mogą otwarty /dev/tty do sterowania terminalem, ale nie. (W pewnym momencie podczas uruchamiania Vim powiela swój stderr na stdin, co pozwala mu odczytać polecenia wejściowe - z fd otwartego do zapisu - ale nawet to nie jest zrobione wystarczająco wcześnie.
+1, a dla TL; ludzie DR po prostu uciekają stty sane
doc_id
@rahmanisback: Pozostałe odpowiedzi, wraz z komentarzem Trevora, zapewniły przede wszystkim sposoby uniknięcia zerwania terminala. Przyjąłem odpowiedź grawity, ponieważ moje pytanie brzmiało „dlaczego”, a nie „jak unikać” - to dotyczy inne pytanie to właściwie zrodzony ten.
DevSolar
@DevSolar Rozumiem, ale pomyśl o sfrustrowanych ludziach, takich jak ja, którzy po prostu google, jak pozbyć się tego zachowania, podczas gdy nie - niestety - masz wystarczająco dużo czasu, aby przestudiować „dlaczego”, co jest jednak bardzo interesujące.
doc_id
4
kiedy mój terminal się zepsuje, używam tego reset zamiast stty sane i to działa dobrze po tym.
Capi Etheriel
123
Zgodnie z odpowiedzią grawity, xargs zwrotnica stdin do /dev/null
Z OSX / BSD man xargs
-o Reopen stdin as /dev/tty in the child process
before executing the command. This is useful
if you want xargs to run an interactive application.
Dlatego następujący wiersz kodu powinien działać dla Ciebie:
find . -name "*.txt" | xargs -o vim
Dla GNU man xargs nie ma flagi, ale możemy jawnie przekazać / dev / tty, aby rozwiązać problem:
Jak wytworzyłbyś z tego alias bash? $@ nie wydaje się poprawnie tłumaczyć argumentów.
zanegray
1
@zanegray - nie możesz utworzyć aliasu, ale możesz uczynić go funkcją. Próbować: function vimin () { xargs sh -c 'vim "$@" < /dev/tty' vim; }
Christopher
Aby uzyskać szczegółowe wyjaśnienie działania rozwiązania GNU xargs i dlaczego potrzebujesz manekina ignoreme sznur, patrz vi.stackexchange.com/a/17813
Głównym pytaniem było „dlaczego”, a nie „jak tego uniknąć”, a odpowiedź na satysfakcję została udzielona dwa i pół roku temu.
DevSolar
3
To oczywiście nie działa prawidłowo, gdy nazwy plików zawierają spacje lub inne znaki specjalne, a także stanowi zagrożenie bezpieczeństwa.
Dejay Clayton
1
Moja ulubiona odpowiedź, ponieważ działa dla każdego polecenia zawierającego listę plików, a nie tylko „znajdź” lub symbole wieloznaczne. Wymaga to niewielkiego zaufania, jak wskazuje Dejay.
Travis Wilson
1
To nie zadziała w wielu przypadkach użycia, dla których xargs jest przeznaczony: np. Gdy liczba ścieżek jest bardzo wysoka (cc @TravisWilson)
Good Person
20
Powinien działać dobrze, jeśli użyjesz opcji -exec na find zamiast piping do xargs.
Na przykład
Huh ... sztuczka jest + (zamiast „zwykłego” \; ), aby pobrać wszystkie znalezione pliki jeden Sesja Vima - opcja I trzymać zapominając o. Oczywiście masz rację i za to +1. używam vim $(find ...) po prostu z przyzwyczajenia. Jednak właściwie o to prosiłem czemu operacja rurowa zaciska terminal, a grawity przybili go swoim wyjaśnieniem.
DevSolar
2
Jest to najlepsza odpowiedź i działa zarówno na BSD / OSX / GNU / Linux.
kevinarpe
1
Ponadto find nie jest jedynym sposobem uzyskania listy plików, które muszą być edytowane jednocześnie przez vim. Mogę użyć grep, aby znaleźć wszystkie pliki ze wzorem i spróbować edytować je jednocześnie.
Chandranshu
8
Zamiast tego użyj GNU Parallel:
find . -name "*.txt" | parallel -j1 --tty vim
Lub jeśli chcesz otworzyć wszystkie pliki za jednym razem:
Nie jest powszechnie dostępny. Większość dnia pracuję na serwerach, na których nie mogę instalować dodatkowych narzędzi. Ale i tak dziękuję za podpowiedź.
DevSolar
Jeśli masz możliwość zrobienia „kota” plik; chmod + x file ', a następnie możesz zainstalować GNU Parallel: Jest to po prostu skrypt perla. Jeśli chcesz mieć strony man i takie, możesz zainstalować je pod swoim katalogiem domowym: ./configure --prefix = $ HOME i amp; marka i amp; wykonaj instalację
Ole Tange
2
OK, spróbuj - ale równolegle nie otwórz wszystkie pliki, otworzy je kolejno . Jest to również całkiem niezły pomysł na prostą operację. vim $(find . -name "*.txt") jest prostsze i wszystkie pliki są otwierane jednocześnie.
DevSolar
5
@DevSolar: Trochę niezwiązany, ale oba find | xargs i $(find) będą miały duże problemy ze spacjami w nazwach plików.
grawity
2
@grawity Poprawnie, ale nie ma łatwego sposobu na obejście go (o czym wiem). Musisz zacząć się bawić $IFS, -print0 i tak dalej, a potem opuściłeś królestwo jednorazowego rozwiązania linii poleceń i dotarłeś do punktu, w którym powinieneś wymyślić skrypt ... jest powód, dla którego przestają być spacje w nazwach plików.
find
lubxargs
w ogóle. Otwórz vima bez argumentów, a następnie uruchom:args **/*.txt<CR>
ustawić argumenty vima z poziomu edytora.grep -l .. | xargs vim
generuje ostrzeżenie, dlaczego? w unix SEOdpowiedzi:
Kiedy wywołujesz program przez
xargs
, stdin programu (standardowe wejście) wskazuje na/dev/null
. (Ponieważ xargs nie zna oryginalny stdin, robi kolejną najlepszą rzecz.)Vim oczekuje, że jego standardowe wejście będzie takie samo jak jego terminal sterujący, i wykonuje różne związane z terminalem ioctl bezpośrednio na stdin. Po zakończeniu
/dev/null
(lub dowolny deskryptor pliku nie będący tty), te ioctle są bez znaczenia i zwracają ENOTTY, która jest ignorowana.Domyślam się bardziej konkretnej przyczyny: przy starcie Vim czyta i zapamiętuje stare ustawienia terminala i przywraca je przy wychodzeniu. W naszej sytuacji, gdy wymagane są „stare ustawienia” dla nie-tty fd (deskryptor pliku), Vim otrzymuje wszystkie wartości puste i wszystkie opcje są wyłączone, i niedbale ustawia je na swoim terminalu.
Możesz to zobaczyć, uruchamiając
vim < /dev/null
, wychodząc z niego, a następnie uruchamiającstty
, który wygeneruje całą masę<undef>
s. W systemie Linux działastty sane
sprawi, że terminal będzie ponownie użyteczny (chociaż to będzie straciłem takie opcje jakiutf8
, prawdopodobnie powodując drobne kłopoty później).Możesz to uznać za błąd w Vimie, ponieważ to mogą otwarty
/dev/tty
do sterowania terminalem, ale nie. (W pewnym momencie podczas uruchamiania Vim powiela swój stderr na stdin, co pozwala mu odczytać polecenia wejściowe - z fd otwartego do zapisu - ale nawet to nie jest zrobione wystarczająco wcześnie.źródło
stty sane
reset
zamiaststty sane
i to działa dobrze po tym.Zgodnie z odpowiedzią grawity,
xargs
zwrotnicastdin
do/dev/null
Z OSX / BSD
man xargs
Dlatego następujący wiersz kodu powinien działać dla Ciebie:
Dla GNU
man xargs
nie ma flagi, ale możemy jawnie przekazać / dev / tty, aby rozwiązać problem:Ignoreme ma zająć 0 $, więc $ @ to wszystkie argumenty z xargs
źródło
$@
nie wydaje się poprawnie tłumaczyć argumentów.function vimin () { xargs sh -c 'vim "$@" < /dev/tty' vim; }
ignoreme
sznur, patrz vi.stackexchange.com/a/17813Najprostszy sposób:
źródło
Powinien działać dobrze, jeśli użyjesz opcji -exec na find zamiast piping do xargs. Na przykład
$ find . -type f -name filename.txt -exec vi {} +
źródło
+
(zamiast „zwykłego”\;
), aby pobrać wszystkie znalezione pliki jeden Sesja Vima - opcja I trzymać zapominając o. Oczywiście masz rację i za to +1. używamvim $(find ...)
po prostu z przyzwyczajenia. Jednak właściwie o to prosiłem czemu operacja rurowa zaciska terminal, a grawity przybili go swoim wyjaśnieniem.Zamiast tego użyj GNU Parallel:
Lub jeśli chcesz otworzyć wszystkie pliki za jednym razem:
Nawet poprawnie obsługuje nazwy plików takie jak:
Obejrzyj film wprowadzający, aby dowiedzieć się więcej: http://www.youtube.com/watch?v=OpaiGYxkSuQ
źródło
vim $(find . -name "*.txt")
jest prostsze i wszystkie pliki są otwierane jednocześnie.find | xargs
i$(find)
będą miały duże problemy ze spacjami w nazwach plików.$IFS
,-print0
i tak dalej, a potem opuściłeś królestwo jednorazowego rozwiązania linii poleceń i dotarłeś do punktu, w którym powinieneś wymyślić skrypt ... jest powód, dla którego przestają być spacje w nazwach plików.