Cómo invocar el editor vim y la salida de tubería a bash


34

A veces necesito escribir texto y luego canalizar ese texto a otro comando. Mi flujo de trabajo habitual es más o menos así:

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

Encuentro esto engorroso y busco aprender scripts de bash. Me gustaría simplificar el proceso escribiendo un comando que abre un editor y cuando el editor cierra la salida del editor a stdout. Entonces podría ejecutar el comando como quickedit | pandoc -o file.pdf.

No estoy seguro de cómo funcionaría esto. Ya escribí una función para automatizar esto siguiendo el flujo de trabajo exacto anterior más algunas adiciones. Genera una cadena aleatoria para actuar como un nombre de archivo y se la pasa a vim cuando se invoca la función. Cuando el usuario sale de vim guardando el archivo, la función imprime el archivo en la consola y luego lo elimina.

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

El problema que pronto encontré es que cuando hago algo como quickedit | commandvim en sí mismo no se puede usar como editor porque toda la salida está restringida a la tubería.

Me pregunto si hay alguna solución a esto, para poder canalizar la salida de mi quickeditfunción. La alternativa subóptima es iniciar un editor separado, digamos texto sublime, pero realmente quiero permanecer en la terminal.


Desde vim, emita el comando :w !pandoc -o file.pdf? (Nota: el espacio entre wy !es esencial.)
John1024

OK eso es genial. No sabía que podía canalizar la salida de vim desde dentro de vim. Esto sirve para mis propósitos, pero para mi conocimiento futuro, ¿es posible resolver mi problema exactamente como pretendía que se resolviera?
theideasmith

¿Puedes publicar tu función? ¿Qué quiere decir cuando habla sobre el problema que pronto encontró (segundo párrafo)? No entiendo eso.
Lucas

55
Por otro lado, debe usarlo enmktemp lugar de reinventarlo de manera insegura.
Comodín

Como nuevo usuario de bash, ¿cuáles son los peligros de seguridad de reinventar mktemp?
theideasmith

Respuestas:


42

vipe es un programa para editar tuberías:

command1 | vipe | command2

Obtiene un editor con la salida completa de command1, y cuando sale, el contenido se pasa a command2través de la tubería.

En este caso, no hay command1. Entonces, podrías hacer:

: | vipe | pandoc -o foo.pdf

O:

vipe <&- | pandoc -o foo.pdf

viperecoge las variables EDITORy VISUAL, por lo que puede usarlas para abrir Vim.

Si no lo tiene instalado, vipeestá disponible en el moreutilspaquete; sudo apt-get install moreutils, o el equivalente de tu sabor.


1
Para usuarios de Mac que llegaron aquí: moreutilsestá disponible en Homebrew.
vergenzt

Para usuarios de FreeBSD: moreutilsestá disponible para su instalación a través de pkg (8) .
Mateusz Piotrowski

20

Puedes hacer esto desde Vim:

:w !pandoc -o file.pdf

O incluso escriba el búfer en una tubería compleja:

:w !grep pattern | somecommand > file.txt

Y luego puede salir de Vim sin guardar:

:q!

Sin embargo, considerando su caso de uso específico, probablemente haya una mejor solución al usarlo vicomo su editor de línea de comandos. Suponiendo que use bash:

set -o vi

Esto establece sus combinaciones de teclas en vi. Así que usted puede editar sus comandos a la derecha en la línea de comandos básicos vide configuración de teclas pulsando <Esc>y escribiendo vicomandos como x, cw, etc. (Puede volver a modo de inserción pulsando i).

Aún mejor, y más relevante para esta pregunta, puede abrir Vim para crear su contenido de línea de comando directamente. Simplemente escriba <Esc>vy obtendrá un búfer de Vim vacío. Cuando guarda y sale, ese es el comando en su línea de comando y se ejecuta inmediatamente. Esto es mucho más flexible que editar directamente en la línea de comandos, ya que puede escribir un mini script completo si lo desea.


Entonces, por ejemplo, si desea escribir un texto complicado y canalizarlo a Pandoc inmediatamente, puede escribir:

<Esc>v

Luego edite el búfer Vim hasta que tenga algo como:

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

Luego guarde y salga (con :x) y todo se ejecutará como un comando de shell.

También estará disponible en el historial de comandos de su shell.


1
Si prefiere mantener las combinaciones de teclas de Emacs, aún puede usar Vim para editar líneas de comando configurando la EDITORvariable de entorno vimy presionando Ctrl-Xseguido Ctrl-Emientras edita la línea de comando.
Anthony G - justicia para Monica

18

Corriendo en una tubería

Tratar:

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

La clave es que, para poder usar vimnormalmente, vimnecesita stdout para ser el terminal. Lo logramos aquí con la redirección >/dev/tty.

Por razones de seguridad, pongo el archivo temporal en el directorio de inicio del usuario. Para obtener más información al respecto, consulte la pregunta 062 de las preguntas frecuentes de Greg . Esto elimina la necesidad de usar un nombre de archivo oscuro.

Ejemplo:

Cuando se vimabre, escribo This function succeeded.y guardo el archivo. El resultado en la pantalla se ve así:

$ quickedit | grep succeeded
This function succeeded.

Aunque la salida de quickeditse redirige a una tubería, vimtodavía funciona normalmente porque le hemos dado acceso directo a ella /dev/tty.

Ejecutando un programa desde vim

Como mencioné en los comentarios, vim puede canalizar un archivo a un comando. Desde vim, por ejemplo, emita el comando :w !pandoc -o file.pdf(Nota: el espacio entre w y! Es esencial).


2
Buena respuesta. Este aborda directamente la pregunta del usuario y ofrece una solución rápida y elegante: redirige vim a / dev / tty. ¡Simple!
Mike S

Estoy usando Zsh; trap '...' exitfalla pero trap '...' EXITparece funcionar. No sé mucho sobre la captura, pero mi enfoque general para los archivos temporales es usar mktmp [--suffix=...]. Además, se vim <outfile> -c '...' >/dev/ttyejecuta de manera normal hasta que se carga el archivo, luego ejecuta la cadena de comandos dada, incluso :wqsi desea omitir la fase de edición. También lo usé set | grep -a EXITy lo encontré signals=(EXIT ... DEBUG).
John P

5

Asegúrese de que vimesté configurado como su editor predeterminado (por ejemplo, export EDITOR=vimen su .bash_profileo .bashrc. Luego, en cualquier solicitud, puede escribir Ctrl- Xseguido de Ctrl- E. Esto abrirá su línea de comando actual en su editor configurado (por ejemplo vim). Realice sus ediciones, guarde y salga y el comando se ejecutará como si lo hubiera escrito en la línea de comando, incluidas las tuberías y similares.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.