While loop processa apenas a primeira entrada do comando ssh

2

Então eu não sei muito sobre o bash e preciso de ajuda profissional. Estou tentando executar um script como este:

filename='file1'
while read p; do
ssh -p 2222 $p 'who -b' | awk '{print $(NF-1)" "$NF}' >> file2*

O que eu estou tentando fazer é um script que passa por todos os endereços no arquivo1 para ver quando eles foram reinicializados pela última vez e, em seguida, mas a resposta no arquivo2.

O problema é que ele só passa pelo primeiro endereço e não pelo outro.

O primeiro endereço tem uma senha que eu preciso digitar para continuar o processo. Pode este ser o problema ou eu especifico cada linha no arquivo 1 ou estou fazendo absolutamente errado para começar?

    
por Ludvig 23.11.2017 / 11:08

2 respostas

5

Finalmente, assumi que a parte restante do script está bem. Então eu segui o @ comment da sobremesa e usei shellcheck que me leva à questão real e sua solução:

  

SC2095 : Adicione < /dev/null para evitar que o ssh engula stdin.

Então você precisa alterar seu script desta maneira:

ssh -p 2222 "$p" 'who -b' < /dev/null | awk '{print $(NF-1)" "$NF}' >> 'file2'

De acordo com a resposta original e graças aos conselhos úteis, fornecidos nos comentários por @EliahKagan e @ rexkogitans , o script completo poderia ser assim:

#!/bin/bash

# Collect the user's input, and if it's empty set the default values
[[ -z "" ]] && OUT_FILE="reboot-indication.txt" || OUT_FILE=""
[[ -z "" ]] && IN_FILE="hosts.txt" || IN_FILE=""

while IFS= read -r host; do
    indication="$(ssh -n "$host" 'LANG=C who -b' | awk '{print $(NF-1)" "$NF}')"
    printf '%-14s %s\n' "$host" "$indication" >> "$OUT_FILE"
done < "$IN_FILE"
  • < /dev/null/ é substituído pela opção -n do comando ssh . De man ssh :

    -n   Redirects stdin from /dev/null (actually, prevents reading from stdin). 
         This must be used when ssh is run in the background... This does not work 
         if ssh needs to ask for a password or passphrase; see also the -f option.
    
  • IFS= read -r line - como @ StéphaneChazelas diz em sua resposta enciclopédica - é o caminho canônico para leia uma linha de entrada com o read builtin .

    • A chave é que read lê palavras de uma linha (possivelmente barra invertida continuada), em que palavras são $IFS delimitadas e barra invertida podem ser usadas para escapar dos delimitadores (ou continuar linhas). Portanto, o comando read deve ser ajustado para ler as linhas.

    • IFS= altera o separador de campos interno para a cadeia nula , Assim, preservamos os espaços em branco iniciais e finais no resultado.

    • A opção -r - r aw input - desativa a interpretação de escapes de barra invertida e continuação de linha nos dados lidos ( referência ).

  • printf '%s %s' "$VAR1" "$VAR2" fornecerá um melhor formato de saída ( referência ).

  • LANG=C garantirá uma saída idêntica de who -b em cada servidor, assim, a análise da saída com awk também será garantida.

  • Observe aqui que o arquivo ~/.ssh/config e parâmetros adicionais como -p 2222 não são necessários ( referência ).

Chame o script acima de ssh-check.sh (não se esqueça de chmod +x ) e use-o desta forma:

  • Use os valores padrão dos arquivos de entrada ( hosts.txt ) e de saída ( reboot-indicação.txt ):

    ./ssh-check.sh
    
  • Defina o valor personalizado para o arquivo de saída; defina o valor personalizado também para os arquivos de entrada:

    ./ssh-check.sh 'my-custom.out'
    ./ssh-check.sh 'my-custom.out' 'my-custom.in'
    

Leia esta resposta para ver como toda a abordagem poderia ser melhorada.

    
por pa4080 23.11.2017 / 11:50
5

Você esqueceu de fechar o loop while-do. Adicione done ao final.

filename='file1'
while read p; do
   ssh -p 2222 $p 'who -b' | awk '{print $(NF-1)" "$NF}' >> file2*
done
    
por ravery 23.11.2017 / 11:14