Menu for managing SSH ZSH sessions

I am trying to create a script that helps me manage SSH sessions with ZSH.

This works, but it does not export my ZSH config like normal ZSH with Z4H would:

#!/usr/bin/zsh

PS3="Enter session nr.: "

select sshs in a@a b@a b@a b@b "Quit Menu"
do
    case $sshs in
        "a@a")
           ssh a@a -p 224 && break;;
        "b@a")
           ssh b@a -p 224 && break;;
        "a@b")
           ssh a@b -p 225 && break;;
        "b@b")
           ssh b@b -p 225 && break;;
        "Quit Menu")
           break;;
        *)
           echo "Invalid input";;
    esac
done

I suspect the SSH command is the tricky part here, because …

which ssh
ssh () {
        z4h ssh "$@"
}

I tried substituting ssh for ssh () {z4h ssh “$@”} and z4h ssh, but to no avail. Got tips?

It’s generally best to script in bash.

Well you can unset the function in your script

unset -f ssh

or find where the function is defined and remove it.

Well, honstly, makes no sense to create such script. Just create a config and use alias to connect.

File: $HOME/.ssh/config

Host serverA
    HostName 1.2.3.4
    IdentityFile ~/.ssh/serverA
    Port 224
    Preferredauthentications publickey
    User userA
Host serverB
    HostName 2.3.4.5
    IdentityFile ~/.ssh/serverB
    Port 224
    Preferredauthentications publickey
    User userB
Host serverC
    HostName 3.4.5.6
    IdentityFile ~/.ssh/serverC
    Port 225
    Preferredauthentications publickey
    User userC
Host serverD
    HostName 4.5.6.7
    IdentityFile ~/.ssh/serverD
    Port 225
    Preferredauthentications publickey
    User userD

Now just connect with:

ssh serverA

It also supports auto-completion when typing TAB.

5 Likes

Great tip, this simplifies things a lot, but I still see the benefit in having a menu list your options.

If you install dialog — it’s in the repos — then you can create an ncurses-based menu with it.

I don’t know whether it works with zsh, but it certainly does work with bash.

Unfortunately, I am not at all familiar with set, unset and functions substituting command paths. Also, I am not that familiar with Z4H or ZSH customization. And for now, I would rather not unset the function, just in case it breaks the current functionality I enjoy.

Also, I know that scripting in bash is more portable, but I am trying to make all of my environments run ZSH, so I won’t care until I find myself in a pinch.

It would only be temporary, unless you found the definition for the function and removed it. Absolutely worst case, you can redefine the function yourself, you already have a copy in the first post.


However there are other options:

I found a new command, this will ignore the function.

command ssh b@a -p 224

Or you can just use the full path.

/usr/bin/ssh b@a -p 224

Not sure this will solve your problem though.

1 Like

None of these options solves the issue. I think the function is what is actually producing the desirable results, that’s why I was trying to call it in my script.

Ah, I was thinking it was getting in the way :crazy_face:.The script you showed didn’t have that function, and you said you’d tried to substitute ssh for the function (but you meant you’d tried to substitute the function for ssh). Clearly I focused on that and forgot about, amongst other things, the 2nd line of your post. :man_facepalming:

Try adding this near the top of your script:

source ~/.zshenv
source ~/.zshrc

No worries and thanks for trying to help.

The files are there, but I get the following errors.

~/.zshenv:source:3: no such file or directory: ~/.zshenv
~/.zshrc:source:4: no such file or directory: ~/.zshrc

I have also tried with quotation marks for the paths, full paths and calling the sources within the “then” statements, but to no avail.

This is how my .zshrc file starts:

# Source additional local files if they exist.
z4h source ~/.env.zsh

#Source zsh-configuration
if [[ -e /path/custom-extras.zshrc ]]; then
  source /path/custom-extras.zshrc
fi
if [[ -e /path/custom-p10k.zsh ]]; then
  source /path/custom-p10k.zsh
fi

Those errors are from your script, please show the current code. Showing the paths to the files wouldn’t hurt.

Quoting interferes with the ~ expansion (like in those errors), but the full path should work either way.

1 Like

With the risk of being a complete idiot here. Where do you call the ssh function?

The cases runs the ssh command in your terminal (connects), not the function, if you want to call the function you have to ssh 'a@a -p 224' and then fetch that with $* inside the function.
But I have no idea how it will react, since there is an ssh command in shell…

