Comment modifier le contenu de l'entrée standard?

15

Je voudrais éditer du contenu dans vim qui a été généré dynamiquement à partir de la ligne de commande sans avoir encore le fichier.

Par exemple:

$ echo This is example. | vim /dev/stdin
$ cat /etc/hosts | vim /dev/stdin

mais il échoue avec les erreurs:

Vim: Avertissement: l'entrée ne provient pas d'un terminal

Vim: Erreur lors de la lecture de l'entrée, de la sortie ...

Est-il possible d'y parvenir?

Kenorb
la source
:help stdin... C'est incroyable à quelle vitesse on peut trouver les réponses en posant leur question sur la documentation intégrée.
dash-tom-bang

Réponses:

24

Vous devez utiliser -à la place du nom de fichier sur la ligne de commande:

echo This is example. | vim -

La commande ci-dessus ouvrira un tampon sans nom rempli avec le texte lu à partir de l'entrée standard.

toro2k
la source
7
L'utilisation d'un -for stdin est à peu près standard pour les outils de ligne de commande;
Martin Tournoij
6

C'est surtout une note amusante sur bashet readline, mais si vous définissez votre EDITORvariable d'environnement sur vim, appuyer sur Ctrl+ x+ eouvrira la ligne actuelle vim. De plus, si vous tapez Meta(Alt/Opt/Esc)+ Ctrl+ e, bash effectuera une expansion sur place sur la ligne de commande actuelle, c'est-à-dire:

$ echo $EDITOR # Assuming EDITOR was set

avec Meta(Alt/Opt/Esc)+ Ctrl+ edeviendrait

$ echo vim # Assuming EDITOR was set

avec Ctrl+ x+ edeviendrait

1 echo vim # Assuming EDITOR was set
~
~
/tmp/sometmpbufferfile

Notez qu'à la fermeture de vim, le contenu du tampon vim est exécuté sur la ligne de commande.

Ces fonctionnalités deviennent très utiles pour moi lorsque je souhaite exécuter des commandes multi-lignes en bash, comme pour les boucles ou les programmes nécessitant des instructions ici, et fournissent un moyen intéressant de sauvegarder un peu de l'historique de la ligne de commande dans un fichier pour une utilisation ultérieure.

Donc, pour répondre à la question d'origine, vous pouvez également écrire,

$ This is an example

puis appuyez sur Ctrl+ x+ epour le charger vim. Vous pourriez aussi avoir,

 $ $(cat /etc/hosts)

et faites Meta(Alt/Opt/Esc)+ Ctrl+ epuis Ctrl+ x+ e, ce qui mettrait tous les fichiers d'hôtes sur une seule ligne et le chargerait vim(probablement pas la meilleure utilisation de ces fonctionnalités - cependant, l'utilité de ces méthodes peut être extrapolée à partir des quelques exemples discutés ici).

Notez que je suppose que votre readlineest réglé sur emacsmode. Si votre readlineest défini sur vimmode, vous pouvez facilement découvrir les liaisons pertinentes en utilisant la commande:

bind -p

et la recherche de edit-and-execute-commandou shell-expand-line, qui étaient respectivement associées aux liaisons Ctrl+ x+ eet Meta(Alt/Opt/Esc)+ Ctrl+ e.

HAL 9001
la source
Vous pouvez dire à bash d'utiliser les liaisons de touches vi au lieu d'emacs. Utilisez set -o vipour l'activer. Ensuite, vous pouvez simplement utiliser le vmappage en mode normal pour modifier la commande actuelle dans votre éditeur.
Quincy Bowers, le
1
Bien sûr, c'est une excellente astuce pour modifier la ligne de commande à l'aide de vi, mais il y a au moins deux problèmes en utilisant cette méthode pour lire le texte de stdin: 1. shell-expand-linesupprimer les retours à la ligne du texte développé et 2. edit-and-execute-commandessayer d'exécuter la commande écrite dans le tampon , quoi qu'il soit enregistré ou non, lorsque vous quittez vi.
toro2k
Woah, c'est génial. J'apprends une nouvelle chose au sujet de readline tous les jours, il semble ...
Poignée de porte
2

En bash, j'ai trouvé utile d'utiliser la substitution de processus en utilisant la <(command)syntaxe, par exemple:

vim <(echo This is example.)
vim <(cat /etc/hosts)

Voir également:

Kenorb
la source
4
Notez que cela ne fonctionnera pas dans tous les shells. Je pense qu'il ne fonctionnera que dans bashet zsh(et non sh, ksh, dash, fish, csh, tcsh, etc.)
Martin Tournoij
@Carpetsmoker Devrait fonctionner dans ksh88 et supérieur, je pense, mais oui, la substitution de processus n'est pas POSIX.
muru
4
Et faites attention à ne pas vous tromper! Lorsque vous démarrez Vim de cette façon, il ouvre un tampon pour un fichier comme /proc/PID/fd/FD. Si vous écrivez le tampon et quittez, Vim ne se plaint pas, mais le fichier dans lequel vous avez écrit sera supprimé par le système d'exploitation. En utilisant -comme nom de fichier, le tampon ouvert n'a aucun fichier associé, donc si vous essayez de quitter sans (tant que vous n'utilisez pas de commande bang ou similaire) enregistrer Vim vous avertira.
toro2k
1
C'est bien car ça se généralise bien vimdiff <(echo foo) <(echo bar).
wchargin
@ toro2k Pour le suivi, il semble utiliser :nextet :prevrelire le flux et n'obtient rien. Il convient également de mentionner que les processus ne sont pas parallèles les uns aux autres - par exemple, cat <(sleep 3; echo a) <(echo b)imprime dans l'ordre - et pendant que les catentrelacements écrivent et lisent, vimattend le fichier pour "terminer la lecture" avant d'afficher tout sauf le cadre extérieur.
John P
-1

Si l'utilisation d'un pipeline vers un nouveau Vim n'est pas une exigence, vous pouvez utiliser la capacité de Vim à extraire la sortie des commandes dans le tampon actuel, couplée à un tampon non sauvegardé (comme avec :newou à la modification d'un fichier inexistant)

:read!cat /etc/hosts en mode commande placera la sortie dans votre tampon actuel en dessous de la position actuelle du curseur.

En plus d'avoir à supprimer la première ligne vide qui reste lorsque cela est fait sur un tampon vide, cela fonctionne bien et est particulièrement pratique si Vim est déjà en cours d'exécution.

ewatt
la source
1
Comment cela répond-il à la question?
muru
Il prend la sortie de la commande et la met dans vim.
ewatt