Recuerda un comando medio escrito mientras reviso algo

97

A menudo me encuentro en la siguiente posición: comencé a escribir un comando largo en el indicador bash, pero a mitad de camino descubro que necesito verificar algo con otro comando. Este es un problema cuando estoy en la consola (no X), que a menudo es el caso, porque entonces solo tengo las siguientes formas insatisfactorias de hacerlo, que conozco:

  • Presione ctrl+ alt+ F2e inicie sesión en otra consola virtual, y descubra lo que quería, luego regrese y continúe
  • ctrl+ a, escriba echo + space+ enter, descubra lo que quería, presione hasta que encuentre mi comando, ctrl+ a, delx 5, ctrl+ ey continúe
  • Resalte lo que he escrito hasta ahora con mi mouse (si gpm se está ejecutando, que generalmente es), presione ctrl+ cpara interrumpir, descubra lo que quería mientras tiene cuidado de no usar mi mouse para resaltar cosas, luego presione el botón central del mouse en un nuevo aviso y continuar
  • Ore a los dioses de la línea de comando para que el comando medio escrito no tenga efectos adversos, sino que simplemente falle, y presione con cautela enter, luego descubra lo que quería, presione uparrow hasta que recupere mi comando y continúe
  • Salto a mi máquina del tiempo, viajo en el tiempo y me recuerdo a mí mismo para iniciar la pantalla antes de comenzar a escribir el comando, viajar al presente, presionar ctrl+ a c, averiguar lo que quería, presionar ctrl+ a ctrl+ay continuar

Entonces, lo que quiero saber es, ¿hay alguna forma más elegante de hacer esto? ¿Una especie de comando subshell o similar?

Estoy más interesado en métodos que no requieren ninguna preparación o configuración para funcionar.

Lauritz V. Thaulow
fuente

Respuestas:

68

Una versión algo más rápida de alex's Ctrl + A Ctrl+ K(que se mueve al frente de la línea y luego corta todo hacia adelante) es usar Ctrl+ U, que corta hacia atrás en bash, y toda la línea (independientemente de su posición actual) en zsh. Luego usas Ctrl+ Ypara pegarlo nuevamente

Michael Mrozek
fuente
1
Al probar esto, concluyo que Ctrl + U no retrocede y corta hacia adelante, sino que retrocede. Tener el cursor en el medio del comando deja lo que esté detrás de él en la línea de comando. Sin embargo, sigue siendo una mejora del 33% sobre la solución de @ alex, ya que ahorra una pulsación de tecla.
Lauritz V. Thaulow
2
@lazyr Oh, muy bien; en zshella corta toda la línea, pero en bashella corta hacia atrás. Nunca noté esa diferencia antes
Michael Mrozek
2
Oh, no sabía que Ctrl + U también pone texto para eliminar el búfer. ¡Bueno saber! :)
alex
1
^U ^Ktendrá el mismo efecto ^A ^Kpero es marginalmente más ergonómico y significativamente más conveniente debajo screen.
intuido
53

Haga Ctrl-A para llegar al inicio de la línea, anteponga un hash y presione Intro; de esta manera, permanecerá en el historial de comandos como un comentario y podrá volver a él con el cursor hacia arriba

EDITAR: acabo de notar que esta es una variante un poco más elegante en su # 2;)

jamespo
fuente
1
Sí, y ¿por qué no pensé en eso? ¡Gracias!
Lauritz V. Thaulow
1
Necesito leer antes de publicar mi propia respuesta. James tiene razón.
Sean C.
44
Tenga en cuenta que esto no funcionará csho zshporque no permiten comentarios en el shell interactivo. En zshlo que necesita para activar la opción correcta: setopt interactive_comments.
sam hocevar
1
@Sam Sí, pero ": comando" tiene el mismo efecto (":" = el comando nulo)
barrycarter
66
@barrycarter: no, :debe considerarse dañino para este propósito y nunca, nunca debe sugerirse. Ejecutará todo después de un punto y coma, backticks internos, etc. con todos los efectos secundarios asociados.
sam hocevar
29

Pulse Ctrl+A, Ctrl+Kpara moverse al inicio de la línea y eliminar (matar) al final de la misma. Luego investigue, y cuando esté listo para continuar, golpee Ctrl+Y(tire) para volver a colocar su línea guardada (asesinada).

alex
fuente
3
Ah, ahora esto es más como lo que tenía en mente. Y lo hago todo el tiempo en Emacs, debería haber pensado en hacer lo mismo en la línea de comandos.
Lauritz V. Thaulow
13

