Aufrufen des VIM-Editors und der Pipe-Ausgabe für die Bash

34

Manchmal muss ich Text schreiben und diesen dann in einen anderen Befehl umleiten. Mein üblicher Workflow sieht ungefähr so ​​aus:

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

Ich finde das umständlich und versuche, Bash-Scripting zu lernen. Ich möchte den Prozess viel einfacher machen, indem ich einen Befehl schreibe, der einen Editor öffnet und wenn der Editor schließt, die Ausgabe des Editors an stdout weiterleitet. Dann könnte ich den Befehl als ausführen quickedit | pandoc -o file.pdf.

Ich bin mir nicht sicher, wie das funktionieren würde. Ich habe bereits eine Funktion zur Automatisierung dieses Vorgangs geschrieben, indem ich den oben beschriebenen exakten Arbeitsablauf sowie einige Ergänzungen befolgt habe. Es generiert eine zufällige Zeichenfolge, die als Dateiname fungiert, und übergibt diese beim Aufruf der Funktion an vim. Wenn der Benutzer vim durch Speichern der Datei beendet, druckt die Funktion die Datei auf der Konsole und löscht sie dann.

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

Das Problem, auf das ich bald gestoßen bin, ist, dass ich so etwas wie quickedit | commandvim selbst nicht als Editor verwenden kann, weil die gesamte Ausgabe auf die Pipe beschränkt ist.

Ich frage mich, ob es irgendwelche Problemumgehungen gibt, damit ich die Ausgabe meiner quickeditFunktion weiterleiten kann. Die suboptimale Alternative ist, einen separaten Editor zu starten, z. B. erhabenen Text, aber ich möchte wirklich im Terminal bleiben.

theideasmith
quelle
Geben Sie in vim den Befehl :w !pandoc -o file.pdf? (Hinweis: Der Abstand zwischen wund !ist von wesentlicher Bedeutung.)
John1024
Okay das ist super. Ich wusste nicht, dass Sie die Ausgabe von vim von vim aus leiten können. Dies dient meinen Zwecken, aber ist es für mein zukünftiges Wissen möglich, mein Problem genau so zu lösen, wie ich es gelöst haben wollte?
theideasmith
Können Sie Ihre Funktion posten? Was meinen Sie, wenn Sie über das Problem sprechen, auf das Sie bald gestoßen sind (vorletzter Absatz)? Ich verstehe das nicht.
Lucas
5
Abgesehen davon sollten Sie es verwenden,mktemp anstatt es unsicher neu zu erfinden.
Wildcard
Welche Sicherheitsrisiken birgt die Neuerfindung von mktemp für einen neuen Bash-Benutzer?
theideasmith

Antworten:

42

vipe ist ein Programm zum Bearbeiten von Pipelines:

command1 | vipe | command2

Sie erhalten einen Editor mit der vollständigen Ausgabe von command1und beim Verlassen werden die Inhalte command2über die Pipe weitergeleitet.

In diesem Fall gibt es keine command1. Sie könnten also Folgendes tun:

: | vipe | pandoc -o foo.pdf

Oder:

vipe <&- | pandoc -o foo.pdf

vipegreift die Variablen EDITORund auf VISUAL, sodass Sie sie zum Öffnen von Vim verwenden können.

Wenn Sie es nicht installiert haben, vipeist es im moreutilsPaket enthalten. sudo apt-get install moreutilsoder was auch immer Ihr Geschmacksäquivalent ist.

muru
quelle
1
Für Mac-Benutzer, die hier angekommen sind: moreutilsist in Homebrew verfügbar.
10.
Für FreeBSD-Benutzer: Kannmoreutils über pkg (8) installiert werden .
Mateusz Piotrowski
20

Sie können dies aus Vim heraus tun:

:w !pandoc -o file.pdf

Oder schreiben Sie den Puffer in eine komplexe Pipeline:

:w !grep pattern | somecommand > file.txt

Und dann können Sie Vim beenden, ohne zu speichern:

:q!

In Anbetracht Ihres speziellen Anwendungsfalls gibt es jedoch wahrscheinlich eine bessere Lösung, viwenn Sie als Befehlszeileneditor verwenden. Angenommen, Sie verwenden bash:

set -o vi

Hiermit setzen Sie Ihre Tastenkombinationen auf vi. So können Sie Ihre Befehle direkt auf der Kommandozeile mit grundlegenden bearbeiten vikeybindings durch Drücken <Esc>und dann die Eingabe - viBefehle wie x, cwetc. (Sie können durch Drücken in Insert - Modus zurück i.)