So, why call the function ssh exactly? That makes things confusing. Call it fex ssh_function instead, that makes it way safer to call it since it does not have the same name as a program. ssh_function 'a@a -p 224'

And on top, if you hardcode the case:s, why not run the z4h command directly there? Why the function?

I believe they’re using this

and would like to use the ssh function defined there. It wraps ssh and copies the config over to the remote.

1 Like

Ah, I understand, I WAS the idiot. :upside_down_face:
Thanks for clarifying, that changes quite a bit.

2 Likes

Join the club. :smiley:

@bedna , @dmt the more you are the more you help.

@dmt, I already tried with the full paths for the directories in the source commands and it didn’t work. I am not familiar with source, but that is very strange behavior.

# Personal Zsh configuration file. It is strongly recommended to keep all
# shell customization and configuration (including exported environment
# variables such as PATH) in this file or in files sourced from it.
#
# Documentation: https://github.com/romkatv/zsh4humans/blob/v5/README.md.


# Source additional local files if they exist.
z4h source ~/.env.zsh

#Source zsh-configuration
if [[ -e /home/username/Home\ Data\ Cluster/Linux/Custom\ ZSH/Deploy/custom-extras.zshrc ]]; then
  source /home/username/Home\ Data\ Cluster/Linux/Custom\ ZSH/Deploy/custom-extras.zshrc
fi
if [[ -e /home/username/Home\ Data\ Cluster/Linux/Custom\ ZSH/Deploy/custom-p10k.zsh ]]; then
  source /home/username/Home\ Data\ Cluster/Linux/Custom\ ZSH/Deploy/custom-p10k.zsh
fi

I don’t think the paths are the problem. They work when I ssh into machines any other way.

The file for “custom-p10k” is very generic, I only changed a few powerline parameters.

My other script is just aliases and such.

########################################
# ALIASES
########################################

####################
#PROGRAMS
####################

alias m='micro'

####################
#NAVIGATION
####################

alias hd='cd ~'
alias ud='cd ..'
alias pd='pushd'
alias d1='pushd +1'
alias d2='pushd +2'
alias d3='pushd +3'
alias d4='pushd +4'
alias d5='pushd +5'
if [[ @USER == root ]]
then
alias sd="dirs -v | awk 'NR>1' | awk '!seen[$2]++'"
else
alias sd="dirs -v | awk 'NR>1'"
fi
alias ppd='popd'

####################
#COMMANDS
####################

alias ll='ls -lh'


########################################
# ENVIRONMENT
########################################

# Editor
export EDITOR=/usr/bin/micro

I don’t think they are the problem, because again, the export works when I ssh into machines any other way.

Correct, but the script calls a regular ssh, instead of the z4h version of it.

A source is just you pulling the contents of another file right into the file you run the command from.
And I think, overwrite if the same text exists? Correct me if I’m wrong @dmt

Try removing z4h to begin with.
Of if you want to use it as a variable, add a =. xD

I am not familiar with z4h to be honest so I most likely wont be much help anyway.

I thought you wanted a simple script with a menu, and depending on the choice a command line was selected and ran.

So, I don’t know why I didn’t find it before, I think I looked, but Z4H also has a function:

z4h () {
        if (( ${+functions[-z4h-cmd-${1-}]} ))
        then
                -z4h-cmd-"$1" "${@:2}"
        else
                -z4h-cmd-help >&2
                return 1
        fi
}

I just don’t understand how these functions work. They are very intricate.

What throws me off is that when I call “ssh” from the terminal I am clearly calling that function, and when the script calls it, it is calling the regular command like it where from “/usr/bin/ssh”, no matter whether the script starts in #!/usr/bin/bash or #!/usr/bin/zsh and also regardless of having the full path to ssh “/usr/bin/ssh” or just “ssh”. Also, the storage cluster works fine. All the files are there.

We need to see the script, not the files you’re trying to source.

I don’t either, but never hurts to check. You did say you’d tried versions that should work.

Scripts don’t inherit your environment. That’s why you’d need to source the config.

@bedna

Nope, sorry.

It passes the contents of the file to the Tcl interpreter. If you source a file from the terminal it’ll run it in the current shell (with the same environment, ie vars etc), if you run the script directly it’ll run in a child shell with a different environment.

When sourced in a script, it will presumably run the script in the same shell as the parent script.

I’m sure @aragorn can explain it better. :smile:

3 Likes