Eu encontrei uma solução bastante portátil (não precisa de nenhuma edição nos arquivos de configuração ssh, e é facilmente contida no próprio script de chamada, e é bem fácil de usar): apenas junte os sshs, e o último chama o shell (ksh ou bash funcionam bem para os unixes "um pouco mais antigos"):
echo "for remotedir in /some/path/*/ ; do \
cd \"\$remotedir\" && \
something using $thisLOCALvariable \
; done" | ssh user1@host1 ssh user2@host2 ssh user3@host3 "bash"
# note: the 'obvious' approach:
# ssh u1@h1 ssh u2@h2 "cmd1 ; cmd2; ..."
# does NOT work : it would execute "cmd2; ..." on h1, not on h2 !!!
# only cmd1 would be executed on h2 ... BE CAREFUL ! (at least on a not-too-old cygwin)
Esse exemplo mostra que podemos misturar variáveis locais e remotas ... e a necessidade de "escapar" das remotas, bem como de aspas duplas, etc ... alguns cuidados precisam ser tomados para garantir que façamos o que pretendíamos fazer.
Mas é muito útil, pois há sempre o mesmo nível de cotação (apenas 1!), mesmo se agruparmos 3 ou mais aninhamento ssh, o que é bastante útil ... É semelhante ao que $(cmd)
traz em comparação com a antiga abordagem '
(backtick): simplifica a escrita sem ter que levar em conta o nível de aninhamento.
caveat : ter isso como parâmetros para um script (como eu perguntei na pergunta: on_all_servers "for dir in /something* ; do cd \"\$dir\" && something using $thisLOCALvariable ; done"
) é um pouco mais difícil de descobrir, como o shell de chamada interpreta primeiro o "\ "e aspas ... então, por enquanto, eu uso a versão de linha de comando (ou uma construção semelhante dentro de um script, mas não um script que obtenha a linha de comando de seus argumentos) ...
Eu ainda deixo a questão aberta, esperando que alguém obtenha uma solução ainda melhor (ou uma melhoria desta, ie: permitir que um comando similar seja passado como parâmetro para um "script de chamada")
Editar : Eu também descobri como fazer extração remota de alcatrão usando este método! Não é trivial, como stdin precisa ser dado ao shell remoto, uma vez para chegar ao diretório apropriado, então o tar local tar - precisa ser encaminhado para esse tar remoto no local adequado: aqui vai:
# the easy one, nothing special needed: from remote to local:
echo "cd /remote/path && tar cf - *" | ssh user1@host1 ssh user2@host2 ssh user3@host3 "bash" | ( cd /local/path && tar xvf - )
# and the hard one: the other way around: needs a trick:
( cd /local/path && tar cf - * ) | { { echo "cd /remote/path/ && tar xvf -" ; cat ;} | ssh user1@host1 ssh user2@host2 ssh user3@host3 "bash" ;}
#once again: this trick allows you to have 1, 2, or any level of ssh.
# PLEASE NOTE: I just run bash, and feed it the command, to avoid
# the command to be split between the remote hose and the first hop!
# ex of the way the 'obvious' way fails:
# ssh user1@host1 ssh user2@host2 "hostname ; hostname;"
# will return not twice the name "host2", but "host2" then "host1" !!
# which means the first part of the command was executed on the last hop,
# but then the rest of it was executed on the first hop!!! DANGEROUS!
# that is why I choose instead to use that way:
# echo "hostname; hostname" | ssh user1@host1 ssh user2@host2 "bash"
# this one properly executes the full (complex) command on host2