ssh在bash中打破while循环
ssh在bash中打破while循环
这个问题已经有了答案:
我使用这个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中写入了一些内容,导致\"read\"命令出现了混淆。注释掉ssh命令使循环正常工作。
有人知道这是为什么以及如何防止ssh退出while循环吗?
admin 更改状态以发布 2023年5月20日
另一种方法是在非标准输入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)
在这里使用的是- u 3和3 <运算符,使用FD 3而不是默认的FD 0(stdin)是关键。使用-print0,已清除的IFS值等提供的方法比原始代码和现有答案更少出错,并且可以正确处理有趣的文件名。(Glenn Jackman的答案已经接近了,但是它甚至不能处理带有换行符或带有尾随空格的文件名)。使用printf %q是生成无法用于攻击远程机器的命令是很关键的。如果没有这种偏执狂,考虑一个名为devel/ $(rm - rf /)/ hello的文件会发生什么。