En zsh, escribo Ctrl+ Zpara "suspender" el comando que estoy escribiendo y escribo otro comando. Después de ejecutar ese comando (o abortarlo con Ctrl+ C), el comando suspendido regresa para edición (incluso recordando la posición del cursor). Como conveniencia adicional, si la línea de comando está vacía cuando escribo Ctrl+ Z, la tecla invoca la función bgincorporada (por lo tanto, un doble Ctrl+ Zenvía un comando en ejecución directamente al fondo).

fancy-ctrl-z () {
  emulate -LR zsh
  if [[ $#BUFFER -eq 0 ]]; then
    bg
    zle redisplay
  else
    zle push-input
  fi
}
zle -N fancy-ctrl-z
bindkey '^Z'          fancy-ctrl-z

No sé cómo hacer algo similar en bash.

En cualquier shell, puede usar el método de baja tecnología de agregar un #al comienzo de la línea actual .

Gilles
fuente
2
su función es admirable, pero ¿sabía que ya zshtiene una función incorporada ? Se llama push-liney todo lo que necesita hacer es usarlo bindkeypara acceder.
Caleb
@Caleb: No sé por qué lo uso en push-inputlugar de push-lineaquí, push-lineparece más apropiado (¿quizás solo las versiones antiguas de zsh tenían push-input?). Pero eso no es un reemplazo para el resto de la función.
Gilles
Por lo que puedo decir, la única diferencia es el mismo efecto vinculante para el fondo de un trabajo en ejecución. ¿Me estoy perdiendo de algo?
Caleb
1
@Caleb: No, es sólo que me parece la combinación de los dos a la vez conveniente ( push-linees inútil en una línea vacía, teniendo bgen Ctrl+Zsólo es útil cuando sólo he suspendido ese proceso con Ctrl+Z) y la tecla de acceso (estoy bien backgrounding el proceso o la línea de comando parcial).
Gilles
3
@Caleb push-inputsuspende todo el búfer de entrada, mientras que push-linesolo suspende la línea actual. Si estoy escribiendo un comando multilínea, quiero suspender todo el comando, así que push-inputes el correcto. Encuentro push-inputmás útil que push-line(si quiero retrasar una línea en un búfer de entrada multilínea, simplemente puedo navegar hasta el comienzo de la línea e insertar una nueva línea), así que de hecho me pregunto por qué push-lineobtuve la combinación de teclas predeterminada y no push-input.
Gilles
13

En bash, solo escribe Alt+ #.

Luego, cuando esté listo, presione Upy luego Alt+ #.

El primero coloca un #al comienzo de la línea para convertirlo en un comentario, luego acepta la línea, como si hubiera presionado Enter.

Luego, cuando lo haces por segunda vez, ve que la línea ya tiene un #al comienzo, por lo que la elimina y la acepta, de nuevo guardándote la Enterclave.

Si la segunda vez solo inserta otra #, entonces debe escribir Alt+ - Alt+ en su #lugar.

Puedes hacer que zsh haga lo mismo poniendo

bindkey -M emacs '\e#' pound-insert

en tu ~ / .zshrc.

O, si está utilizando enlaces vi, puede escribir #desde el modo de comando tanto en bash como en zsh.

Mikel
fuente
2
No funciona para mí, el segundo comando destinado a eliminar el # solo agrega más # al frente.
Lauritz V. Thaulow
1
¿El primero funciona? ¿Qué versión de bash estás usando?
Mikel
3
Alt + # funciona como usted describe en su tercer párrafo, pero no como en el cuarto, simplemente antepone otro # al frente y acepta la línea. Uso bash 4.1.5 (1) -release en Ubuntu 10.10.
Lauritz V. Thaulow
1
Oh querido, en bash requiere un argumento numérico, por ejemplo, Esc+1entonces Alt+ #para alternar.
Mikel
Eso funciona, pero es mucho más engorroso que simplemente Ctrl + A Del Ctrl + E, especialmente en mi diseño de teclado donde Alt + # es, de hecho, Alt + Shift + 3.
Lauritz V. Thaulow
10

Una de mis características favoritas zshes la función de línea push incorporada que se encarga de esto sin ninguna de la piratería en otras respuestas aquí. Lo tengo vinculado a Ctrl+ len mi .zshrcarchivo así:

bindkey '^L' push-line

Luego, cuando estoy escribiendo algún comando y necesito hacer algo más rápido, puedo invocarlo con una tecla y obtener un mensaje en blanco. Después de ejecutar el otro comando, la solicitud se completa automáticamente con lo que estaba escribiendo antes.

Incluso puede encadenar varias capas de esto y los comandos volverán a usted en orden inverso al que los empujó a la cola.

Caleb
fuente
55
Bound to Ctrl+Qy ESC qpor defecto (en modo emacs).
Gilles
¿Hay algo similar para bash?
Magnus
@Magnus: Por favor revise el resto de las respuestas a esta pregunta. Hay soluciones para bash, pero no tan elegantes como esta.
Caleb
@Caleb, debería haber sido más específico, ¿hay una combinación de teclas única similar para bash?
Magnus
1
Esta es claramente la respuesta "correcta", ¡para Zsh de todos modos! Solo quiero mencionar el push-line-or-editwidget, que no está vinculado en ningún mapa de teclas de forma predeterminada. En el indicador de nivel superior, hace lo mismo push-line, pero en cualquier nivel de indicador inferior, convierte todo el comando que se ingresa en un búfer de varias líneas. ¡Dos excelentes funciones en una combinación de teclas! Puedo recomendar encuadernación en push-line-or-editlugar de simple push-line. No pierde nada y obtiene una funcionalidad útil.
wjv
5

Además del ctrl- a ctrl- ktruco, si está en la pantalla, solo ctrl- a dpara separar y volver a conectar conscreen -r

También podría simplemente abrir otra ventana con ctrl+a c

madriguera
fuente
8
Si está en la pantalla, simplemente abra otra ventana con Ctrl+A c.
Gilles
1
@Gilles ... a menos que necesite usar algún aspecto del estado del shell (variables, funciones, alias, etc.).
intuido
4

Una forma alternativa, aunque no perfecta, es presionar Ctrl-X Ctrl-E. Esto abrirá su editor predeterminado que contiene su comando medio escrito. Luego puede guardar su comando en un archivo o abrir un nuevo shell desde su editor. Cuando salga del nuevo shell, lo devolverá al editor y guardar el contenido los ejecutará automáticamente.

Esto no es perfecto porque no lo devuelve a su shell original, sino que fuerza la ejecución del comando o lo descarta por completo. Pero no hay selecciones temporales o buffers de muerte por los que preocuparse, y también hay algunos ajustes agradables, por ejemplo, si editor = vi

:wq            # execute the command
:cq            # cancel and abort
:! command     # execute command
:shell         # open a new shell
:r filename    # insert the contents of a file for editing
:r ! command   # insert the output of a command for editing
forcefsck
fuente
Muy buena alternativa. Soy vi-emacs-agnóstico, por lo que seré feliz como una almeja usando esto cuando realmente se necesitan herramientas eléctricas. (Hablando de vi, probé el emulador de Linux N64 Mupen64Plus hace un tiempo. Esc abandona el emulador sin guardar. Pronto dejé de jugar.)
Lauritz V. Thaulow
1
@lazyr, para debian / ubuntu ejecuta sudo update-alternatives --config editory elige tu editor favorito. Para otros sistemas, configure las variables de entorno EDITOR o VISUAL en su editor favorito, por ejemplo, agregue export EDITOR=/usr/bin/nanosu .bashrc.
forcefsck
3

Similar al método de agregar #al comienzo de la línea, hay un método posiblemente más simple que utilizo que no requiere volver al comienzo de la línea:

Simplemente agregue una cotización abierta y no la cierre, ya sea simple o doble.

Luego presione Enter.

Luego presione CtrlC.

El comando parcial se guarda en el historial de comandos (disponible mediante la flecha hacia arriba) pero en realidad no se ejecuta.

Comodín
fuente
2

Usando zsh, si escribe <ESC> q(escape, luego Q), su línea de solicitud se cortará, para que pueda escribir otro comando. Recuperará automáticamente el texto cortado en la próxima solicitud.

Puede recordar varias líneas al mismo tiempo, por lo que puede usarlo mientras le espera una línea. Incluso puede usarlo en una línea en blanco para retrasar la reanudación de su línea de corte.

No es la forma más eficiente si tiene que usar varios comandos para la verificación / preparación (deberá volver a escribir <ESC> qantes de cada comando). Pero creo que es posible vincularlo a un atajo más corto.


Si solo desea consultar el manual, escriba <ESC> h(escape, luego H). Eso ejecutará el run-helpincorporado, con la primera palabra de la línea de comando como argumento. Volverás a encontrar tu línea intacta una vez hecho.

loxaxs
fuente
La mayoría de las terminales te permitirán hacerlo en M-qlugar de<ESC> q
sleblanc