Quel est le problème avec cette boucle While?


3

Contexte

J'ai créé un script pour:

  • Lire une liste d'adresses IP une à la fois
  • Copier un fichier de configuration de l'hôte local vers l'hôte distant
  • Redémarrer l'hôte distant
  • Fermer la session ssh en cours

Contenu du script:

#!/bin/bash

SSHPASS="OMITTED"
FILE_TO_COPY=/opt/someConfigFile.conf
TARGET_FOLDER=/opt/

echo "Reading ip list..."
cat $1 | while read ip
do
    echo "Copying file to $ip"
    sshpass -p $SSHPASS scp -o StrictHostKeyChecking=no -o ServerAliveInterval=3 $FILE_TO_COPY root@$ip:$TARGET_FOLDER
    echo "Sending reboot command to $ip"
    sshpass -p $SSHPASS ssh -o StrictHostKeyChecking=no -o ServerAliveInterval=3 'nohup reboot > /dev/null & exit'
    echo "Done for $ip"
done
echo "Done for all"

Mon script lit les entrées d'un fichier texte dans lequel chaque entrée est séparée par une nouvelle ligne, quelque chose comme:

192.168.XXX.XX1
192.168.XXX.XX2
192.168.XXX.XX3
192.168.XXX.XX4

Lorsque je lance ce script, ./ConfigSender.sh /host_list.txtje peux voir la sortie suivante:

$> ./ConfigSender.sh /host_list.txt
Rading ip list...
Copying file to 192.168.XXX.XX1
Sending reboot command to 192.168.XXX.XX1
Done for 192.168.XXX.XX1
Done for all
$>

Je m'attendais à voir la sortie pour toutes les entrées du fichier. Je soupçonnais que les commandes à l'intérieur avaient en whilequelque sorte brisé l'exécution. J'ai donc édité mon script pour simplement imprimer la valeur lue en sortie:

#...
echo "Reading ip list..."
cat $1 | while read ip
do
    echo "Copying file to $ip"
done
echo "Done for all"

C'est la sortie:

$> ./ConfigSender.sh /host_list.txt
Rading ip list...
Copying file to 192.168.XXX.XX1
Copying file to 192.168.XXX.XX2
Copying file to 192.168.XXX.XX3
Copying file to 192.168.XXX.XX4
Done for all
$>

Question

Il est clair que les commandes à l'intérieur d'origine whilecausent ce comportement. Quel est le problème avec la boucle while? Qu'est-ce que j'oublie ici?

MODIFIER

Les réponses @harrymc & @Kamil Maciorowski résolvent mon problème, merci beaucoup. J'ai décidé d'accepter la réponse de @ harrymc car elle est plus descriptive.

Réponses:


3

sshpassfonctionne en manipulant stdinpour sshcroire qu’il obtient le mot de passe d’un utilisateur interactif. Lorsque vous utilisez une ... | whileboucle de style, la boucle itère pour chaque ligne en provenance de celle-ci stdin, qui sshpassdisparaît après le premier appel. C'est pourquoi seule la première ligne est exécutée.

Plusieurs solutions sont possibles:

  • Rediriger pour sshpass l'entrée standard vers /dev/null
  • Enroulez le corps entier de la boucle dans des accolades pour isoler stdin ( {})
  • Assigner à un tableau avant la boucle pour que vous n'utilisiez pas stdin
    readarray a < file
    for ip in "${a[@]}"; do
  • Boucle sur un descripteur de fichier autre que stdin
    while read -u 5 -r ip; do
    ...
    done 5<file

2

J'ai fait des tests. Je pense que vos lignes aiment

sshpass …

lire stdin, ils "mangent" des adresses IP supplémentaires fournies par cat. Vous pouvez enquêter sur la raison pour laquelle il arrive , mais il suffit de savoir qu'il ne se produise.

La solution consiste à leur donner une autre contribution:

</dev/null sshpass …

Ou vous pouvez reconstruire votre boucle comme ceci:

for ip in `cat $1`
do
 …
done

0

Pas sûr que cela résoudra le problème, mais vous n’avez pas fourni l’utilisateur et le nom d’hôte dans votre ligne de commande ssh reboot.

sshpass -p $SSHPASS ssh -o StrictHostKeyChecking=no -o ServerAliveInterval=3 root@$ip 'nohup reboot > /dev/null & exit'

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.