J'utilise ce code bash pour télécharger des fichiers sur un serveur distant, pour les fichiers normaux, cela fonctionne bien:
for i in `find devel/ -newer $UPLOAD_FILE`
do
echo "Upload:" $i
if [ -d $i ]
then
echo "Creating directory" $i
ssh $USER@$SERVER "cd ${REMOTE_PATH}; mkdir -p $i"
continue
fi
if scp -Cp $i $USER@$SERVER:$REMOTE_PATH/$i
then
echo "$i OK"
else
echo "$i NOK"
rm ${UPLOAD_FILE}_tmp
fi
done
Le seul problème est que pour les fichiers avec un espace dans le nom, la boucle for échoue, j'ai donc remplacé la première ligne comme ceci:
find devel/ -newer $UPLOAD_FILE | while read i
do
echo "Upload:" $i
if [ -d $i ]
then
echo "Creating directory" $i
ssh $USER@$SERVER "cd ${REMOTE_PATH}; mkdir -p $i"
continue
fi
if scp -Cp $i $USER@$SERVER:$REMOTE_PATH/$i
then
echo "$i OK"
else
echo "$i NOK"
rm ${UPLOAD_FILE}_tmp
fi
done
Pour une raison étrange, la commande ssh sort de la boucle while, donc le premier répertoire manquant est bien créé, mais tous les fichiers/répertoires manquants suivants sont ignorés.
Je suppose que cela a quelque chose à voir avec l'écriture de ssh quelque chose sur stdout qui confond la commande "read". La mise en commentaire de la commande ssh fait fonctionner la boucle comme il se doit.
Est-ce que quelqu'un sait pourquoi cela se produit et comment peut-on empêcher ssh de rompre la boucle while?
Le problème est que ssh
lit à partir de l'entrée standard, donc il mange toutes vos lignes restantes. Vous pouvez simplement connecter son entrée standard à nulle part:
ssh $USER@$SERVER "cd ${REMOTE_PATH}; mkdir -p $i" < /dev/null
Vous pouvez aussi utiliser ssh -n
au lieu de la redirection.
Une autre approche consiste à boucler sur un FD autre que stdin:
while IFS= read -u 3 -r -d '' filename; do
if [[ -d $filename ]]; then
printf -v cmd_str 'cd %q; mkdir -p %q' "$REMOTE_PATH" "$filename"
ssh "$USER@$SERVER" "$cmd_str"
else
printf -v remote_path_str '%q@%q:%q/%q' "$USER" "$SERVER" "$REMOTE_PATH" "$filename"
scp -Cp "$filename" "$remote_path_str"
fi
done 3< <(find devel/ -newer "$UPLOAD_FILE" -print0)
Les opérateurs -u 3
Et 3<
Sont critiques ici, en utilisant FD 3 plutôt que FD 0 par défaut (stdin).
L'approche donnée ici - en utilisant -print0
, Une valeur IFS
effacée, etc. - est également moins boguée que le code original et la réponse existante, qui ne peut pas gérer correctement les noms de fichiers intéressants . (La réponse de Glenn Jackman est proche, mais même cela ne peut pas traiter les noms de fichiers avec des nouvelles lignes ou les noms de fichiers avec des espaces en fin).
L'utilisation de printf %q
Est essentielle pour générer des commandes qui ne peuvent pas être utilisées pour attaquer la machine distante. Considérez ce qui se passerait avec un fichier nommé devel/$(rm -rf /)/hello
avec du code qui ne présentait pas cette paranoïa.