【发布时间】:2016-08-06 15:18:57
【问题描述】:
我使用此 bash 代码将文件上传到远程服务器,对于普通文件,这可以正常工作:
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
唯一的问题是对于名称中有空格的文件,for循环失败,所以我将第一行替换为这样:
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
由于某种奇怪的原因,ssh 命令跳出了 while 循环,因此第一个丢失的目录被创建得很好,但所有后续丢失的文件/目录都被忽略了。
我猜这与 ssh 向 stdout 写入一些内容有关,这会混淆“读取”命令。注释掉 ssh-command 会使循环正常工作。
有谁知道为什么会发生这种情况以及如何防止 ssh 打破 while 循环?
【问题讨论】:
-
顺便说一句——按照惯例,全大写的变量名是为环境变量和内置变量保留的;它们不应该用于脚本的本地变量。
-
while read当您的文件名包含文字反斜杠时会严重中断。使用read -r更安全。类似地,read将从名称中去除尾随空格;为避免这种情况,您需要清除IFS。 -
另外,
find | while read发出一个以换行符分隔的流,但 UNIX 上的合法文件名允许包含换行符。想想如果有人做了mkdir -p devel/$'\n'/etc然后写信给devel/$'\n'/etc/passwd会发生什么;此时您最好希望您的脚本无权写入远程计算机上的/etc/passwd。 -
另外,如果
$i包含空格或通配符表达式,或者为空,[ -d $i ]将出现异常。使用[[ -d $i ]](如果您的shell 是bash 或其他ksh 衍生工具)或[ -d "$i" ],带引号(为了与POSIX 兼容)。 -
我刚刚发现了这个问题,并且只是想注意,只有当
ssh成功与远程机器建立连接时才会出现错误情况。拒绝连接时不会发生这种情况。