简体   繁体   中英

Run command in new background tmux window and wait for process to finish

I'm trying to use tmux in a script, so that it runs a command that takes some time (let's say 'ping -c 5 8.8.8.8', for example) in a new hidden pane, while blocking the current script itself until the ping ends.

By "hidden pane", I mean running the command in a new pane that would be sent in background, and is still accessible by switching panes in order to monitor and/or interact with it (not necessarily ping).
(cf. EDIT)

Here is some pseudo bash code to show more clearly what I'm trying to do:

echo "Waiting for ping to finish..."
echo "Ctrl-b + p to switch pane and see running process"

tmux new-window -d 'ping -c 5 8.8.8.8' # run command in new "background" window
tmux wait-for                          # display "Done!" only when ping command has finished

echo "Done!"

I know the tmux commands here don't really have any sense like this, but this is just to illustrate.

I've looked at different solutions in order to either send a command in background, or wait until a process has finished in an other pane, but I still haven't found a way to do both correctly.

EDIT

Thanks to Nicholas Marriott for pointing out the -d option exists when creating a new window to avoid switching to it automatically. Now the only issue is to block the main script until the command ends.

I tried the following, hoping it would work, but it doesn't either (the script doesn't resume).

tmux new-window -d 'ping -c 5 8.8.8.8; tmux wait -S ping' &
tmux wait $!

Maybe there is a way by playing with processes (using fg , bg ...), but I still haven't figured it out.

Similar questions:
[1] Make tmux block until programs complete
[2] Bash - executing blocking scripts in tmux
[3] How do you hide a tmux pane
[4] how to wait for first command to finish?

You can use wait-for but you need to give it a channel and signal that channel when your process is done, something like:

tmux neww -d 'ping blah; tmux wait -S ping'
tmux wait ping
echo done

If you think you might run the script several times in parallel, I suggest making a channel name using mktemp or similar (and removing the file when wait-for returns).

wait-for can't automatically wait for stuff like pane or windows exiting, silence in a pane, and so on, but I would like to see that implemented at some point.

The other answers are only working if you're already within a tmux session. But if you are outside of it you've to use something like this:

tmux new-session -d 'vi /etc/passwd' \; split-window -d 'vi /etc/group' \; attach

If you want to call this within a script you should check whether or not "$TMUX" is set. (Or just unset to force a nested tmux window).

#!/bin/sh
export com1="vi /etc/passwd"
export com2="vi /etc/group"
if [ -z $TMUX ]
then
    export doNewSession="new-session -d 'exit 0'"
else
    export doNewSession=""
fi
tmux $doNewSession \; split-window -d $com1 \; split-window -d $com2 \; attach;
[ -z $TMUX ] && exit 0

My solution was to make a named pipe and then wait for input using read :

#!/bin/sh 

rm -f /wait
mkfifo /wait

tmux new-window -d '/bin/sh -c "ping -c 5 8.8.8.8; echo . > /wait"'

read -t 10 WAIT <>/wait

[ -z "$WAIT" ] && 
  echo 'The operation failed to complete within 10 seconds.' ||
  echo 'Operation completed successfully.'

I like this approach because you can set a timeout and, if you wanted, you could extend this further with other tmux controls to kill the ongoing process if it doesn't end the way you want.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM