Nota: Você pode executar esta operação inteiramente dentro vim, não usar findou xargsem tudo. Abra o vim sem argumentos e execute :args **/*.txt<CR>para definir os argumentos do vim de dentro do editor.
Trevor Powell
3
@TrevorPowell: Em todos esses anos, o vim nunca deixou de me surpreender.
Quando você invoca um programa via xargs, o stdin do programa (entrada padrão) aponta para /dev/null. (Como o xargs não conhece o stdin original , ele faz a próxima melhor coisa.)
$ true | xargs filan -s
0 chrdev / dev / null
1 tty / dev / pts / 1
2 tty / dev / pts / 1
$ true | xargs ls -l / dev / fd /
O Vim espera que seu stdin seja igual ao seu terminal de controle e execute vários ioctls relacionados ao terminal no stdin diretamente. Quando executados em /dev/null(ou em qualquer descritor de arquivo não tty), esses ioctls não fazem sentido e retornam ENOTTY, que é ignorado silenciosamente.
Meu palpite para uma causa mais específica: Na inicialização, o Vim lê e se lembra das configurações antigas do terminal e as restaura novamente quando sai. Em nossa situação, quando as "configurações antigas" são solicitadas para um não-tty fd (descritor de arquivo), o Vim recebe todos os valores vazios e todas as opções desabilitadas, e descuidadamente define o mesmo para o seu terminal.
Você pode ver isso executando vim < /dev/null, saindo e executando stty, o que produzirá muitos <undef>s. No Linux, o corredor stty sanevai fazer a utilizável de terminal novamente (embora se perderam opções como iutf8, possivelmente causando pequenos aborrecimentos mais tarde).
Você pode considerar isso um bug no Vim, pois ele pode ser aberto /dev/ttypara controle de terminal, mas não. (Em algum momento durante a inicialização, o Vim duplica seu stderr para stdin, o que permite ler seus comandos de entrada - de um arquivo aberto para gravação - mas mesmo isso não é feito o suficiente.)
+1 e para TL; as pessoas DR apenas executamstty sane
doc_id 11/02/2015
@rahmanisback: As outras respostas, além do comentário de Trevor, forneceram maneiras de evitar a quebra do terminal em primeiro lugar. Aceitei a resposta do grawity, porque minha pergunta era "por que", não "como evitar" - isso é coberto por outra pergunta que realmente gerou essa.
DevSolar 11/11
@DevSolar Entendeu, mas pense em pessoas frustradas como eu, que apenas pesquisam no Google como se livrar desse comportamento, embora não - infelizmente - tenham tempo suficiente agora para estudar o "porquê", o que é muito interessante.
DOC_ID
4
quando meu terminal quebra, assim, eu uso em resetvez de stty sanee funciona bem depois disso.
Capi Etheriel
137
(Seguindo a explicação de grawity, isso xargsaponta stdinpara /dev/null.)
A solução para esse problema é adicionar o -oparâmetro a xargs. De man xargs:
-o
Reabra stdin como /dev/ttyno processo filho antes de executar o comando. Isso é útil se você deseja xargsexecutar um aplicativo interativo.
Portanto, a seguinte linha de código deve funcionar para você:
encontrar . -name "* .txt" | xargs -o vim
O GNU xargs suporta essa extensão desde algum lançamento em 2017 (com o nome da opção longa --open-tty).
Para versões mais antigas ou outras do xargs, você pode explicitamente passar /dev/ttypara resolver o problema:
Como você criaria um alias de bash com isso? $@parece não estar traduzindo argumentos corretamente.
Zanegray 31/08/2015
1
@zanegray - você não pode criar um alias, mas pode torná-lo uma função. Tente:function vimin () { xargs sh -c 'vim "$@" < /dev/tty' vim; }
Christopher
Para uma explicação detalhada de como a solução xargs GNU funciona, e porque você precisa o manequim ignoremecorda, ver vi.stackexchange.com/a/17813
wisbucky
@zanegray, você pode criar um pseudônimo. As aspas são complicadas. Veja a solução em vi.stackexchange.com/a/17813
wisbucky 2/11/18
The -J, -o, -P and -R options are non-standard FreeBSD extensions which may not be available on other operating systems.(Não estava disponível no macOS para mim porque instalei o xargs a partir do homebrew (o GNU))
A questão principal era "por que", não "como evitá-lo", e foi respondida com satisfação há dois anos e meio.
DevSolar
5
Obviamente, isso não funciona corretamente quando os nomes de arquivos contêm espaços ou outros caracteres especiais e também é um risco à segurança.
DeJay Clayton
1
Minha resposta favorita porque funciona para todos os comandos que listam arquivos, não apenas para "encontrar" ou curingas. Exige um pouco de confiança, como Dejay aponta.
Travis Wilson
1
Isto não irá trabalhar com muitos casos de uso xargs é projetado para: por exemplo, quando o número de caminhos é muito elevado (cc @TravisWilson)
Boa Pessoa
21
Deverá funcionar muito bem se você usar a opção -exec em find ao invés de canalizar para xargs.
Huh ... o truque é o +(em vez de "o habitual" \;) para colocar todos os arquivos encontrados em uma sessão do Vim - uma opção que eu continuo esquecendo. Você está certo, é claro, e +1 para isso. Eu uso vim $(find ...)simplesmente por hábito. No entanto, eu estava realmente perguntando por que a operação do tubo estraga o terminal e o grawity acertou em cheio com sua explicação.
DevSolar
2
Esta é a melhor resposta e funciona no BSD / OSX / GNU / Linux.
Kevinarpe
1
Além disso, o find não é a única maneira de obter uma lista de arquivos que precisam ser editados simultaneamente pelo vim. Posso usar o grep para encontrar todos os arquivos com um padrão e tentar editá-los ao mesmo tempo.
Chandranshu
8
Use o GNU Parallel:
find . -name "*.txt" | parallel -j1 --tty vim
Ou se você deseja abrir todos os arquivos de uma só vez:
find . -name "*.txt" | parallel -Xj1 --tty vim
Ele até lida corretamente com nomes de arquivos como:
Não onipresente. Na maior parte do dia, trabalho em servidores nos quais não tenho liberdade para instalar ferramentas adicionais. Mas obrigado pela dica de qualquer maneira.
DevSolar 16/09
Se você tem a liberdade de fazer o arquivo 'cat>; chmod + x file ', então você pode instalar o GNU Parallel: É simplesmente um script perl. Se você quiser páginas de manual e tal, você pode instalá-lo em seu diretório de usuário: ./configure --prefix = $ HOME && make && make install
Ole Tange
2
OK, tentei isso - mas o paralelo não abre todos os arquivos, mas abre-os sucessivamente . Também é um bocado para uma operação simples. vim $(find . -name "*.txt")é mais simples e você abre todos os arquivos de uma só vez.
DevSolar
5
@ DevSolar: um pouco não relacionado, mas ambos find | xargse $(find)terão grandes problemas com espaços nos nomes dos arquivos.
grawity
2
@rawity Correto, mas não há uma maneira fácil de contornar isso (que eu saiba). Você teria que começar a mexer com $IFS, -print0e outras coisas, e então você deixou o reino de uma solução de linha de comando one-shot e chegou a um ponto onde você deve vir acima com um script ... há uma razão pela qual os espaços em nomes de arquivos são desencorajados .
DevSolar 21/09
0
talvez não seja o melhor, mas aqui está o script que eu uso (nomeado vim-open):
Quanto a várias outras respostas, observe que a pergunta real era "por que", não "como evitá-la". (Por que eu ainda apontam para o comentário de Trevor sob a minha pergunta como a forma mais sólida que não necessita de script, aliases ou qualquer coisa.)
find
ouxargs
em tudo. Abra o vim sem argumentos e execute:args **/*.txt<CR>
para definir os argumentos do vim de dentro do editor.grep -l .. | xargs vim
gera um aviso, por quê? no unix SERespostas:
Quando você invoca um programa via
xargs
, o stdin do programa (entrada padrão) aponta para/dev/null
. (Como o xargs não conhece o stdin original , ele faz a próxima melhor coisa.)O Vim espera que seu stdin seja igual ao seu terminal de controle e execute vários ioctls relacionados ao terminal no stdin diretamente. Quando executados em
/dev/null
(ou em qualquer descritor de arquivo não tty), esses ioctls não fazem sentido e retornam ENOTTY, que é ignorado silenciosamente.Meu palpite para uma causa mais específica: Na inicialização, o Vim lê e se lembra das configurações antigas do terminal e as restaura novamente quando sai. Em nossa situação, quando as "configurações antigas" são solicitadas para um não-tty fd (descritor de arquivo), o Vim recebe todos os valores vazios e todas as opções desabilitadas, e descuidadamente define o mesmo para o seu terminal.
Você pode ver isso executando
vim < /dev/null
, saindo e executandostty
, o que produzirá muitos<undef>
s. No Linux, o corredorstty sane
vai fazer a utilizável de terminal novamente (embora se perderam opções comoiutf8
, possivelmente causando pequenos aborrecimentos mais tarde).Você pode considerar isso um bug no Vim, pois ele pode ser aberto
/dev/tty
para controle de terminal, mas não. (Em algum momento durante a inicialização, o Vim duplica seu stderr para stdin, o que permite ler seus comandos de entrada - de um arquivo aberto para gravação - mas mesmo isso não é feito o suficiente.)fonte
stty sane
reset
vez destty sane
e funciona bem depois disso.(Seguindo a explicação de grawity, isso
xargs
apontastdin
para/dev/null
.)A solução para esse problema é adicionar o
-o
parâmetro axargs
. Deman xargs
:Portanto, a seguinte linha de código deve funcionar para você:
O GNU xargs suporta essa extensão desde algum lançamento em 2017 (com o nome da opção longa
--open-tty
).Para versões mais antigas ou outras do xargs, você pode explicitamente passar
/dev/tty
para resolver o problema:(
ignoreme
Existe para receber $ 0, para que $ @ sejam todos argumentos de xargs.)fonte
$@
parece não estar traduzindo argumentos corretamente.function vimin () { xargs sh -c 'vim "$@" < /dev/tty' vim; }
ignoreme
corda, ver vi.stackexchange.com/a/17813The -J, -o, -P and -R options are non-standard FreeBSD extensions which may not be available on other operating systems.
(Não estava disponível no macOS para mim porque instalei o xargs a partir do homebrew (o GNU))A maneira mais fácil:
fonte
Deverá funcionar muito bem se você usar a opção -exec em find ao invés de canalizar para xargs.
fonte
+
(em vez de "o habitual"\;
) para colocar todos os arquivos encontrados em uma sessão do Vim - uma opção que eu continuo esquecendo. Você está certo, é claro, e +1 para isso. Eu usovim $(find ...)
simplesmente por hábito. No entanto, eu estava realmente perguntando por que a operação do tubo estraga o terminal e o grawity acertou em cheio com sua explicação.Use o GNU Parallel:
Ou se você deseja abrir todos os arquivos de uma só vez:
Ele até lida corretamente com nomes de arquivos como:
Assista ao vídeo de introdução para saber mais: http://www.youtube.com/watch?v=OpaiGYxkSuQ
fonte
vim $(find . -name "*.txt")
é mais simples e você abre todos os arquivos de uma só vez.find | xargs
e$(find)
terão grandes problemas com espaços nos nomes dos arquivos.$IFS
,-print0
e outras coisas, e então você deixou o reino de uma solução de linha de comando one-shot e chegou a um ponto onde você deve vir acima com um script ... há uma razão pela qual os espaços em nomes de arquivos são desencorajados .talvez não seja o melhor, mas aqui está o script que eu uso (nomeado
vim-open
):irá trabalhar com
vim-open a b c
els | vim-open
por exemplofonte