ssh在bash中打破while循环

14 浏览
0 Comments

ssh在bash中打破while循环

这个问题已经有了答案

在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日
0
0 Comments

另一种方法是在非标准输入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的文件会发生什么。

0
0 Comments

问题在于ssh从标准输入读取,因此它吃掉了你的所有剩余行。你只需将其标准输入连接到无处:

ssh $USER@$SERVER "cd ${REMOTE_PATH}; mkdir -p $i" < /dev/null

你也可以使用ssh -n代替重定向。

0