Comment invoquer l'éditeur vim et la sortie de pipe vers bash

34

Parfois, je dois écrire du texte, puis rediriger ce texte dans une autre commande. Mon flux de travail habituel ressemble à ceci:

vim
# I edit and save my file as file.txt
cat file.txt | pandoc -o file.pdf # pandoc is an example 
rm file.txt

Je trouve cela lourd et cherchant à apprendre les scripts bash, je voudrais rendre le processus beaucoup plus simple en écrivant une commande qui déclenche l'ouverture d'un éditeur et lorsque l'éditeur se ferme, redirige la sortie de l'éditeur vers stdout. Ensuite, je serais en mesure d'exécuter la commande en tant que quickedit | pandoc -o file.pdf.

Je ne sais pas comment cela fonctionnerait. J'ai déjà écrit une fonction pour automatiser cela en suivant le flux de travail exact ci-dessus et quelques ajouts. Il génère une chaîne aléatoire pour agir comme un nom de fichier et la transmet à vim lorsque la fonction est invoquée. Lorsque l'utilisateur quitte vim en enregistrant le fichier, la fonction imprime le fichier sur la console, puis supprime le fichier.

function quickedit {
    filename="$(cat /dev/urandom | env LC_CTYPE=C tr -cd 'a-f0-9' | head -c 32)"
    vim $filename
    cat $filename
    rm $filename
}
# The problem:
# => Vim: Warning: Output is not to a terminal

Le problème que j'ai rapidement rencontré est que lorsque je fais quelque chose comme quickedit | commandvim lui-même, il ne peut pas être utilisé comme éditeur car toutes les sorties sont limitées au tuyau.

Je me demande s'il y a des solutions à cela, afin que je puisse diriger la sortie de ma quickeditfonction. L'alternative sous-optimale est de lancer un éditeur séparé, par exemple un texte sublime, mais je veux vraiment rester dans le terminal.

