Ist es möglich, vim-Befehle an vim weiterzuleiten?

18

Ich möchte die folgende Shell ausführen.

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

Was ich gehofft hatte, würde die Tastenanschläge w(vorwärts bewegen eines Wortes) dann e(Ende des Wortes) dann a(anhängen) dann -this is the end of the second word(Text) an das genannte Vim-Dokument leiten, jdas bereits Wörter enthält.

Der folgende Fehler ist aufgetreten, als ich das Shell-Skript ausgeführt habe.

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

Ich verwende Ubuntu 14.04. Zwei Arten von Antworten werden geschätzt:

  1. Verwendung von Rohrleitungen, um dieses gewünschte Ergebnis zu erzielen.
  2. Eine andere Methode, mit der ich "Vim-Befehle" (keine ed- oder sed-Befehle) verwenden kann, um ein Textdokument aus einem Shell-Skript heraus zu bearbeiten.
Jason Basanese
quelle
1
Das |Zeichen leitet die Ausgabe eines Befehls an einen anderen weiter. wea-thisist kein Befehl. Piping kann nicht verwendet werden, um das zu erreichen, was Sie tun möchten. Dies führt dazu, dass Vims Standard die Anwendung für die linke Hand ist, nicht die Tastatur. Wenn Sie in einen Puffer in vim erhalten stdin wollen, starten Sie es mit einem Minus für die Dateinamen: echo Hello, world! | vim -.
Dash-Tom-Bang

Antworten:

15

Um die Zeichenfolge "hello"in die erste Zeile der Datei einzufügen j, können Sie den folgenden Befehl in Ihre Shell eingeben:

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

  • :1 Bewegt den Cursor in die erste Zeile des Puffers
  • :put! ='hello' Fügt die Zeichenfolge "Hallo" über der aktuellen Zeile ein

So fügen Sie die Zeichenfolge ein "hello"und speichern und beenden die Datei:

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

Wie zuvor haben wir gerade den Ex-Befehl hinzugefügt, der :xspeichert und beendet.

Im Allgemeinen können Sie eine beliebige Folge von Ex-Befehlen für eine Datei, eine interaktive Shell oder ein Bash-Skript wie folgt ausführen:

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

Wenn Sie viele Ex-Befehle haben, können Sie sie alle in eine dedizierte Datei schreiben (beispielsweise myExCommands.vimeinen Befehl pro Zeile) und sie dann über die Shell oder ein Skript (mit dem Ex-Befehl :sourceoder der Kurzversion) ausgeben :so) so was:

vim +'so myExCommands.vim' file

Bearbeiten

Wie ich sehe, haben Sie Ihre Frage bearbeitet.
Ich denke, die vorherige Antwort gilt immer noch, weil Sie jeden normalen Befehl aus dem Ex-Modus mit den Ex-Befehlen :normalund ausführen können :execute.

Angenommen, Sie möchten:

  • Bewegen Sie den Cursor in die erste Zeile des Puffers ( 1G)
  • Bewegen Sie den Cursor zum ersten Nicht-Leerzeichen in der Zeile ( _)
  • Bewegen Sie den Cursor ein Wort vorwärts ( w)
  • Bewegen Sie den Cursor an das Ende des neuen Wortes ( e)
  • gehe in den Einfügemodus nach dem Zeichen unter dem Cursor ( a)
  • füge die Zeichenkette ein hello
  • speichern und beenden ( :x)

Geben Sie dazu in der Datei jFolgendes in die Shell ein:

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

Weitere Informationen finden Sie unter:

:help +cmd
:help :normal
:help :execute
saginaw
quelle
Ich habe mein Ziel nicht vollständig geklärt. Ich möchte in der Lage sein, vims-Befehle zu verwenden, wie z. B. w, um ein Wort vorwärts zu bewegen, und so weiter. Ich werde meine Frage zur Korrektur bearbeiten.
Jason Basanese
@JasonBasanese Ich habe meine Antwort bearbeitet, mache die Ex-Befehle :normalund :executemache was du willst?
Saginaw
9

Hier ist eine Möglichkeit, einen Stream, der Vim von stdin präsentiert wird, nicht nur mit ex-Befehlen, sondern mit Befehlen im normalen Modus zu bearbeiten. Dies ist kein sehr nützliches Beispiel, aber es veranschaulicht die beteiligten Techniken. Es wird davon ausgegangen, dass Ihre Shell bash ist.

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

