ssh在bash中突然出现while循环

时间:2012-02-22 10:28:17

标签: bash ssh

我使用这个bash-code将文件上传到远程服务器,对于普通文件,这可以正常工作:

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-command突然出现了while循环,因此第一个缺失的目录被创建得很好,但是所有后续丢失的文件/目录都被忽略了。

我想这与ssh写一些东西到stdout有关,这会混淆“read”命令。注释掉ssh-command会使循环工作正常。

有人知道为什么会发生这种情况以及如何阻止ssh打破while循环吗?

2 个答案:

答案 0 :(得分:180)

问题是ssh从标准输入中读取,因此它会占用剩余的所有行。您可以将其标准输入连接到任何地方:

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

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

答案 1 :(得分:9)

另一种方法是循环除了stdin以外的FD:

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 33<运算符在这里至关重要,使用FD 3而不是默认FD 0(stdin)。

此处给出的方法 - 使用-print0,已清除的IFS值等 - 与原始代码和现有答案相比也更少,这些代码无法处理有趣的文件名正确。 (格伦杰克曼的答案很接近,但即便如此也无法处理带有新行或带有尾随空格的文件名的文件名。)

使用printf %q对于生成无法用于攻击远程计算机的命令至关重要。考虑一个名为devel/$(rm -rf /)/hello的文件会发生什么,代码没有这种偏执。