bash - run - ssh execute command on remote server
ssh se rompe de while-loop en bash (3)
Además de la respuesta de choroba , no use un bucle for
para leer nombres de archivos:
find devel/ -newer $UPLOAD_FILE |
while read -r i
do ...
Esta pregunta ya tiene una respuesta aquí:
Utilizo este código bash para cargar archivos en un servidor remoto, para archivos normales esto funciona 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
El único problema es que para los archivos con un espacio en el nombre, el for-loop falla, así que reemplacé la primera línea así:
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
Por alguna extraña razón, el comando ssh se rompe del ciclo while, por lo tanto, el primer directorio que falta se crea correctamente, pero se ignoran todos los archivos / directorios que faltan.
Supongo que esto tiene algo que ver con que ssh escriba algo a stdout que confunde el comando "leer". Comentando el comando ssh hace que el bucle funcione como debería.
¿Alguien sabe por qué sucede esto y cómo uno puede evitar que ssh rompa el ciclo while?
El problema es que ssh
lee desde la entrada estándar, por lo tanto, come todas las líneas restantes. Simplemente puede conectar su entrada estándar a ninguna parte:
ssh $USER@$SERVER "cd ${REMOTE_PATH}; mkdir -p $i" < /dev/null
También puede usar ssh -n
lugar de la redirección.
Otro enfoque es pasar por encima de un FD distinto de 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)
Los operadores -u 3
y 3<
son críticos aquí, usando FD 3 en lugar del FD 0 predeterminado (stdin).
El enfoque que se da aquí -utilizando -print0
, un valor IFS
despejado, y similares- también es menos problemático que el código original y la respuesta existente, que no puede manejar nombres de archivo interesantes correctamente. (La respuesta de Glenn Jackman está cerca, pero incluso eso no puede tratarse con nombres de archivos con líneas nuevas o nombres de archivos con espacios en blanco al final).
El uso de printf %q
es crítico para generar comandos que no pueden usarse para atacar la máquina remota. Considere lo que sucedería con un archivo llamado devel/$(rm -rf /)/hello
con código que no tenía esta paranoia.