ssh 跳出 bash 中的 while 循环

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9393038/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 21:40:45  来源:igfitidea点击:

ssh breaks out of while-loop in bash

bashssh

提问by Robby75

I use this bash-code to upload files to a remote server, for normal files this works fine:

我使用这个 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

The only problem is that for files with a space in the name, the for-loop fails, so I replaced the first line like this:

唯一的问题是,对于名称中带有空格的文件,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

For some strange reason, the ssh-command breaks out of the while-loop, therefore the first missing directory is created fine, but all subsequent missing files/directories are ignored.

出于某种奇怪的原因,ssh 命令跳出 while 循环,因此第一个丢失的目录创建得很好,但所有后续丢失的文件/目录都被忽略。

I guess this has something to do with ssh writing something to stdout which confuses the "read" command. Commenting out the ssh-command makes the loop work as it should.

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

Does anybody know why this happens and how one can prevent ssh from breaking the while-loop?

有谁知道为什么会发生这种情况以及如何防止 ssh 破坏 while 循环?

回答by choroba

The problem is that sshreads from standard input, therefore it eats all your remaining lines. You can just connect its standard input to nowhere:

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

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

You can also use ssh -ninstead of the redirection.

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

回答by Charles Duffy

Another approach is to loop over a FD other than 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)

The -u 3and 3<operators are critical here, using FD 3 rather than the default FD 0 (stdin).

-u 33<这里运算符是关键的,使用FD 3而不是默认的FD 0(标准输入)。

The approach given here -- using -print0, a cleared IFSvalue, and the like -- is also less buggy than the original code and the existing answer, which can't handle interesting filenames correctly. (Glenn Hymanman's answer is close, but even that can't deal with filenames with newlines or filenames with trailing whitespace).

这里给出的方法——使用-print0、清除IFS值等——也比原始代码和现有答案的错误更少,后者无法正确处理有趣的文件名。(格伦Hyman曼的回答很接近,但即使这样也无法处理带有换行符的文件名或带有尾随空格的文件名)。

The use of printf %qis critical to generate commands which can't be used to attack the remote machine. Consider what would happen with a file named devel/$(rm -rf /)/hellowith code which didn't have this paranoia.

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