Est-il possible de diriger les commandes vim vers vim?

18

Je veux exécuter le shell suivant.

wea-this is the end of the second word | vim j
exit 0

Ce que j'avais espéré dirigerait les touches w(avancer d'un mot) puis e(fin du mot) puis a(ajouter) puis -this is the end of the second word(texte) vers le document Vim nommé jqui contient déjà des mots.

L'erreur suivante s'est produite lorsque j'ai exécuté le script shell.

/root/bin/tt.sh: line 1: wea-this: command not found
Vim: Warning: Input is not from a terminal

J'utilise Ubuntu 14.04. Deux types de réponses seront appréciées:

  1. Comment utiliser la tuyauterie pour obtenir ce résultat souhaité.
  2. Une autre méthode par laquelle je peux utiliser des "commandes Vim" (pas des commandes ed ou sed) pour éditer un document texte à partir d'un script shell.
Jason Basanese
la source
1
Le |personnage dirige la sortie d'une commande vers une autre. wea-thisn'est pas une commande. La tuyauterie ne peut pas non plus être utilisée pour réaliser ce que vous cherchez à faire; cela fera que stdin de Vim soit l'application de gauche, pas le clavier. Si vous voulez vous stdin dans un tampon vim, commencez avec un moins pour le nom du fichier: echo Hello, world! | vim -.
dash-tom-bang

Réponses:

15

Pour insérer la chaîne "hello"sur la première ligne du fichier j, vous pouvez taper dans votre shell la commande suivante:

vim +"1 | put! ='hello'" j

  • :1 déplace le curseur sur la première ligne du tampon
  • :put! ='hello' colle la chaîne "bonjour" au-dessus de la ligne actuelle

Pour insérer la chaîne "hello", puis enregistrer et quitter le fichier:

vim +"1 | put! ='hello' | x" j

Même chose qu'avant, nous venons d'ajouter la commande Ex :xqui enregistre et quitte.

Plus généralement, vous pouvez exécuter n'importe quelle séquence de commandes Ex sur un fichier, à partir d'un shell interactif ou d'un script bash, comme ceci:

vim +'Ex command1 | Ex command2 | ...' file

Si vous avez beaucoup de commandes Ex, vous pouvez toutes les écrire dans un fichier dédié (appelé par exemple myExCommands.vim), une commande par ligne, puis à partir du shell ou d'un script, vous pouvez la source (avec la commande Ex :sourceou la version courte :so) comme ça:

vim +'so myExCommands.vim' file

Éditer

Je vois que vous avez modifié votre question.
Je pense que la réponse précédente s'applique toujours, car vous pouvez exécuter n'importe quelle commande normale du mode Ex avec les commandes Ex :normalet :execute.

Par exemple, supposons que vous souhaitiez:

  • déplacez votre curseur sur la première ligne du tampon ( 1G)
  • déplacez votre curseur sur le premier caractère non blanc sur la ligne ( _)
  • déplacez votre curseur d'un mot vers l'avant ( w)
  • déplacez votre curseur à la fin du nouveau mot ( e)
  • passer en mode insertion après le caractère sous le curseur ( a)
  • insérer la chaîne hello
  • enregistrer et quitter ( :x)

Pour ce faire sur le fichier j, tapez à partir du shell:

vim +"execute 'normal! 1G_weahello' | x" j

Pour plus d'informations, voir:

:help +cmd
:help :normal
:help :execute
saginaw
la source
Je n'ai pas réussi à clarifier complètement mon objectif. Je veux pouvoir utiliser les commandes vims, telles que w pour avancer un mot, etc. Je vais modifier ma question pour la corriger.
Jason Basanese
@JasonBasanese J'ai édité ma réponse, fais les commandes Ex :normalet :executefais ce que tu veux?
saginaw
9

Voici un moyen d'utiliser des commandes en mode normal, plutôt que simplement des commandes ex, pour éditer un flux présenté à Vim depuis stdin. Ce n'est pas un exemple très utile, mais il illustre les techniques impliquées. Cela suppose que votre shell est bash.

echo "The brown fox jumped." | vim -s <(printf 'wcwred\e:wq! foo\n') -

