xargs e vi - “A entrada não é de um terminal”

11

Eu tenho cerca de 10% de arquivosphp.ini no meu sistema, localizados em todo o lugar, e queria navegar rapidamente por eles. Eu tentei este comando:

locate php.ini | xargs vi

Mas vi me avisa Input is not from a terminal e então o console começa a ficar muito estranho - depois eu preciso pressionar :q! para sair de vi e depois desconectar da sessão ssh e reconectar para que o console se comporte normalmente novamente.

Eu acho que meio que entendo o que está acontecendo aqui - basicamente o comando não terminou quando vi começou então o comando talvez não tenha terminado e vi não acha que o terminal está no modo normal.

Eu não tenho ideia de como consertar isso. Eu pesquisei no Google e também no unix.stackexchange.com com pouca sorte.

    
por cwd 31.07.2012 / 22:52

5 respostas

11

Eu odeio xargs , eu realmente gostaria que morresse: -)

vi $(locate php.ini)

Nota: isto terá problemas se seus caminhos de arquivo tiverem espaços, mas é funcionalmente equivalente ao seu comando.
Esta próxima versão irá manipular corretamente espaços, mas é um pouco mais complicada (novas linhas em nomes de arquivos ainda irão quebrá-lo)

(IFS=$'\n'; vi $(locate php.ini))


Explicação:

O que está acontecendo é que os programas herdam seus descritores de arquivos do processo que os gerou. xargs tem seu STDIN conectado ao STDOUT de locate , então vi não tem idéia do que realmente é o STDIN original.

    
por 31.07.2012 / 23:10
8

Esta pergunta foi feita anteriormente no Superusuário fórum.

Citando a resposta de @grawity sobre essa questão:

When you invoke a program via xargs, the program's stdin (standard input) points to /dev/null. (Since xargs doesn't know the original stdin, it does the next best thing.)

Vim expects its stdin to be the same as its controlling terminal, and performs various terminal-related ioctl's on stdin directly. When done on /dev/null (or any non-tty file descriptor), those ioctls are meaningless and return ENOTTY, which gets silently ignored.

Isso é mencionado nas páginas de manual do xarg. Do OSX / BSD:

-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.

Assim, no OSX, você pode usar o seguinte comando:

find . -name "php.ini" | xargs -o vim

Enquanto, não há nenhuma chave direta na versão GNU, este comando funcionará. (Certifique-se de incluir a string dummy , caso contrário, o primeiro arquivo será descartado.)

find . -name "php.ini" | xargs bash -c '</dev/tty vim "$@"' dummy

As soluções acima são de cortesia Jaime McGuigan no SuperUser . Adicioná-los aqui para futuros visitantes que pesquisarem o site por esse erro.

    
por 31.07.2012 / 23:20
1

Uma maneira rápida de fazer isso é usar back-ticks (sotaques graves) para executar um comando antes de executar outro comando.

Por exemplo,

vi 'find / -type f -name 'php.ini''

O comando contido nos back-ticks será executado primeiro. A saída do comando contido é então executada pelo comando declarado antes dos tiques de retorno.

Por exemplo, na linha acima, o comando find / -type f -name 'php.ini' será executado primeiro, enviará a saída e, em seguida, vi será executado nessa saída.

    
por 31.07.2012 / 23:37
1

Edite vários php.ini no mesmo editor?

Experimente: vim -o $(locate php.ini)

    
por 01.08.2012 / 10:04
0

Esse erro ocorre quando o vim é invocado e é conectado à saída do pipeline anterior, em vez do terminal e está recebendo diferentes entradas inesperadas (como as NULs). O mesmo acontece quando você executa: vim < /dev/null , então o comando reset neste caso ajuda. Isso é explicado bem pelo grawity no superusuário .

No Unix / OSX você pode usar o parâmetro xargs with -o , como:

locate php.ini | xargs -o vim

-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.

No Linux, tente a seguinte solução alternativa:

locate php.ini | xargs -J% sh -c 'vim < /dev/tty $@'

Como alternativa, use o GNU parallel em vez de xargs para forçar a alocação de tty, no exemplo:

locate php.ini | parallel -X --tty vi

Nota: parallel no Unix / OSX não funciona porque tem parâmetros diferentes e não suporta tty.

Muitos outros comandos populares também oferecem alocação pseudo-tty (como -t in ssh ), portanto, procure por ajuda.

Como alternativa, use find para passar os nomes dos arquivos para edição, portanto, não é necessário usar xargs , basta usar -exec , no exemplo:

find /etc -name php.ini -exec vim {} +
    
por 18.02.2015 / 13:59