Noch besser und relevanter für diese Frage ist, dass Sie Vim öffnen können, um Ihren Befehlszeileninhalt direkt zu erstellen. Geben <Esc>vSie einfach ein und Sie erhalten einen leeren Vim-Puffer. Wenn Sie speichern und beenden, ist dies der Befehl in Ihrer Befehlszeile, der sofort ausgeführt wird. Dies ist viel flexibler als das direkte Bearbeiten über die Befehlszeile, da Sie ein ganzes Miniskript schreiben können, wenn Sie möchten.


Wenn Sie beispielsweise einen schwierigen Text schreiben und ihn sofort an pandoc weiterleiten möchten, können Sie einfach Folgendes eingeben:

<Esc>v

Bearbeiten Sie dann den Vim-Puffer, bis Sie ungefähr Folgendes haben:

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

Dann speichern und beenden (mit :x) und das Ganze wird als Shell-Befehl ausgeführt.

Es ist auch im Befehlsverlauf Ihrer Shell verfügbar.

Platzhalter
quelle
1
Wenn Sie die Emacs-Tastenzuordnungen beibehalten möchten, können Sie Vim weiterhin zum Bearbeiten von Befehlszeilen verwenden, indem Sie die EDITORUmgebungsvariable auf setzen vimund Ctrl-Xgefolgt von drücken, Ctrl-Ewährend Sie die Befehlszeile bearbeiten.
Anthony G - Gerechtigkeit für Monica
18

Laufen in einer Pipeline

Versuchen:

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

Der Schlüssel ist, dass, um vimnormal arbeiten zu können, vimstdout als Terminal benötigt wird. Das erreichen wir hier mit dem Redirect >/dev/tty.

Aus Sicherheitsgründen habe ich die temporäre Datei in das Ausgangsverzeichnis des Benutzers gestellt. Weitere Informationen hierzu finden Sie in Gregs FAQ, Frage 062 . Dadurch entfällt die Verwendung eines unklaren Dateinamens.

Beispiel:

Beim vimÖffnen gebe ich This function succeeded.die Datei ein und speichere sie. Das Ergebnis auf dem Bildschirm sieht folgendermaßen aus:

$ quickedit | grep succeeded
This function succeeded.

Auch wenn die Ausgabe von quickeditan eine Pipeline umgeleitet wird, vimfunktioniert sie normal, da wir direkten Zugriff darauf gewährt haben /dev/tty.

Ausführen eines Programms aus vim heraus

Wie ich in den Kommentaren erwähnt habe, kann vim eine Datei an einen Befehl weiterleiten. Geben Sie beispielsweise in vim den Befehl ein :w !pandoc -o file.pdf(Hinweis: Der Abstand zwischen w und! Ist von wesentlicher Bedeutung).

John1024
quelle
2
Gute Antwort. Dieser geht direkt auf die Frage des Benutzers ein und bietet eine schnelle und elegante Lösung: Leiten Sie vim nach / dev / tty um! Einfach!
Mike S
Ich benutze Zsh; trap '...' exitschlägt fehl, trap '...' EXITscheint aber zu funktionieren. Ich weiß nicht viel über Überfüllung, aber mein allgemeiner Ansatz für temporäre Dateien ist zu verwenden mktmp [--suffix=...]. Wird vim <outfile> -c '...' >/dev/ttywie gewohnt ausgeführt, bis die Datei geladen ist, und führt dann die angegebene Befehlskette aus, auch :wqwenn Sie die Bearbeitungsphase überspringen möchten. Ich habe auch verwendet set | grep -a EXITund gefunden signals=(EXIT ... DEBUG).
John P
5

Stellen Sie sicher, dass dies vimals Standardeditor festgelegt ist (z . B. export EDITOR=vimin Ihrem .bash_profileoder .bashrc. Dann können Sie an jeder Eingabeaufforderung Folgendes eingeben: Ctrl- Xgefolgt von Ctrl- E. Dadurch wird Ihre aktuelle Befehlszeile in Ihrem konfigurierten Editor geöffnet (z vim. B. ). Nehmen Sie Ihre Änderungen vor, speichern und exit, und der Befehl wird ausgeführt, als ob Sie ihn in der Befehlszeile eingegeben hätten, einschließlich Pipelines und dergleichen.

DopeGhoti
quelle