SSH faz com que o loop while pare

30

Finalmente consegui resumir um problema com o qual estou lutando há algumas semanas. Eu uso o SSH com "chaves autorizadas" para executar comandos remotamente. Tudo está bem, exceto quando eu faço isso em um loop while. O loop termina após a conclusão de qualquer iteração com um comando ssh.

Por um longo tempo, pensei que isso fosse algum tipo de estranheza do ksh, mas agora descobri que o bash se comporta de maneira idêntica.

Um pequeno programa de amostra para reproduzir o problema. Isso é extraído de uma implementação maior, que tira instantâneos e os replica entre os nós em um cluster.

#!/bin/bash

set -x

IDTAG=".*zone"
MARKER="mark-$(date +%Y.%m.%d.%H.%M.%S)"
REMOTE_HOST=sol10-target
ZFSPARENT=rpool

ssh $REMOTE_HOST zfs list -t filesystem -rHo name,mounted $ZFSPARENT | grep "/$IDTAG    " > /tmp/actionlist

#for RMT_FILESYSTEM in $(cat /tmp/actionlist)
cat /tmp/actionlist | while read RMT_FILESYSTEM ISMOUNTED
do
   echo ${RMT_FILESYSTEM}@${MARKER}
   [ "$ISMOUNTED" = "yes" ] && ssh $REMOTE_HOST zfs snapshot -r ${RMT_FILESYSTEM}@${MARKER}
   echo Remote Command Return Code: $?
done

(Observe que há um caractere TAB na expressão grep search conforme a definição do comportamento da opção "-H" da lista zfs.)

Minha amostra possui alguns sistemas de arquivos ZFS para a raiz, onde todas as "zonas" têm seu sistema de arquivos raiz em um conjunto de dados chamado similar a

POOL / zonas / app1zone
POOL / zonas / group2 / app2zone

etc.

O loop acima deve criar um instantâneo para cada um dos conjuntos de dados selecionados, mas, em vez disso, opera apenas no primeiro e depois sai.

O fato de o programa encontrar o número certo de conjuntos de dados pode ser facilmente confirmado verificando o arquivo "/ tmp / actionlist" após a existência do script.

Se o comando ssh for substituído por, por exemplo, um comando echo, o loop percorrerá todas as linhas de entrada. Ou o meu favorito - acrescente "eco" ao comando incorreto.

Se eu usar um loop for em vez disso, ele também funcionará, mas devido ao tamanho potencial da lista de conjuntos de dados, isso pode causar problemas com o comprimento máximo da linha de comando expandida.

Agora tenho 99,999% de certeza de que apenas aqueles loops com comandos ssh me causam problemas!

Observe que a iteração na qual o comando ssh é executado é concluída! É como se os dados transmitidos para o loop while fossem repentinamente perdidos ... Se as primeiras linhas de entrada não executarem um comando ssh, o loop continuará até que realmente execute o comando SSH.

No meu laptop em que estou testando isso, tenho duas VMs Solaris 10 com apenas dois ou três conjuntos de dados de amostra, mas o mesmo está acontecendo nos grandes sistemas SPARC em que isso deve ser lançado, e há muitos conjuntos de dados.

Johan
fonte
7
O SSH pode estar lendo da entrada padrão, consumindo o seu actionlist. Tente redirecionar a entrada padrão do ssh para/dev/null
BatchyX
Vou tentar isso. Quero acrescentar que colocar ssh em um invólucro não ajuda ....
Johan
Você está certo. Como eu não pude ver isso !?
26413 Johan Johan
@BatchyX Acho que seu comentário se qualifica como resposta.
a CVn 26/02
Concordo que gostaria de "aceitar" a resposta, portanto, se o @BatchyX puder repassá-la como tal, eu o farei.
26413 Johan Johan

Respostas:

43

O SSH pode estar lendo da entrada padrão, consumindo sua lista de ações. Tente redirecionar a entrada padrão do ssh para / dev / null:

ssh $REMOTE_HOST zfs snapshot -r ${RMT_FILESYSTEM}@${MARKER} </dev/null

Como regra geral, ao executar comandos que podem interferir na entrada padrão em um while readloop estilo, eu gosto de envolver todo o corpo do loop em chaves:

cat /tmp/uuoc | while read RMT_FILESYSTEM ISMOUNTED
do {
    echo ${RMT_FILESYSTEM}@${MARKER}
    [ "$ISMOUNTED" = "yes" ] && ssh $REMOTE_HOST zfs snapshot -r ${RMT_FILESYSTEM}@${MARKER}
    echo Remote Command Return Code: $?
} < /dev/null; done
BatchyX
fonte
3
O dobro de impressionante para o uso específico das chaves ... que eu nunca encontrei em 20 anos de script (pelo menos não me lembro). E pela inferência uuoc. FWIW (e em minha própria defesa) às vezes faço uma exceção e adiciono declarações redundantes de gatos por uma questão de legibilidade! Adoro este fórum porque, de repente, estou aprendendo coisas novas novamente! Especificamente, eu gosto de adicionar redirecionamentos ao início de linhas como este caso, mas em fóruns que parecem confundir o assunto, fazendo com que eu obtenha menos respostas úteis!
26413 Johan Johan
Eu tenho tentado descobrir a diferença entre {...} e (...) a página de manual do ksh diz que {...} são palavras-chave especiais reconhecidas apenas no início de uma linha de comando. Mas há outra diferença ... ( </tmp/file [ -z "$SOMEVAR" ] && awk '{print "X", $0}' )difere da mesma maneira com o aparelho. Quero dizer, em termos de saída produzidos, e não sobre o fato de que a chave de fechamento deve estar em uma nova linha ...
Johan
5
Além disso, o ssh do OpenSSH tem a -nopção de fazê-lo (efetivamente) reabrir seu stdin a partir de / dev / null.
31813 Chris Johnsen
Alguma solução alternativa para usar sudocom o comando dentro do loop?
bonh 29/08/16
Eu costumava usar -n desde idades e em algum ponto perdido o hábito .... e agora eu novamente sei por que fiz isso, depois de algum tempo passou escavação ...
Florian Heigl