Come invocare l'editor vim e l'output di pipe a bash


34

A volte ho bisogno di scrivere del testo e quindi reindirizzarlo in un altro comando. Il mio solito flusso di lavoro va in questo modo:

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

Lo trovo ingombrante e sto cercando di imparare lo script bash Mi piacerebbe rendere il processo molto più semplice scrivendo un comando che apre un editor e quando l'editor chiude il pipe dell'output dell'editor su stdout. Quindi sarei in grado di eseguire il comando come quickedit | pandoc -o file.pdf.

Non sono sicuro di come funzionerebbe. Ho già scritto una funzione per automatizzare questo seguendo il flusso di lavoro esatto sopra più alcune aggiunte. Genera una stringa casuale che funge da nome file e la passa a VIM quando viene invocata la funzione. Quando l'utente esce da vim salvando il file, la funzione stampa il file sulla console e quindi elimina il file.

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

Il problema che ho riscontrato presto è che quando faccio qualcosa come quickedit | commandVim stesso non può essere usato come editor perché tutto l'output è vincolato alla pipe.

Mi chiedo se ci sono soluzioni alternative a questo, in modo da poter convogliare l'output della mia quickeditfunzione. L'alternativa non ottimale è quella di avviare un editor separato, diciamo testo sublime, ma voglio davvero rimanere nel terminale.


Dall'interno di VIM, emettere il comando :w !pandoc -o file.pdf? (Nota: lo spazio tra wed !è essenziale.)
Giovanni 1024

D'accordo va benissimo. Non sapevo che si potesse convogliare l'output di VIM dall'interno di VIM stesso. Questo serve ai miei scopi, ma per le mie conoscenze future, è possibile risolvere il mio problema esattamente come intendevo risolverlo?
theideasmith

Puoi pubblicare la tua funzione? Cosa intendi quando parli del problema che hai riscontrato presto (secondo ultimo paragrafo)? Non capisco.
Lucas,

5
A parte questo, dovresti usarlomktemp piuttosto che reinventarlo in modo insicuro.
Carattere jolly

Come nuovo utente bash, quali sono i pericoli per la sicurezza di reinventare mktemp?
theideasmith

Risposte:


42

vipe è un programma per la modifica di pipeline:

command1 | vipe | command2

Si ottiene un editor con l'output completo di command1e quando si esce, il contenuto viene passato command2tramite la pipe.

In questo caso, non c'è command1. Quindi, potresti fare:

: | vipe | pandoc -o foo.pdf

O:

vipe <&- | pandoc -o foo.pdf

viperaccoglie le variabili EDITORe VISUAL, in modo da poterle usare per aprire Vim.

Se non lo hai installato, vipeè disponibile nel moreutilspacchetto; sudo apt-get install moreutilso qualunque sia l'equivalente del tuo sapore.


1
Per utenti Mac arrivati ​​qui: moreutilsè disponibile in Homebrew.
vergenzt,

Per gli utenti di FreeBSD: moreutilsè disponibile per l'installazione tramite pkg (8) .
Mateusz Piotrowski

20

Puoi farlo da Vim:

:w !pandoc -o file.pdf

O addirittura scrivere il buffer in una pipeline complessa:

:w !grep pattern | somecommand > file.txt

E poi puoi uscire da Vim senza salvare:

:q!

Tuttavia, considerando il tuo caso d'uso specifico, esiste probabilmente una soluzione migliore usando vicome editor della riga di comando. Supponendo che tu usi bash:

set -o vi

Questo imposta le tue combinazioni di tasti su vi. Quindi è possibile modificare i comandi proprio sulla riga di comando con base vicombinazioni di tasti premendo <Esc>e quindi digitando vicomandi come x, cwe così via (è possibile tornare in modalità di inserimento premendo i.)

Ancora meglio e più pertinente a questa domanda, puoi aprire Vim per creare direttamente il contenuto della tua riga di comando. Basta digitare <Esc>ve otterrai un buffer Vim vuoto. Quando salvi ed esci, quello è il comando sulla tua riga di comando e viene immediatamente eseguito. Questo è molto più flessibile della modifica direttamente dalla riga di comando, poiché puoi scrivere un intero mini-script se lo desideri.


Quindi, ad esempio, se vuoi scrivere del testo complicato e inserirlo immediatamente in Pandoc, puoi semplicemente digitare:

<Esc>v

Quindi modifica il buffer Vim fino a quando non hai qualcosa di simile:

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

Quindi salva ed esci (con :x) e il tutto verrà eseguito come comando shell.

Sarà anche disponibile nella cronologia dei comandi della shell.


1
Se si preferisce mantenere le associazioni dei tasti Emacs, è comunque possibile utilizzare Vim per modificare le righe di comando impostando la EDITORvariabile di ambiente su vime premendo Ctrl-Xseguito da Ctrl-Ementre si modifica la riga di comando.
Anthony G - giustizia per Monica,

18

In esecuzione in una pipeline

Provare:

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

La chiave è che, per poter essere utilizzato vimnormalmente, è vimnecessario che stdout sia il terminale. Lo realizziamo qui con il reindirizzamento >/dev/tty.

Per motivi di sicurezza, ho inserito il file temporaneo nella home directory dell'utente. Per ulteriori informazioni, consultare la domanda frequente 062 di Greg . Ciò elimina la necessità di utilizzare un nome di file oscuro.

Esempio:

Quando si vimapre, scrivo This function succeeded.e salvo il file. Il risultato sullo schermo appare come:

$ quickedit | grep succeeded
This function succeeded.

Anche se l'output di quickeditviene reindirizzato a una pipeline, vimfunziona ancora normalmente perché gli abbiamo concesso l'accesso diretto /dev/tty.

Esecuzione di un programma da vim

Come ho detto nei commenti, vim può reindirizzare un file a un comando. Dall'interno di vim, ad esempio, immettere il comando :w !pandoc -o file.pdf(Nota: lo spazio tra w e! È essenziale).


2
Bella risposta. Questo risolve direttamente la domanda dell'utente e offre una soluzione rapida ed elegante: reindirizzare vim su / dev / tty! Semplice!
Mike S,

Sto usando Zsh; trap '...' exitfallisce ma trap '...' EXITsembra funzionare. Non so molto sul trapping, ma il mio approccio generale per i file temporanei è l'uso mktmp [--suffix=...]. Inoltre, vim <outfile> -c '...' >/dev/ttyviene eseguito normalmente fino al caricamento del file, quindi esegue la determinata catena di comandi, anche :wqse si desidera saltare la fase di modifica. Ho anche usato set | grep -a EXITe trovato signals=(EXIT ... DEBUG).
John P

5

Assicurati che vimsia impostato come editor predefinito (ad es. export EDITOR=vimNel tuo .bash_profileo .bashrc. Quindi, a qualsiasi prompt, puoi digitare Ctrl- Xseguito da Ctrl- E. Questo aprirà la tua riga di comando corrente nell'editor configurato (ad es vim.). Apporta le tue modifiche, salva e exit, e il comando verrà eseguito come se fosse stato digitato sulla riga di comando, inclusi pipeline e simili.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.