theideasmith
la source
Depuis vim, lancez la commande :w !pandoc -o file.pdf? (Remarque: l'espace entre wet !est essentiel.)
John1024
OK, c'est bien. Je ne savais pas que vous pouviez diriger la sortie de vim depuis vim lui-même. Cela sert mes objectifs, mais pour mes connaissances futures, est-il possible de résoudre mon problème exactement comment je voulais qu'il soit résolu?
theideasmith
Pouvez-vous publier votre fonction? Que voulez-vous dire lorsque vous parlez du problème que vous avez rapidement rencontré (avant-dernier paragraphe)? Je ne comprends pas.
Lucas
5
Soit dit en passant, vous devez l' utilisermktemp plutôt que de le réinventer de manière non sécurisée.
Wildcard
En tant que nouvel utilisateur bash, quels sont les dangers pour la sécurité de réinventer mktemp?
theideasmith

Réponses:

42

vipe est un programme pour éditer des pipelines:

command1 | vipe | command2

Vous obtenez un éditeur avec la sortie complète de command1, et lorsque vous quittez, le contenu est transmis command2via le canal.

Dans ce cas, il n'y a pas command1. Donc, vous pourriez faire:

: | vipe | pandoc -o foo.pdf

Ou:

vipe <&- | pandoc -o foo.pdf

vipereprend les variables EDITORet VISUAL, vous pouvez donc les utiliser pour ouvrir Vim.

Si vous ne l'avez pas installé, vipeest disponible dans le moreutilspackage; sudo apt-get install moreutils, ou quel que soit l'équivalent de votre saveur.

muru
la source
1
Pour les utilisateurs Mac qui sont arrivés ici: moreutilsest disponible dans Homebrew.
vergenzt
Pour les utilisateurs de FreeBSD: moreutilsest disponible pour être installé via pkg (8) .
Mateusz Piotrowski
20

Vous pouvez le faire depuis Vim:

:w !pandoc -o file.pdf

Ou même écrivez le tampon dans un pipeline complexe:

:w !grep pattern | somecommand > file.txt

Et puis vous pouvez quitter Vim sans enregistrer:

:q!

Cependant, compte tenu de votre cas d'utilisation spécifique, il existe probablement une meilleure solution en utilisant vicomme éditeur de ligne de commande. En supposant que vous utilisez bash:

set -o vi

Cela définit vos raccourcis clavier sur vi. Ainsi , vous pouvez modifier vos commandes à droite sur la ligne de commande avec base viraccourcis clavier en appuyant sur <Esc>, puis en tapant des vicommandes telles que x, cw, etc. (Vous pouvez revenir en mode d'insertion en appuyant sur i.)

Encore mieux et plus pertinent pour cette question, vous pouvez ouvrir Vim pour créer directement le contenu de votre ligne de commande. Tapez simplement <Esc>vet vous obtiendrez un tampon Vim vide. Lorsque vous enregistrez et quittez, c'est la commande sur votre ligne de commande et il est immédiatement exécuté. C'est beaucoup plus flexible que l'édition directe sur la ligne de commande car vous pouvez écrire un mini-script entier si vous le souhaitez.


Ainsi, par exemple, si vous souhaitez écrire du texte délicat et le canaliser immédiatement dans pandoc, vous pouvez simplement taper:

<Esc>v

Modifiez ensuite le tampon Vim jusqu'à ce que vous ayez quelque chose comme:

cat <<EOF | pandoc -o file.pdf
stuff for pandoc
more stuff for pandoc
EOF

Ensuite, enregistrez et quittez (avec :x) et le tout sera exécuté comme une commande shell.

Il sera également disponible dans l'historique des commandes de votre shell.

Wildcard
la source
1
Si vous préférez conserver les raccourcis clavier Emacs, vous pouvez toujours utiliser Vim pour modifier les lignes de commande en définissant la EDITORvariable d'environnement sur vimet en appuyant sur Ctrl-Xpuis en Ctrl-Emodifiant la ligne de commande.
Anthony G - justice pour Monica
18

Exécution dans un pipeline

Essayer:

quickedit() (  trap 'rm ~/temp$$' exit; vim ~/temp$$ >/dev/tty; cat ~/temp$$ )

La clé est que, pour pouvoir utiliser vimnormalement, vimstdout doit être le terminal. Nous accomplissons cela ici avec la redirection >/dev/tty.

Pour des raisons de sécurité, j'ai placé le fichier temporaire dans le répertoire personnel de l'utilisateur. Pour en savoir plus à ce sujet, consultez la question 062 de la FAQ de Greg . Cela élimine le besoin d'utiliser un nom de fichier obscur.

Exemple:

Lorsqu'il vims'ouvre, je tape This function succeeded.et enregistre le fichier. Le résultat à l'écran ressemble à:

$ quickedit | grep succeeded
This function succeeded.

Même si la sortie de quickeditest redirigée vers un pipeline, vimfonctionne toujours normalement car nous lui avons donné un accès direct à /dev/tty.

Exécuter un programme depuis vim

Comme je l'ai mentionné dans les commentaires, vim peut diriger un fichier vers une commande. Depuis vim, par exemple, exécutez la commande :w !pandoc -o file.pdf(Remarque: l'espace entre w et! Est essentiel).

John1024
la source
2
Bonne réponse. Celui-ci répond directement à la question de l'utilisateur, et propose une solution rapide et élégante: redirigez vim vers / dev / tty! Simple!
Mike S
J'utilise Zsh; trap '...' exitéchoue mais trap '...' EXITsemble fonctionner. Je ne sais pas grand chose sur le piégeage, mais mon approche générale pour les fichiers temporaires est d'utiliser mktmp [--suffix=...]. En outre, vim <outfile> -c '...' >/dev/ttys'exécute normalement jusqu'à ce que le fichier soit chargé, puis exécute la chaîne de commandes donnée, y compris :wqsi vous souhaitez ignorer la phase d'édition. J'ai également utilisé set | grep -a EXITet trouvé signals=(EXIT ... DEBUG).
John P
5

Assurez-vous qu'il vimest défini comme votre éditeur par défaut (par exemple export EDITOR=vimdans votre .bash_profileou .bashrc. Ensuite, à toute invite, vous pouvez taper Ctrl- Xsuivi de Ctrl- E. Cela ouvrira votre ligne de commande actuelle dans votre éditeur configuré (par exemple vim). Faites vos modifications, enregistrez et exit, et la commande sera exécutée comme si vous l'aviez tapée sur la ligne de commande, y compris les pipelines et autres.

DopeGhoti
la source