107

I often find myself in the following position: I've started typing a long command at the bash prompt, but half-way through I find out I need to check something with another command. This is a problem when I'm at the console (no X), which is often the case, because then I only have the following unsatisfactory ways to do it, that I know of:

  • Hit ctrl+alt+F2 and log in on another virtual console, and find out what I wanted, then go back and continue
  • ctrl+a, type echo + space + enter, find out what I wanted, press until I find my command, ctrl+a, del x 5, ctrl+e, and continue
  • Highlight what I've typed so far with my mouse (if gpm is running, which it usually is), press ctrl+c to interrupt, find out what I wanted while being careful not to use my mouse to highlight stuff, then press middle mouse button on a new prompt and continue
  • Pray to the command line gods that the half-written command will have no adverse effects but simply fail, and gingerly press enter, then find out what I wanted, press uparrow until I get my command back, and continue
  • Jump into my time machine, travel back in time and remind myself to start screen before starting to type command, travel back to the present, press ctrl+a c, find out what I wanted, press ctrl+a ctrl+a, and continue

So what I want to know is, is there some more elegant way of doing this? A sort of subshell-command or similar?

I'm most interested in methods that do not require any preparations or setup to work.

Mikel
  • 57,299
  • 15
  • 134
  • 153

11 Answers11

77

A somewhat faster version of alex's Ctrl+A Ctrl+K (which moves to the front of the line and then cuts everything forward) is to just use Ctrl+U, which cuts backward on bash, and the entire line (regardless of your current position) on zsh. Then you use Ctrl+Y to paste it again

Michael Mrozek
  • 93,103
  • 40
  • 240
  • 233
  • 1
    Testing this, I conclude that Ctrl+U does not move back and cut forward, but rather cuts backwards. Having cursor in the middle of the command leaves whatever is behind it on the command line. Still a 33% improvement over @alex's solution though, since it saves a keystroke. – Lauritz V. Thaulow Apr 07 '11 at 21:18
  • 2
    @lazyr Oh, quite right; on zsh it does cut the entire line, but on bash it cuts backwards. I never noticed that difference before – Michael Mrozek Apr 07 '11 at 21:20
  • 2
    Oh, I didn't know Ctrl+U also puts text to kill buffer. Nice to know! :) – alex Apr 08 '11 at 06:10
  • 1
    ^U ^K will have the same effect as ^A ^K but is marginally more ergonomic, and significantly more convenient under screen. – intuited Apr 19 '11 at 05:04
55

Do ctrl-A to get to start of line, prepend a hash and press return - this way it will stay in the command history as a comment and you can get back to it with cursor up

EDIT: just noticed this is a slightly more elegant variant on your #2 ;)

jamespo
  • 1,171
  • 7
  • 6
  • 1
    Yes, and why didn't I think of that? Thank you! – Lauritz V. Thaulow Apr 07 '11 at 14:03
  • 1
    I need to read before I post my own answer. James has it right on. – Sean C. Apr 07 '11 at 16:53
  • 4
    Note that this will not work in csh or zsh because they do not allow comments in the interactive shell. In zsh you need to activate the proper option: setopt interactive_comments. – sam hocevar Apr 07 '11 at 19:56
  • 1
    @Sam Yes, but ": command" has the same effect (":" = the null command) –  Apr 08 '11 at 14:09
  • 6
    @barrycarter: no, : should be considered harmful for this purpose and never, ever be suggested. It will execute everything after a semicolon, inside backticks etc. with all the associated side effects. – sam hocevar Apr 08 '11 at 16:35
  • Note that this will work better than prepending echo if there are multiple commands on the line (delimited by ;, &&, etc.). – intuited Apr 19 '11 at 04:58
  • @barrycarter As Sam mentioned that's a really dangerous idea, but I'm not sure it was clear how many things fall into his "etc." box. Very notably shell redirects are still processed meaning this habit will clober files. Also some forms of variable assignment will still run as will subshells, process and command substitution, etc. Interactive aliases will be replaced and more. In other words 95% of what would normall happen in a shell still happens and will happen wired up no a noop command instead of the one intended, which will almost certainly screw up your workspace. – Caleb Jun 07 '16 at 18:12
30

Hit Ctrl+A, Ctrl+K to move to the start of line and delete (kill) to the end of it. Then do your research, and when ready to continue hit Ctrl+Y (yank) to put your saved (killed) line back.

alex
  • 7,223
  • 3
    Ah, now this is more like what I had in mind. And I do that all the time in Emacs, should have thought about doing the same on the command line. – Lauritz V. Thaulow Apr 07 '11 at 18:50
