10

Suppose you run a command which takes some time to return and want to execute a different command after it has been executed but you didn't plan this in advance.

I know that there is the option to press Ctrl + Z and then submit fg && otherCommand. However, this has two major flaws:

  1. It doesn't work if the first command is a composition of different commands (command1 && command2 or command1; command2) because then the subsequent commands of the first submitted line aren't executed.
  2. Execution of the first command is stopped while you enter the next command. With those nasty 30 second commands, the time you spend entering the next command makes up a good portion of the remaining execution time, if not all of it.

I also know that you can just type in the next command while one command is being executed and then hit Enter to sumbit it. However, this also has two major flaws:

  1. It doesn't work if the command you execute first reads from stdin.
  2. If the command you execute first produces output, you can't see what you entered.

Is there a quick way to queue up more commands while one command is being executed, possibly involving using a special terminal emulator or several terminals?

UTF-8
  • 3,237
  • So when you are typing the second command, you want the first command to stay running; in addition, the first command may read from stdin. These two requirements seem to contradict each other: you do both "typing the second commands" and "feeding the first command" with your stdin simultaneously? – Franklin Yu Apr 30 '17 at 16:51
  • I think there are probably two different cases: the first command is either interactive (so it reads from stdin), or non-interactive (so it doesn't get in the way when you instruct the shell about the second command). – Franklin Yu Apr 30 '17 at 17:03
  • @FranklinYu I can see several ways this can be fulfilled. Maybe there is a terminal emulator which can open a new terminal window after the user pressed some shortcut and only starts executing stuff in that new terminal after execution of the command which was executed in the first terminal when the shortcut was activated terminated. Maybe there is one which has a shortcut which lets the user add commands in an extra line or a pop-up which are sent to the terminal after the current command terminated. – UTF-8 Apr 30 '17 at 17:35
  • Maybe there is a ctrl. seq. which suppresses the output of the current command while you type the next command and then replays the output (both stdout and stderr) after you hit enter. Maybe there is a terminal window manager (like screen) which introduces a ctrl. seq. that does that. Maybe there is a command which misuses job control to do this (launches a new process to do the actual work and then pipes that process's output through put the new process isn't affected by ctrl + Z). My point is: There are lots of options. Probably a lot more than I can think about while writing a comment. – UTF-8 Apr 30 '17 at 17:39
  • I got your point. So you may want to add to the question that you are fine with multiple terminal sessions (it seems that I'm not the only one making wrong assumptions), and that you are already using a graphic terminal emulator like GNOME Terminal or Konsole. In addition, by saying "the command you execute first reads from stdin" you are actually fine if the first command can't read certain byte like ^Z (which is not the case if, for example, the first command is a shell). – Franklin Yu May 01 '17 at 04:48

5 Answers5

5

Press Ctrl+Z and immediately run bg. This causes the current command to keep running in the background. Then you can use fg && otherCommand to schedule otherCommand after the current one.

To make this easier, I've configured Ctrl+Z in my shell to run bg when I press it on an empty command line. See In zsh, how can I more quickly disown the foreground process? and How do you send command line apps directly to the background? ; I haven't checked if modern versions of bash make it easy to do the same.

  • 1
    That's weird because it says "Stopped" when Ctrl+ Z is pressed. In either case: It has the problem described in point 1 of the first list in the question. – UTF-8 May 01 '17 at 11:55
  • Unfortunately, this only works if the running command doesn't continuously write to stdout. – Raphael Mar 14 '24 at 22:08
  • @Raphael It works even if the command writes to stdout. It's annoying to have the command print a lot of output that prevents you from seeing what you type, but you can still interact with the shell while the command is spamming your terminal from the background. – Gilles 'SO- stop being evil' Mar 14 '24 at 23:13
1

You most likely want:

wait $pid

If you aren't running in the same shell you can't use a built in and will need a workaround. See discussion here.

user1794469
  • 4,067
  • 1
  • 26
  • 42
  • Does this mean I should end all commands with an & so I get the PID of the process? Even if I did this, I couldn't wait for the process in a different terminal (using wait), so I'd have to write in the output of the previous command, again. – UTF-8 Apr 30 '17 at 16:08
  • No you don't have to start them i in the background. you can send them to the background while they are running and get their pid using ps. You won't have to write the output of the previous command but yoiu will have to start the new job in the same shell, i'm not sure why that would be a problem. – user1794469 Apr 30 '17 at 18:02
  • I don't know how you can send commands directly to the background. I only know of the ctrl + Z and then bg method. But if I do this (which is fairly quick), I have to decide between writing in the output of the then-resumed command after entering bg and writing bg && secondCommand where otherCommand may be complex and take me quite some time to write. And if I then want to add a third command before the first one terminates, the whole thing breaks because secondCommand won't be executed if I do the exact same thing again. So I think I don't know what you're talking about. – UTF-8 Apr 30 '17 at 18:33
1

You can create a named pipe (this needs to be done once):

mkfifo ~/myfifo

Then from a terminal (let's call it terminal A) you can say:

exec 10< ~/myfifo

To assign the read end of the pipe to file descriptor 10, you can use any other number above 2 (so the standard input, output and error remains available if another command needs it).

Then from another terminal (let's call it terminal B) you can say:

cat - > ~/myfifo

To complete the connection to terminal A which then returns the prompt. This command writes what you enter from the standard input into the pipe. Then you can enter the following into terminal A:

while read -u10 -r LINE; do eval "$LINE"; done

So it will execute the commands you type in terminal B. The read command will read lines from file descriptor 10 and execute it with eval. eval allows you to run shell commands such as exporting variables.

As long as terminal A is open you can interrupt the loop with Ctrl+C so you can enter commands again then later you can restart the loop to start running the remaining queued commands.

The exec and while commands can be put into a shellscript so you can use the Ctrl-Z fg && yourscript to activate the pipe mode if you forgot to do it at the beginning.

Calmarius
  • 625
  • 2
  • 5
  • 15
  • Sweet! Worth the 6.5 year wait :D Thank you! But your "then" makes it appear as though I had to enter everything that's in the 2nd code block before entering what's in the 3rd code block into a separate terminal. However, my first terminal didn't show me a prompt after I entered the first command of the second code block. It only showed me a prompt after I had entered the command that's in the third code block into a separate terminal. I think you should re-phrase this to make your answer more helpful to others. – UTF-8 Oct 16 '23 at 17:49
  • I also have a question: What does 10< do? – UTF-8 Oct 16 '23 at 17:50
  • 1
    @UTF-8 Indeed, I tested it by putting the first two commands into a script so I don't need to retype them as I tweaked it, I didn't notice that it blocks on the first command. The 10< means opening the file for reading and assign it to file descriptor 10.

    I updated the answer.

    – Calmarius Oct 17 '23 at 19:36
0

Assuming the premise that you cannot open a second terminal/connection, you can run your session in a terminal multiplexer, such as screen or tmux.

Then you can easily open another session at any time to get more done while waiting for a command to finish in the current session.

This also has the benefit of keeping the session(s) alive, should the connection/emulator get interrupted for any reason.

Mio Rin
  • 3,040
  • 1
    I can keep as many concurrent terminal sessions open as I want. What feature of screen allows me to schedule future commands? – UTF-8 Apr 30 '17 at 16:04
0

EDIT: I misinterpreted the question, but the technique below might still be useful to people when running commands in a bash script (so they have single PID)

This is what I use (on Linux), when command1 is printing useful output and I just want to start another process in a another shell once it's finished (that is, I don't want to background command1):

tail --pid=$command1_pid -f /dev/null; command2

where $command1_pid is the PID of the process you are waiting to finish

(I think I originally found it here: https://stackoverflow.com/a/41613532/1676393. See there for helpful other details. Such as a version that will work on Darwin (macOS))


Step by step:

  • stop command1 with Ctrl + Z
  • run ps, then look for the process corresponding to command1, and find its PID
  • then restart the process of command1 by typing fg, and in a new shell, run the above command

Like this, command2 will start in the new shell when command1 is done in the old shell.

postylem
  • 101
  • This doesn't work for the same reason the other answers don't work: If several commands are queued, they don't have a common PID. In fact, only the command currently running has a PID at all. – UTF-8 May 13 '21 at 11:22
  • Ah you are correct, of course! I use this when my commands are in a bash script, but of course you're right... I'll leave this here in case someone finds it useful, but edit it to make it clear it doesn't work for your case? – postylem May 13 '21 at 16:38