I have just (belatedly) discovered that I can ssh -t from one machine to another and run a command there.

The thought then took me that I should be able to come up with a script that tailed a log file (from a pair) on a machine by doing something like

ssh -t $1 ssh -t $2 tailf /pathtofile/$3/log.log

and indeed if I put in 1,2 and 3 by hand it works just fine.

My problem is that I may have 1,2 or 3 hosts to jump between to make this work.

How would I do this in zsh? I've done some digging and it looks as though shift may be my friend, but I'm a bit lost.


Since I'm not really a zsh user, I will write a sh solution (zsh should be able to execute it too).

The general gist is to create a list with one ssh -t hostname bit for each command line option except for the last one, and then to execute that list as a command.



for arg do
   i=$(( i + 1 ))

   if [ "$i" -lt "$argn" ]; then
       set -- "$@" ssh -t "$arg"
       set -- "$@" "/pathtofile/$arg/log.log"

command "$@"

Running this as

sh script.sh alpha beta gamma zeta

it would create the list

ssh -t alpha ssh -t beta ssh -t gamma /pathtofile/zeta/log.log

The last command in the script would execute this as a command.

The list is built in $@, the list of positional parameters, which at the start of the script contains the command line parameters of the script. The loop keeps track of when the last element of that original list is encountered and treats it specially.

The set command, when used as above, will append to the list, and shift will remove the first element of the list (the one we are currently processing).

I'm sure this could be made shorter and more elegant with zsh-specific syntax.

| improve this answer | |
  • I learned this just yesterday! zsh -c 'set -- alpha beta gamma zeta; print -- "-t "${^@}' – Jeff Schaller Sep 5 '18 at 13:19
  • 1
    @JeffSchaller, except that it would become like "-t $1" "-t $2".... Using o=-t; print -- "${(@)o:^^argv}" would make it "-t" "$1" "-t" "$2", but here you want "ssh" "-t" "$1" "ssh" "-t" "$2", and actually even rather ssh -t "$1" "ssh -t quoted-$2 \"... – Stéphane Chazelas Sep 5 '18 at 21:11
  • Where do you find a reference to the arcane incantations such as "$0" etc for these scripts? – Peter Nunn Sep 6 '18 at 22:23
  • @PeterNUnn I don't think I used $0 in this script. Are you asking where to find more information about the sh shell? In that case, I tend to read the POSIX standard (specifically the "Shell & Utilities" section). – Kusalananda Sep 7 '18 at 5:45

I don't think you can easily get away without a loop:

for i ($argv[1,-2]) cmd+=(ssh -t $i)
$cmd tailf /pathtofile/$argv[-1]/log.log

Stritly speaking, since it's a shell command line that you pass to ssh, if you wanted to be able to support arbitrary values for those $1, $2, you'd need quote those arguments and add an extra level of quoting for each ssh.

Here assuming that the login shell of the user on all the hosts is Bourne-like:

cmd=(tailf /pathtofile/$argv[-1]/log.log)
while (($#argv)) {
  cmd=(ssh -t "$argv[-1]" ${(j: :)${(qq)cmd}})

That should make it work when called as

that-script host1 host2 'dir with spaces and other nasty characters'
| improve this answer | |

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.