Das -am Ende weist Vim an, Text (nicht Befehle) von stdin zu lesen. Das -sweist Vim an, Tastatureingaben aus der angegebenen Datei auszuführen. In diesem Fall ist die Datei die Ausgabe einer Bash-Prozessersetzung. Das <(...)wird durch den Namen einer Named Pipe ersetzt. Die Ausgabe der Pipe ist die Ausgabe des Befehls in Klammern. Das wcwred\ebewegt den Cursor um ein Wort und ändert das nächste Wort in red. Das :wq! foo\nspeichert das Ergebnis in die Datei fooselbst wenn die Datei bereits vorhanden. Das Endergebnis ist eine Datei foomit dem Namen, die den Text enthältThe red fox jumped.

Weitere Informationen zu einigen dieser Themen finden Sie unter

:help -file
:help -s

Siehe auch den Process SubstitutionAbschnitt der bash(1)Manpage.

garyjohn
quelle
Hinzu kommt meine ~ / .zshrc: vimx () { vi -s <(echo "$1"':wq') "$2" &> /dev/null; }. Jetzt kann ich vimx 'iThe brow fox jumped.\e' foo; vimx 'wcwred\efjdwiclimbed\e' foo; cat foo. Ordentlich!
Leonard Pauli
4

Ich fand die Methode, die Ausgabe eines Programms als von der Sub-Shell umgeleitet zu betrachten, sehr einfach:

vim <( program )

Beispiel:

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

Ich hatte genau den gleichen Wunsch wie Sie: Ich wollte normale vim-Befehle schreiben und diese einen Pipeline-Stream bearbeiten lassen. Ich war enttäuscht über die Schwierigkeit, normales Vim auf diese Weise zu verwenden (so viele Flags!), Wie es die vim-Standardoptionen bieten.

Deshalb habe ich auf vim einen kleinen Wrapper geschrieben: https://github.com/MilesCranmer/vim-stream/ . Es heißt vims.

Das Herzstück des Wrappers ist der folgende Befehl:

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

Wenn ich das benutze, funktioniert es bei der Befehlsgenerierung ziemlich präzise, ​​und da vim ein Modal-Editor ist, habe ich vimseinen Modal-Stream-Editor erstellt. Es gibt drei Hauptmodi, die für das Bearbeiten von Pipelines nützlich sind:

[-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

Schau dir das an:

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

Geht also ezum Ende Hellound afängt dann an anzuhängen.

Etwas ausgefalleneres im Exe-Modus, um Zeilen mit dem Inhalt zu kommentieren my_bad_varund die vorhergehende Zeile zu löschen.

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

Das heißt vims '%g/my_bad_var/exe "norm I//\<esc>kdd"'- der IBefehl zum Starten des Einfügens am Zeilenanfang und //die Kommentarsequenz. \<esc>kdddrückt die Escape-Taste, rückt eine Zeile nach oben und löscht die Zeile.

Ich habe insgesamt 11 Beispiele auf dem Repo. Ich ermutige Sie, sie zu überprüfen. Auch dies läuft auf vim, es ist nur eine Möglichkeit, vim für Streaming-Eingaben ähnlicher zu machen (aber all Ihre geliebten vim-Makros zu erhalten!)

Meilen
quelle
3

Dies ist eine ziemlich alte Frage, aber ich war der Meinung, dass es sich lohnt, dazu beizutragen, dass moreutilsSie sie installieren und einfach vipeals Standardzusatz verwenden können, um vim:

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

moreutilsist auch für seine anderen Tools sehr praktisch und ich würde sie wärmstens empfehlen, wenn Sie ein ernsthafter Kommandozeilenbenutzer sind! :) Weitere Informationen finden Sie in der Einführung des Autors (vorheriger Link).

moreutilssollte für die meisten * nix-ähnlichen Distributionen generell über einen Paketmanager und über Homebrew auf dem Mac verfügbar sein . Beispielsweise...

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


# Mac OS and Homebrew
brew install moreutils

moreutilsist auch Teil des MSYS2-Paket-Repositorys , sodass Sie es technisch auch unter Windows verwenden können. :)

Erich Gubler
quelle