É possível canalizar comandos do vim para o vim?

18

Eu quero executar o seguinte shell.

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

Que eu esperava que canalizasse os pressionamentos de tecla w(avançar uma palavra) e depois e(final da palavra), depois a(anexar) e depois -this is the end of the second word(texto) no documento do Vim nomeado jque já possui palavras.

O seguinte erro ocorreu quando eu executei o script de shell.

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

Estou executando o Ubuntu 14.04. Dois tipos de respostas serão apreciados:

  1. Como usar a tubulação para alcançar o resultado desejado.
  2. Outro método pelo qual eu posso usar os "comandos Vim" (não os comandos ed ou sed) para editar um documento de texto a partir de um script de shell.
Jason Basanese
fonte
1
O |caractere canaliza a saída de um comando para outro. wea-thisnão é um comando. A tubulação também não pode ser usada para alcançar o que você deseja; fará com que o stdin do Vim seja o aplicativo à esquerda, não o teclado. Se você quiser se stdin em um buffer no vim, iniciá-lo com um sinal de menos para o filename: echo Hello, world! | vim -.
traço-tom-bang

Respostas:

15

Para inserir a string "hello"na primeira linha do arquivo j, você pode digitar em seu shell o seguinte comando:

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

  • :1 move o cursor para a primeira linha do buffer
  • :put! ='hello' cola a string "olá" acima da linha atual

Para inserir a sequência "hello"e, em seguida, salve e saia do arquivo:

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

Assim como antes, acabamos de adicionar o comando Ex :xque salva e sai.

Em geral, você pode executar qualquer sequência de comandos Ex em um arquivo, em um shell interativo ou em um script bash, como este:

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

Se você tiver muitos comandos Ex, poderá escrevê-los todos em um arquivo dedicado (chamado, por exemplo myExCommands.vim), um comando por linha e, a partir do shell ou de um script, poderá obtê-lo (com o comando Ex :sourceou a versão curta :so) como isso:

vim +'so myExCommands.vim' file

Editar

Vejo que você editou sua pergunta.
Acho que a resposta anterior ainda se aplica, porque você pode executar qualquer comando normal no modo Ex com os comandos Ex :normale :execute.

Por exemplo, digamos que você queira:

  • mova o cursor na primeira linha do buffer ( 1G)
  • mova o cursor para o primeiro caractere que não é um espaço em branco na linha ( _)
  • mova o cursor uma palavra para frente ( w)
  • mova o cursor para o final da nova palavra ( e)
  • entra no modo de inserção após o caractere sob o cursor ( a)
  • insira a string hello
  • salvar e sair ( :x)

Para fazer isso no arquivo j, digite no shell:

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

Para mais informações, veja:

:help +cmd
:help :normal
:help :execute
saginaw
fonte
Não consegui esclarecer completamente meu objetivo. Quero poder usar comandos do vims, como w para avançar uma palavra e tal. Vou editar minha pergunta para corrigir.
Jason Basanese
@JasonBasanese Eu editei minha resposta, execute os comandos Ex :normale :executefaça o que você deseja?
Saginaw
9

Aqui está uma maneira de usar comandos no modo normal, em vez de apenas comandos ex, para editar um fluxo apresentado ao Vim a partir do stdin. Este não é um exemplo muito útil, mas ilustra as técnicas envolvidas. Assume que seu shell é uma festança.

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

O -no final diz ao Vim para ler texto (não comandos) do stdin. O -scomando diz ao Vim para executar pressionamentos de teclas do arquivo especificado. Nesse caso, o arquivo é a saída de uma substituição do processo bash. O <(...)é substituído pelo nome de um pipe nomeado. A saída do pipe é a saída do comando entre parênteses. O wcwred\emove o cursor por uma palavra e altera a próxima palavra para red. O :wq! foo\nresultado é salvo no arquivo, foomesmo que ele já exista. O resultado final é um arquivo chamado foocontendo o textoThe red fox jumped.

Para mais informações sobre alguns desses tópicos, consulte

:help -file
:help -s

Veja também a Process Substitutionseção da bash(1)página de manual.

garyjohn
fonte
Adicionado ao meu ~ / .zshrc: vimx () { vi -s <(echo "$1"':wq') "$2" &> /dev/null; }. Agora eu posso vimx 'iThe brow fox jumped.\e' foo; vimx 'wcwred\efjdwiclimbed\e' foo; cat foo. Arrumado!
21318 Leonard Pauli
4

Eu achei o método de pegar a saída de um programa redirecionado do sub-shell para ser muito fácil:

vim <( program )

Exemplo:

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

Eu tinha exatamente o mesmo desejo que você: queria escrever comandos vim normais e fazer com que eles editassem um fluxo de pipeline. Fiquei desapontado com a dificuldade de usar o vim normal dessa maneira (tantas bandeiras!), Conforme fornecido pelas opções padrão do vim.

Portanto, escrevi um pequeno invólucro no vim para fazê-lo: https://github.com/MilesCranmer/vim-stream/ . É chamado vims.

O coração do wrapper é o seguinte comando:

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

Usando isso, com a geração de comandos que eu faço, parece bastante conciso e, como o vim é um editor modal, vimscriei um editor de fluxo modal. Existem três modos principais que são úteis para a mentalidade de edição 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

Vê isto:

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

Então, evai para o final de Helloe acomeça a acrescentar.

Algo mais sofisticado, no modo exe, para comentar as linhas que contêm my_bad_vare excluir a linha anterior.

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

O que se traduz em vims '%g/my_bad_var/exe "norm I//\<esc>kdd"'- Isendo o comando para iniciar a inserção no início da linha e //sendo a sequência de comentários. \<esc>kddpressiona a tecla Escape, move uma linha para cima e exclui a linha.

Eu tenho 11 exemplos no total do repositório. Convido você a vê-los. Novamente, isso está sendo executado no topo do vim, é apenas uma maneira de tornar o vim mais parecido com o sed para entrada de fluxo (mas preservando todas as suas amadas macros do vim!)

Milhas
fonte
3

Essa é uma pergunta bastante antiga, mas achei que valia a pena contribuir para o fato de que, se a sua distribuição / SO tiver acesso moreutils, você poderá instalá-la e simplesmente usá-la vipecomo complemento padrão para vim:

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

moreutilstambém é super útil para outras ferramentas, e eu as recomendo se você for um usuário sério da linha de comando! :) Veja a introdução do autor (link anterior) para mais detalhes.

moreutilsgeralmente deve estar disponível para a maioria das distribuições do tipo * nix por meio de um gerenciador de pacotes e pelo Homebrew no Mac . Por exemplo...

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


# Mac OS and Homebrew
brew install moreutils

moreutilstambém faz parte do repositório de pacotes MSYS2 , para que você também possa usá-lo tecnicamente no Windows. :)

Erich Gubler
fonte