(I have read many of the questions on this site that look related and I believe this is a genuinely new question.)I have lots of keys on lots of servers and they're all protected with passphrases.I like entering passphrases about as much as I like entering passwords - it's a real productivity drain.ssh-agent + ssh-add commands can be used on a login shell to mean you only have to enter your passphrase once at loginkeychain can be used to hold an ssh-agent alive beyond logout, so for example you can have it so you only have to enter the passphrase once at boot, or you can have it keep it alive for an hour or so.The problem I have is that both of these solutions typically get initiated in a shell login (e.g. .zshrc) rely on me entering my passphrase when I log in, even if I'm not going to need it unlocked. (I'm not happy with keychain keeping an agent alive indefinitely.)What I would like is to be prompted for a passphrase (for an agent) only when needed.So I can log in to server A, do some stuff, then ssh to server B and at that point be asked for the passphrase. Do some stuff on server B, log out. Back on A, do some more stuff, ssh to B again and not need my passphrase (it's held by an agent).I note that this is possible on graphical desktops like Gnome - you get a pop-up asking for the passphrase to unlock your private key as soon as you try to ssh. So this is what I'm after but from a console.
How to get asked for SSH key passphrase once and only when needed?
ssh;ssh agent
Zsh has a preexec hook that executes a function before a command entered on the commandline is executed. Here's a hook that looks for ssh in your command line and if found, checks for the existence of an ssh agent. If that's not found, it runs keychain.So this way, keychain is only run before ssh commands, and then only if needed.Put this in your ~/.zshrc:function check_ssh {  [[ $3 =~ '\bssh\b' ]] || return  [[ -n $SSH_AGENT_PID && -e /proc/$SSH_AGENT_PID ]] \    && ssh-add -l >/dev/null && return  eval `keychain --eval id_dsa --timeout 60`}    autoload -U add-zsh-hookadd-zsh-hook preexec check_sshWhat happens here is whenever a command is typed, check_ssh is called before the command is executed.The first line of the function checks the expanded command for ssh using a Zsh regex. ssh must have word boundaries \b either side. If this is not found then the function returns.The next line checks that there's an SSH agent process in the environment variable, and that that process exists in the process table still, and then that at least one key has been added to the agent. If all of that is OK, then ssh agent is set up and we don't need to do anything, so it returns.Finally we start keychain, with the agent to be kept alive for an hour.It still leaves the problem about embedded ssh stuff, like git or rsync or scp as that won't trigger the function (you could add these to the regex).