yudai / sshh

A SSH session duplicator for tmux
Apache License 2.0
80 stars 10 forks source link

Fish shell: Changes needed to get working in Fish shell #4

Open ElijahLynn opened 6 years ago

ElijahLynn commented 6 years ago

After many hours of debugging, IT WORKS in FISH SHELL!!!!

These are mostly notes for myself on what I had to do to get this working with Fish shell but I really hope they help others as well (https://superuser.com/a/1317624/30982).

1) Had to set the PATH for bash (even though it is fish shell), see #3.

2) Fix shebang, https://github.com/yudai/sshh/pull/2

3) I had to change the bindings in .tmux.conf to:

bind-key C-t run-shell "tmux split-window -h \"set --export SSHH_INDEX (tmux display-message -p \",#{pane_index}\");fish --login \"" \; send-keys -t:+0 "sshh \$SSHH_INDEX" Enter

Using send-keys without a -t just tried running sshh in the source pane for some reason (tmux bug?), so using -t:+0 actually specifies the pane. The + is actually an alias for the next pane and the tokens ‘+’ and ‘-’ may be followed by an offset. We can use - or + as the offset is the same.

From man tmux: {next} + The next pane by number {previous} - The previous pane by number

4) I had to patch the sshh script, which added the elif to check for a grandchild, otherwise it would only work properly on the first split, and fail subsequent splits. This is because in the bind we set the variable in fish (not VAR=VALUE) and then we call fish --login, this results in 2 commands and then fish launches a subshell, so ssh is actually in the subshell/grandchild PID.

for child_pid in $(pgrep --parent ${pane_pid}); do
    child_cmd=$(ps ${child_pid} | tail -n 1 | awk '{for(i=5;i<NF;i++) printf("%s ",$i); print $NF}')
    if [ $(echo "${child_cmd}" | awk '{ print $1 }') = 'ssh' ]; then
        echo "${child_cmd}"
        eval "exec ${child_cmd}"
    # Fish grandchild PID.
    elif pgrep --parent ${child_pid}; then
        grandchild_pid=$(pgrep --parent ${child_pid})
        grandchild_cmd=$(ps ${grandchild_pid} | tail -n 1 | awk '{for(i=5;i<NF;i++) printf("%s ",$i); print $NF}')
        echo "${grandchild_cmd}"       
        eval "exec ${grandchild_cmd}"
    else
        echo "Command at Pane #${pane_index} of Window #${window_index} is not SSH."
        echo -n "Do you want to run '${child_cmd}' ? [y/N]: "
        while [ 1 ]; do
            read line
            case $line in
                [yY]) eval "exec ${child_cmd}"; break;;
                [Nn] | "") exit 4;;
                *) echo "Error: [Yy] is expected: "
            esac
        done
    fi

    # Ignore following lines
    break
done

The ps axf output looks like this:

6419 pts/1    Ss     0:00  \_ -fish                                                                           
14349 pts/1    S+     0:00  |   \_ ssh root@example.com                                                                                            
23511 pts/8    Ss     0:00  \_ fish -c set --export SSHH_INDEX (tmux display-message -p ,2);fish --login       
23515 pts/8    S      0:00  |   \_ fish --login                                                                
23527 pts/8    S+     0:00  |       \_ ssh root@example.com        

6419 is the original SSH, then 23511 is the first split, which has the child PID of 23515 as fish, not ssh, and then the grandchild PID is 23527. There is probably a more elegant way to do this but right now this is working code and that makes me happy!