web-dev-qa-db-fra.com

Invoquer vi via find | xargs casse mon terminal. Pourquoi?

Lors de l'appel de vim à find | xargs, procédez comme suit:

find . -name "*.txt" | xargs vim

vous recevez un avertissement à propos de

Input is not from a terminal

et un terminal avec un comportement à peu près cassé par la suite. Pourquoi donc?

135
DevSolar

Lorsque vous appelez un programme via xargs, le stdin (entrée standard) du programme pointe sur /dev/null. (Puisque xargs ne connait pas le original stdin, c'est la meilleure chose à faire.)

 $ 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 s'attend à ce que son stdin soit identique à son terminal de contrôle et exécute diverses opérations relatives au terminal ioctl est sur stdin directement. Lorsque cela est fait sur /dev/null (ou tout descripteur de fichier non-tty), ces ioctls n'ont pas de sens et renvoient ENOTTY, ce qui est ignoré silencieusement.

  • À mon avis, une cause plus spécifique: Au démarrage, Vim lit et retient les anciens paramètres du terminal, puis les restaure à la sortie. Dans notre cas, lorsque les "anciens paramètres" sont demandés pour un descripteur de fichier non-tty, Vim reçoit toutes les valeurs vides et toutes les options désactivées, et définit négligemment la même chose sur votre terminal.

    Vous pouvez le voir en exécutant vim < /dev/null, en le quittant, puis en exécutant stty, qui générera un grand nombre de <undef>s. Sous Linux, exécuter stty sane rendra le terminal utilisable à nouveau (bien que aura perdu des options telles que iutf8, ce qui pourrait causer des ennuis mineurs. plus tard).

Vous pourriez considérer cela comme un bogue dans Vim, car il peut ouvrir /dev/tty pour le contrôle terminal, mais ne le fait pas. (À un moment donné au cours du démarrage, Vim duplique son stderr sur stdin, ce qui lui permet de lire vos commandes d'entrée - à partir d'un fd ouvert en écriture - mais même cela n'est pas fait assez tôt.)

93
grawity

Suite à la réponse de grawity, xargs points stdin à /dev/null


De OSX/BSD man xargs

 - o Rouvrez stdin en tant que/dev/tty dans le processus enfant 
 avant d'exécuter la commande. Ceci est utile 
 Si vous voulez que xargs exécute une application interactive. 

Ainsi, la ligne de code suivante devrait fonctionner pour vous:

trouver . -name "* .txt" | xargs -o vim

Pour GNU man xargs, il n'y a pas d'indicateur, mais nous pouvons explicitement passer dans/dev/tty pour résoudre le problème:

trouver . -name "* .txt" | xargs bash -c '</ dev/tty vim "$ @"' ignoreme

l'ignoreme est là pour prendre $ 0, donc $ @ est tous les arguments de xargs

132
James McGuigan

Le moyen le plus simple:

vim $(find . -name "*foo*")
31
trolol

Cela devrait fonctionner correctement si vous utilisez l'option -exec sur find plutôt que de vous connecter à xargs.

find . -type f -name filename.txt -exec vi {} + 
20
Chris Wraith

Utilisez GNU Parallel à la place:

find . -name "*.txt" | parallel -j1 --tty vim

Ou si vous voulez ouvrir tous les fichiers en une fois:

find . -name "*.txt" | parallel -Xj1 --tty vim

Il traite même correctement les noms de fichiers tels que:

My brother's 12" records.txt

Regardez la vidéo d'introduction pour en savoir plus: http://www.youtube.com/watch?v=OpaiGYxkSuQ

8
Ole Tange

peut-être pas le meilleur mais voici le script que j'utilise (nommé vim-open):

#!/usr/bin/env Ruby

require 'shellwords'

inputs = (ARGV + (STDIN.tty? ? [] : STDIN.to_a)).map(&:strip)
exec("</dev/tty vim #{inputs.flatten.shelljoin}")

fonctionnera avec vim-open a b c et ls | vim-open par exemple

0
localhostdotdev