15

In zsh, I type Ctrl+Z to “suspend” the command I'm typing and type another command. After I've run that command (or aborted it with Ctrl+C), the suspended command comes back for edition (even remembering the cursor position). As an additional convenience, if the command line is empty when I type Ctrl+Z, the key invokes the bg built-in instead (so a double Ctrl+Z sends a running command directly to the background).

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

I don't know how to do something similar in bash.

In any shell, you can use the low-tech method of adding a # at the beginning of the current line.

  • 2
    your function is admirable, but did you know that zsh has a function for that built in already? It's called push-line and all you need to do is use bindkey to get to it. – Caleb Apr 25 '11 at 17:42
  • @Caleb: I don't know why I use push-input rather than push-line here, push-line does seem more appropriate (maybe old versions of zsh only had push-input?). But that's not a replacement for the rest of the function. – Gilles 'SO- stop being evil' Apr 25 '11 at 18:17
  • As far as I can tell the only difference is the same-binding effect to background a running job. Am I missing something? – Caleb Apr 25 '11 at 18:20
  • 1
    @Caleb: No, it's just that I find the combination of the two both convenient (push-line is useless on an empty line, having bg on Ctrl+Z is only useful when I've just suspended that process with Ctrl+Z) and mnemonic (I'm either backgrounding the process or the partial command line). – Gilles 'SO- stop being evil' Apr 25 '11 at 20:39
  • 3
    @Caleb push-input suspends the whole input buffer, whereas push-line suspends only the current line. If I'm typing a multiline command, I want to suspend the whole command, so push-input is the right one. I find push-input more often useful than push-line (if I want to delay a line in a multiline input buffer, I can simply navigate to the beginning of the line and insert a newline), so I in fact wonder why push-line got the default keybinding and not push-input. – Gilles 'SO- stop being evil' May 02 '13 at 09:50
  • @Caleb: two comments & a question: (1) very nice hack to bind this to ^Z and do a bg on an empty line! (2) it's a bit better to do a zle get-line before the zle redisplay --- this makes it work fine for cases like: ^Z to suspend something, start a command, ^Z^Z to bg the something and continue editing; (3) is there any need for the emulate -LR? – Eli Barzilay Jun 07 '16 at 17:17
  • @EliBarzilay (2) That's intended behavior: backgrounding a job with ^Z^Z doesn't automatically recall a previously-suspended command line. (3) I think in this case there isn't, but I have the habit of including it in functions that might be used in interactive sessions with all kinds of “crazy” options for user preferences. – Gilles 'SO- stop being evil' Jun 07 '16 at 17:33
  • @Caleb, re (2) with that addition it only does the recall if you ^Z^Z while typing a new command, which fixes a weird thing that happens without it. Just it with your version: sleep 10 RET ^Z pwd (no enter) ^Z^Z -- at this point it will bg-es the sleep, but it leaves you with an empty line, and after another RET you get the restored line. Then try the same sequence with my addition. – Eli Barzilay Jun 08 '16 at 04:20
  • @EliBarzilay Once again, that's the behavior I intended. If you prefer to recall the line automatically, then by all means include the call to get-line in your configuration. – Gilles 'SO- stop being evil' Jun 08 '16 at 07:46
  • Here's a variation of the Ctrl-Z solution, which should work for Bash. – Sebastian Carlos Jul 19 '23 at 13:26
14

In bash, just type Alt+#.

Then when you're ready, press Up then Alt+#.

The first puts a # at the start of the line to turn it into a comment, then accepts the line, as if you had pressed Enter.

Then, when you do it a second time, it sees the line already has a # at the start, so it removes it, and accepts it, again saving you the Enter key.

If the second time just inserts another #, then you have to type Alt+- Alt+# instead.

You can make zsh do the same by putting

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

in your ~/.zshrc.

Or, if you are using vi bindings, you can type # from command mode in both bash and zsh.

Mikel
  • 57,299
  • 15
  • 134
  • 153
  • 3
    Doesn't work for me, the second command meant to remove the # just adds more #'s to the front. – Lauritz V. Thaulow Apr 07 '11 at 21:14
  • 1
    Does the first one work? What version of bash are you using? – Mikel Apr 07 '11 at 21:19
  • 3
    Alt+# works as you describe in your third paragraph, but not as in your fourth, it simply prepends another # to the front and accepts the line. I use bash 4.1.5(1)-release on Ubuntu 10.10. – Lauritz V. Thaulow Apr 07 '11 at 21:24
  • 1
    Oh dear, in bash it requires a numeric argument, e.g. Esc+1 then Alt+# to toggle. – Mikel Apr 07 '11 at 21:30
  • That works, but is a lot more cumbersome than just Ctrl+A Del Ctrl+E, especially on my keyboard layout where Alt+# is in fact Alt+Shift+3. – Lauritz V. Thaulow Apr 07 '11 at 21:39
  • Definitely. There might be a solution to bind Alt+# to numeric-argument insert-comment, so you don't also have to type Alt+ first. – Mikel Apr 07 '11 at 21:45
  • You can also prepend Esc instead of pressing Alt. This might be more palatable for removing the #: you can do Esc 1 Esc #. – intuited Apr 19 '11 at 05:06
11

One of my favorite features in zsh is the builtin push-line function that takes care of this without any of the hackery in other answers here. I have it bound to Ctrl+l in my .zshrc file like this:

bindkey '^L' push-line

Then when I'm typing along in some command and need to do something else real quick I can invoke that with one key and get a blank prompt. After running the other command, the prompt is automatically filled out with what I was typing before.

You can even chain multiple layers of this and the commands will come back at you in reverse order that you pushed them into the queue.

Caleb
  • 70,105
  • 6
    Bound to Ctrl+Q and ESC q by default (in emacs mode). – Gilles 'SO- stop being evil' Apr 25 '11 at 20:37
  • Is there something similar for bash? – Magnus Oct 01 '12 at 13:53
  • @Magnus: Please review the rest of the answers on this question. There are solutions for bash, just not as elegant as this. – Caleb Oct 01 '12 at 13:58
  • @Caleb, I should have been more specific, is there a similar single key combination for bash? – Magnus Oct 01 '12 at 14:11
  • 1
    This is clearly the “correct” answer, for Zsh anyway! I just want to mention the push-line-or-edit widget, which is not bound in any keymap by default. At the top-level prompt it does the same thing as push-line, but at any prompt level lower down it convert the entire command being entered to a multi-line buffer. Two great functions on one keybinding! I can recommend binding push-line-or-edit instead of plain push-line. You lose nothing, and gain useful functionality. – wjv Apr 05 '16 at 07:38
5

In addition to the ctrl-a ctrl-k trick, if you're in screen, just ctrl-a d to detach then reattach with screen -r

You could also just open another window with ctrl+a c

warren
  • 1,848
4

An alternative way, not perfect though, press Ctrl-X Ctrl-E. This will open your default editor containing your half typed command. Then you may save your command to a file or open a new shell from within your editor. When you exit the new shell it will return you to the editor and saving the contents will automatically execute them.

This is not perfect because it doesn't return you to your original shell, but either forces the execution of the command or completely discards it. But there are no temporary selections or kill buffers to worry about, and there are also some nice tweaks, e.g. if 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
  • 7,964
  • Very nice alternative. I'm vi-emacs-agnostic, so I'll be happy as a clam using this when powertools are really needed. (Speaking of vi, I tried the N64 linux emulator Mupen64Plus a while ago. Esc quits the emulator without saving. I soon gave up playing anything.) – Lauritz V. Thaulow Apr 07 '11 at 20:04
  • 1
    @lazyr, for debian/ubuntu run sudo update-alternatives --config editor and choose your favorite editor. For other systems set the EDITOR or VISUAL environment variables to your favorite editor, e.g. add export EDITOR=/usr/bin/nano in your .bashrc. – forcefsck Apr 07 '11 at 20:17
3

Using zsh, if you type <ESC> q (escape, then Q), your prompt line will be cut, so that you can type another command. You will automatically get back your cut text in the next prompt.

It can remember several lines at the same time, so you can use it while a line is waiting for you. You can even use it on blank line to delay the resume of your cut line.

It's not the most efficient way if you have to use several commands for the checking/preparation (you'll have to retype <ESC> q before each command). But I think that it is possible to bind it to a shorter shortcut.


If you just want to check the manual, type <ESC> h (escape, then H). That will run the run-help built-in, with the first word of the command line as argument. You'll find back your line intact once done.

loxaxs
  • 1,924
3

Similar to the method of adding # at the start of the line, there is an arguably simpler method that I use that doesn't require returning to the beginning of the line:

Just add an open quote and don't close it, whether single or double.

Then press Enter.

Then press CtrlC.

The partial command is saved in the command history (available via up arrow) but is not actually executed.

Wildcard
  • 36,499
2

I've recently written a script for this. Just Ctrl+b to remember/restore command-lines.

Download:

Visit the repository.

Demo:

demo

ynn
  • 870