Le -à la fin indique à Vim de lire le texte (pas les commandes) de stdin. Le -sdit à Vim d'exécuter les frappes à partir du fichier spécifié. Dans ce cas, le fichier est la sortie d'une substitution de processus bash. Le <(...)est remplacé par le nom d'un canal nommé. La sortie du tuyau est la sortie de la commande entre parenthèses. Le wcwred\edéplace le curseur d'un mot et change le mot suivant en red. Le :wq! foo\nenregistre le résultat dans le fichier foomême si ce fichier existe déjà. Le résultat final est un fichier nommé foocontenant le texteThe red fox jumped.

Pour en savoir plus sur certains de ces sujets, voir

:help -file
:help -s

Voir aussi la Process Substitutionsection de la bash(1)page de manuel.

garyjohn
la source
Ajouté à mes ~ / .zshrc: vimx () { vi -s <(echo "$1"':wq') "$2" &> /dev/null; }. Maintenant je peux vimx 'iThe brow fox jumped.\e' foo; vimx 'wcwred\efjdwiclimbed\e' foo; cat foo. Soigné!
Leonard Pauli
4

J'ai trouvé la méthode pour prendre la sortie d'un programme comme redirigé depuis le sous-shell pour être très facile:

vim <( program )

Exemple:

 vim <( grep -nH  hello  myFile.cpp )
 vim <( find . -name '*.cpp' -exec grep -nH code_expr {} \+ )
J Jorgenson
la source
4

J'avais exactement le même désir que vous: je voulais écrire des commandes vim normales et les faire éditer un flux de pipeline. J'ai été déçu par la difficulté d'utiliser vim normal de cette manière (autant de drapeaux!), Comme le fournissent les options par défaut de vim.

Par conséquent, j'ai écrit un petit wrapper sur vim pour le faire: https://github.com/MilesCranmer/vim-stream/ . Ça s'appelle vims.

Le cœur de l'encapsuleur est la commande suivante:

vim - -nes "${vim_cmds[@]}" -c ':q!' | tail -n +2

En utilisant cela, avec la génération de commandes que je fais, cela semble assez concis, et parce que vim est un éditeur modal, j'ai créé vimsun éditeur de flux modal. Il existe trois modes principaux utiles pour la mentalité d'édition de pipeline:

[-t|--turn-off-mode] - (Default mode)
                       Every string is a vim command line, e.g., '%g/foo/d' deletes
                       all lines with foo.
[-e|--exe-mode] -      Translated to '%g/$1/exe "norm $2"', see examples below
[-s|--simple-mode] -   Like exe-mode, but runs on 1st line only

Regarde ça:

$ echo "Hello World" | vims -s "ea Beautiful"
Hello Beautiful World

Alors, eva à la fin de Hello, puis acommence à s'ajouter.

Quelque chose de plus sophistiqué, en mode exe, pour commenter les lignes contenant my_bad_varet supprimer la ligne précédente.

cat my_script.cpp | vims -e 'my_bad_var' 'I//\<esc>kdd'

Ce qui se traduit par vims '%g/my_bad_var/exe "norm I//\<esc>kdd"'- Iêtre la commande pour démarrer l'insertion au début de la ligne, et //être la séquence de commentaires. \<esc>kddappuie sur la touche d'échappement, monte d'une ligne, puis supprime la ligne.

J'ai 11 exemples au total sur le repo, je vous encourage à les vérifier. Encore une fois, cela fonctionne au-dessus de vim, c'est juste un moyen de rendre vim plus semblable à sed pour l'entrée de flux (mais en préservant toutes vos macros vim bien-aimées!)

Miles
la source
3

C'est une question assez ancienne, mais j'ai senti qu'il valait la peine de contribuer que si votre distribution / OS donnée a accès à moreutils, vous pouvez l'installer et simplement l'utiliser vipecomme ajout standard à vim:

echo foo | vipe # Now you can edit "foo" to be "bar"!

moreutilsest également très pratique pour ses autres outils, et je les recommande fortement si vous êtes un utilisateur sérieux de la ligne de commande! :) Jetez un œil à l'introduction de l'auteur (lien précédent) pour plus de détails.

moreutilsdevrait être généralement disponible pour la plupart des distributions de type * nix via un gestionnaire de paquets et via Homebrew sur Mac . Par exemple...

# Arch Linux and MSYS2 (more below) as part of the `community` repo
pacman -Sy moreutils


# Mac OS and Homebrew
brew install moreutils

moreutilsfait également partie du référentiel de packages MSYS2 , vous pouvez donc également l'utiliser techniquement sous Windows. :)

Erich Gubler
la source