SSH删除远程文件致Bash脚本while循环意外终止?求原因分析
问题原因与解决方案
这个问题我太熟悉了——根源在于ssh命令会默认占用标准输入,刚好你的while read循环是从标准输入读取find命令的输出,两者直接冲突了!
具体原因
当你第一次循环执行ssh root@$RMT_IP "rm $file"时,ssh会自动从当前的标准输入(也就是find命令输出的文件列表)读取数据,这就把剩下的所有文件路径都“吃掉”了。read命令再也读不到下一个文件路径,循环自然就提前终止,只执行了一次。
快速解决方法
给ssh命令加上-n参数,这个参数会强制ssh不从标准输入读取数据(相当于把标准输入重定向到/dev/null),这样就不会干扰while read的输入流了。修改后的代码行如下:
ssh -n root@$RMT_IP "rm $file"
更安全的进阶优化
另外要注意,如果远程文件的路径包含空格、引号或者其他特殊字符,直接在ssh命令里使用$file可能会导致命令执行出错。推荐用printf %q来对文件路径进行转义,确保命令安全执行:
ssh -n root@$RMT_IP "$(printf 'rm %q' "$file")"
修改后的完整脚本示例
#!/bin/bash S_ACCOUNTS=('yohplala') RMT_IP='88.214.320.588' LOC_PATH_DATA='../data/cs_remote/' MOD_TIME='+10' # Last modification time, in minutes # List, copy, delete files. for serv_account in "${S_ACCOUNTS[@]}"; do while IFS= read -r -d $'\0' file; do scp -i ~/.ssh/id_rsa root@$RMT_IP:"$file" "$LOC_PATH_DATA""$serv_account" if test -f "$LOC_PATH_DATA""$serv_account"/'/'"$(basename "$file")"; then echo "$(basename "$file")"' successfully copied.' # 加上-n参数避免占用标准输入,同时用printf转义文件路径 ssh -n root@$RMT_IP "$(printf 'rm %q' "$file")" fi done < <(ssh root@$RMT_IP "find "/root/test" -maxdepth 1 -type f -mmin $MOD_TIME -print0") done
内容的提问来源于stack exchange,提问作者pierre_j
相关产品推荐
相关产品推荐

