2

Refer to this unanswered question before continuing: Tmux: check exit code of command that was sent by send-keys

tmux send-keys just sends the command and exit successfully but repeat 5; do print This is a test; sleep 1; done still continue running as a subprocess - not in a subshell.

In case I need to make sure repeat 5; do print This is a test; sleep 1; done completely done before doing another tmux send-keys.

How could I achieve that with zsh?

EDIT: @Stéphane Chazelas: I'd like to extend or make the question more clear:

In case of a zsh script that contain multiple send-keys commands as below:

send-keys 'command1_run_as_subprocess_with_unpredictable_time_to_complete' Enter
send-keys 'command2_run_as_subprocess_with_unpredictable_time_to_complete' Enter
send-keys 'command3_run_as_subprocess_with_unpredictable_time_to_complete' Enter
<...>

Each send-keys has to wait for the previous one totally completed before running.

How your solution would apply to above case?:

typeset -A pane_pid=($(for t (id index) tmux lsp -F "#{pane_$t} #{pane_pid}"))

pid=$pane_pid[%0] # pid of process started in first pane

1 Answer 1

1

I suppose you could wait until the shell running in that tmux pane reads from the terminal device again:

If on Linux,

until grep -qw tty_read "/proc/$pid/stack"; do sleep 1; done

where $pid is the process id of that shell.

Or more efficiently and with a smaller delay with zsh:

zmodload zsh/zselect
until [[ $(</proc/$pid/stack) = *tty_read* ]] zselect -t 10

Note that you need /proc/sys/kernel/yama/ptrace_scope to contain 0 for that to work (for processes to be able to look into what other processes are doing like that). Beware that changing that value to 0 (with sudo sysctl -w kernel.yama.ptrace_scope=0) slightly reduces the security of the system.

To get a mapping between tmux pane id or index and pid of the process it ran in there, you can do:

typeset -A pane_pid=($(for t (id index) tmux lsp -F "#{pane_$t} #{pane_pid}"))

pid=$pane_pid[%0] # pid of process started in first pane

So combining both:

zmodload zsh/zselect
wait_for_shell_on_pane_to_read_tty() {
  local pane=$1
  local -A pane_pid=($(for t (id index) tmux lsp -F "#{pane_$t} #{pane_pid}"))
  until [[ $(</proc/$pane_pid[$pane]/stack) = *tty_read* ]] zselect -t 10
}

pane=%0 # replace with the pane you want to send those commands to
        # see tmux lsp for the list of panes

for cmd (
  'repeat 5; do print This is a test; sleep 1; done'
  command1_run_as_subprocess_with_unpredictable_time_to_complete
  command2_run_as_subprocess_with_unpredictable_time_to_complete
  command3_run_as_subprocess_with_unpredictable_time_to_complete
) {
  wait_for_shell_on_pane_to_read_tty $pane
  tmux send-keys -t $pane $cmd Enter
}

Note that since we're sending those command lines in sequence without delay between them, the shell in the pane may still be reading from the tty after we've sent the first command (and hasn't executed it yet) which could cause several command lines to be sent at once.

4
  • Thanks, I've just edit the question for more details, can you take a look?
    – Tuyen Pham
    Sep 19, 2018 at 13:35
  • @TuyenPham see edit Sep 19, 2018 at 15:37
  • I've got this error when trying to execute the snippet: error when reading /proc/28850/stack: operation not permitted
    – Tuyen Pham
    Sep 20, 2018 at 2:58
  • Thanks, I've just revised this issue, is there anyway that we can avoid /proc/<..>/stack, it sticks to linux distributions and is that something for cmd ( <..> ) {...} work with bash?
    – Tuyen Pham
    Jan 5, 2019 at 1:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.