¿Cómo editar contenido desde la entrada estándar?

15

Me gustaría editar contenido en vim que se generó dinámicamente desde la línea de comandos sin tener el archivo todavía.

Por ejemplo:

$ echo This is example. | vim /dev/stdin
$ cat /etc/hosts | vim /dev/stdin

pero está fallando con los errores:

Vim: Advertencia: la entrada no proviene de un terminal

Vim: Error al leer la entrada, saliendo ...

¿Es posible lograr eso?

kenorb
fuente
:help stdin... Es sorprendente lo rápido que uno puede encontrar las respuestas haciendo su pregunta sobre la documentación incorporada.
dash-tom-bang

Respuestas:

23

Debe usar -en lugar del nombre del archivo en la línea de comando:

echo This is example. | vim -

El comando anterior abrirá un búfer sin nombre lleno del texto leído desde la entrada estándar.

toro2k
fuente
77
El uso de -for stdin es bastante estándar para las herramientas de línea de comandos;
Martin Tournoij
6

Esto es principalmente una nota divertida sobre bashy readline, pero si configura su EDITORvariable de entorno en vim, presionar Ctrl+ x+ eabrirá la línea actual vim. Además, si escribe Meta(Alt/Opt/Esc)+ Ctrl+ e, bash realizará una expansión en el lugar en la línea de comando actual, es decir:

$ echo $EDITOR # Assuming EDITOR was set

con Meta(Alt/Opt/Esc)+ Ctrl+ ese convertiría

$ echo vim # Assuming EDITOR was set

con Ctrl+ x+ ese convertiría

1 echo vim # Assuming EDITOR was set
~
~
/tmp/sometmpbufferfile

Tenga en cuenta que al salir de vim, el contenido del búfer vim se ejecuta en la línea de comando.

Estas características se vuelven muy útiles para mí cuando quiero hacer comandos de varias líneas en bash, como para bucles o programas que requieren declaraciones aquí, y proporciona una forma interesante de guardar un poco del historial de la línea de comandos para archivarlo para su uso posterior.

Entonces, para responder la pregunta original, también puedes escribir,

$ This is an example

y luego presione Ctrl+ x+ epara cargarlo vim. También podrías tener,

 $ $(cat /etc/hosts)

y haga Meta(Alt/Opt/Esc)+ Ctrl+ eluego Ctrl+ x+ e, lo que colocaría todos los archivos hosts en una línea y lo cargaría vim(probablemente no sea el mejor uso de estas características; sin embargo, la utilidad de estos métodos se puede extrapolar de los pocos ejemplos discutidos aquí).

Tenga en cuenta que supongo que su readlineestá configurado en emacsmodo. Si readlineestá configurado en vimmodo, puede descubrir fácilmente los enlaces relevantes mediante el comando:

bind -p

y buscando edit-and-execute-commando shell-expand-line, que se asociaron respectivamente con los enlaces Ctrl+ x+ ey Meta(Alt/Opt/Esc)+ Ctrl+ e.

HAL 9001
fuente
Puede decirle a bash que use las combinaciones de teclas vi en lugar de emacs. Use set -o vipara encenderlo. Luego puede usar la vasignación en modo normal para editar el comando actual en su editor.
Quincy Bowers
1
Por supuesto, este es un gran truco para editar la línea de comando usando vi, pero hay al menos dos problemas al usar este método para leer texto de stdin: 1. shell-expand-lineeliminar líneas nuevas del texto expandido e 2. edit-and-execute-commandintentar ejecutar el comando escrito en el búfer , se guarde o no, cuando salga de vi.
toro2k
Woah, esto es asombroso. Aprendo algo nuevo sobre readline todos los días, parece ...
Pomo
2

En bash, me pareció útil usar la sustitución de procesos usando la <(command)sintaxis, por ejemplo:

vim <(echo This is example.)
vim <(cat /etc/hosts)

Ver también:

kenorb
fuente
44
Tenga en cuenta que esto no funcionará en todos los depósitos. Creo que sólo funcionará en bashy zsh(y no sh, ksh, dash, fish, csh, tcsh, etc.)
Martin Tournoij
@Carpetsmoker Debería funcionar en ksh88 y superior, creo, pero sí, la sustitución del proceso no es POSIX.
muru
44
¡Y presta atención para no engañarte! Cuando inicia Vim de esta manera, abre un búfer para un archivo como /proc/PID/fd/FD. Si escribe el búfer y sale, Vim no se queja, pero el sistema operativo eliminará el archivo en el que ha escrito. Al usar -como nombre de archivo, el búfer abierto no tiene ningún archivo asociado, por lo que si intenta salir sin guardar (Vim, le avisará), siempre y cuando no use un comando de explosión o similar.
toro2k
1
Esto es bueno porque se generaliza bien vimdiff <(echo foo) <(echo bar).
wchargin
@ toro2k Para hacer un seguimiento, parece que usa :nexty :prevvuelve a leer la transmisión y no obtiene nada. También vale la pena mencionar que los procesos no son paralelos entre sí, por ejemplo, se cat <(sleep 3; echo a) <(echo b)imprime en orden, y mientras las catintercalaciones escriben y leen, vimesperan en el archivo para "terminar de leer" antes de mostrar todo menos el marco exterior.
John P
-1

Si el uso de una canalización a un nuevo Vim no es un requisito, puede usar la capacidad de Vim para extraer la salida de comandos en el búfer actual, junto con tener un búfer sin respaldo de archivo (como :neweditar un archivo inexistente)

:read!cat /etc/hosts en modo comando colocará la salida en su búfer actual debajo de la posición actual del cursor.

Además de tener que eliminar la primera línea vacía que queda cuando esto se hace en un búfer vacío, esto funciona bien y es especialmente conveniente si Vim ya se está ejecutando.

ewatt
fuente
1
¿Cómo responde esto a la pregunta?
muru
Toma el resultado del comando y lo pone en vim.
ewatt