web-dev-qa-db-fra.com

While loop ne traite que la première entrée de la commande ssh

Donc, je ne connais pas grand chose à propos de bash et j'ai besoin de l'aide d'un professionnel. J'essaye de lancer un script comme celui-ci:

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

ce que j'essaie de faire est un script qui passe en revue toutes les adresses de fichier1 pour voir quand elles ont été redémarrées pour la dernière fois, puis la réponse dans fichier2.

Le problème, c'est qu'il ne s'agit que de la première adresse et non de l'autre.

La première adresse a reçu un mot de passe que je dois taper pour poursuivre le processus. Peut-être que ce soit le problème ou est-ce que je spécifie chaque ligne de fichier1 ou est-ce que je me trompe complètement au début?

2
Ludvig

Enfin, j'ai supposé que la partie restante du script est correcte. Puis j'ai suivi commentaire de @ dessert et utilisé shellcheck qui m'a amené au problème et à sa solution:

SC2095 : Ajoutez _< /dev/null_ pour empêcher ssh d’avaler stdin.

Donc, vous devez changer votre script de cette façon:

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

Selon le réponse originale et grâce aux conseils utiles fournis dans les commentaires par @ EliahKagan et @ rexkogitans , le script complet pourrait ressembler à cette:

_#!/bin/bash

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

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/_ est remplacé par l'option _-n_ de la commande 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_ - comme le dit @ StéphaneChazelas dans sa réponse encyclopédique - est le moyen canonique de lire une ligne d'entrée avec le read intégré.

    • La clé est que read lit les mots d'une ligne (éventuellement des barres obliques inversées), où les mots sont délimités par _$IFS_ et la barre oblique inverse peut être utilisée pour échapper aux délimiteurs (ou lignes suivantes). La commande read doit être modifiée pour lire les lignes.

    • _IFS=_ change le séparateur de champ interne en chaîne nulle , nous conservons donc les espaces de début et de fin dans le résultat.

    • L'option _-r_ - r entrée aw - désactive l'interprétation des échappements de barre oblique inversée et la poursuite de la ligne dans les données lues ( - référence ).

  • _printf '%s %s' "$VAR1" "$VAR2"_ fournira un meilleur format de sortie ( référence ).

  • _LANG=C_ garantira une sortie identique de _who -b_ sur chaque serveur, ainsi l'analyse de la sortie avec awk sera également garantie.

  • Remarque: supposons qu'il existe un fichier _~/.ssh/config_ et que des paramètres supplémentaires tels que _-p 2222_ ne sont pas nécessaires ( ---] [référence ).


Appelez le script ci-dessus _ssh-check.sh_ (n'oubliez pas de _chmod +x_) et utilisez-le de cette façon:

  • Utilisez les valeurs par défaut des fichiers d'entrée (hosts.txt) et du fichier de sortie (reboot-indication.txt):

    _./ssh-check.sh
    _
  • Définir une valeur personnalisée pour le fichier de sortie; définir une valeur personnalisée également pour les fichiers d'entrée:

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

Lire cette réponse pour voir comment toute l'approche pourrait être améliorée.

5
pa4080

Vous avez oublié de fermer la boucle while-do. Ajoutez done à la fin.

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