rsync error: protocol incompatibility / mismatch

1、问题

今日在维护集群环境的时候,遇到了一个小问题,rsync 向集群中的机器传输文件的时候报错:

protocol version mismatch -- is your shell clean?
(see the rsync man page for an explanation)
rsync error: protocol incompatibility (code 2) at compat.c(171) [sender=3.0.6]

即使打开调试选项 -vv,也没能得到更多的有用信息,不过看提示,应该是跟 shell 环境有关。

又翻了下 man rsync,发现官方对这个问题有如下的解释:

DIAGNOSTICS

rsync occasionally produces error messages that may seem a little cryptic. The one that seems to cause the most confusion is "protocol version mismatch -- is your shell clean?".

This message is usually caused by your startup scripts or remote shell facility producing unwanted garbage on the stream that rsync is using for its transport. The way to diagnose this problem is to run your remote shell like this:

ssh remotehost /bin/true > out.dat

then look at out.dat. If everything is working correctly then out.dat should be a zero length file. If you are getting the above error from rsync then you will probably find that out.dat contains some text or data. Look at the contents and try to work out what is producing it. The most common cause is incorrectly configured shell startup scripts (such as .cshrc or .profile) that contain output statements for non-interactive logins.

同时 google 这个问题你会发现答案也都是来源于官方的帮助文档,那么问题初步确定是 shell 环境的问题。

按照提示,ssh remotehost /bin/true > out.dat 执行过后输出的正是远程机器上 .bashrc 设置里的一条 echo 提示语句。

注释掉,然后再次测试,即可正常运行了。

2、原因

那么,这儿问题就来了(问题当然不是挖掘机哪家强 - _ - 。。。),rsync 和 .bashrc 有半毛钱关系呢?

哈哈,欲听后事如何,且听我慢慢道来~

原因是 rsync 在传输数据之前,会先与远端进行一次 ssh 登录认证,而当 .bashrc文件有输出的时候,rsync 客户端解析返回的数据包会出现混乱,于是乎就会出现文中开头提到的报错:客户端和远端的协议版本不兼容/不匹配了。

需要说明的是:

远端 sshd 进程是通过“bash –c”的方式来执行命令(即"非交互式的非登录shell")

但在执行命令之前,ssh的那一次登录本身是“非交互式的登录shell”,非交互式的登录shell (bash –l xxx.sh)载入的信息列表及顺序如下:

/etc/profile
[~/.bash_profile || ~/.bash_login || ~/.profile]
$BASH_ENV

对于Bash来说,登录shell(包括交互式登录shell和使用“–login”选项的非交互shell),它会首先读取和执行/etc/profile全局配置文件中的命令,然后依次查找~/.bash_profile、~/.bash_login 和 ~/.profile这三个配置文件,读取和执行这三个中的第一个存在且可读的文件中命令。除非被“–noprofile”选项禁止了。 在非登录shell里,只读取 ~/.bashrc (和 /etc/bash.bashrc、/etc/bashrc )文件,不同的发行版里面可能有所不同,如RHEL6.3中非登录shell仅执行了“~/.bashrc”文件(没有执行/etc/bashrc),而KUbuntu10.04中却依次执行了/etc/bash.bashrc 和 ~/.bashrc 文件。 对于这些规则,可以直接在相应的配置文件中加一些echo命令来验证其真实性。

所以 ssh 的时候会载入“~/.bash_profile”,

让我们再来看一下 .bash_profile 的内容:

cat ~/.bash_profile
# .bash_profile

# Get the aliases and functions
if [ -f ~/.bashrc ]; then
        . ~/.bashrc  # .bashrc 默认又会加载 /etc/bashrc
fi

# User specific environment and startup programs

PATH=$PATH:$HOME/bin

export PATH

看到这儿,我想你大概明白了为什么 .bashrc 里有输出流会导致 rsync 传输失败了。

3、解决方案

既然都找到原因了,那怎么解决呢?

有同学会问,我本来就是要让用户登录的时候有登录提示的呀?现在为了 rsync 岂不是得禁掉?

那这里就又引入了另一个知识点:交互式shell和飞交互式shell、登录shell和非登录shell 的区别

什么是交互式的呢?就像我们平时通过命令行做事一样,你敲一个命令,终端解析执行完之后给你一个结果,这样一种交互式的形式。那么,平时我们接触的Shell基本上都是交互式的,如gnome-terminal打开一个Shell以及通过Ctrl+alt+1等切换过去的文本终端。交互式Shell下, "echo $-"返回的字符串中包含i,否则不包含。也可以通过在bash后面加-i参数打开一个交互式的Shell,具体可以看man bash。bash后面加-c参数执行命令打开的是非交互式Shell,可以用以下命令验证:

bash -c 'echo $-'  # 返回hBc

解释完交互式之后,继续解析本小节后半部分中的登录二字。登录Shell其实很好理解,就是我们平时通过用户名/密码才能登录的Shell,最典型的就是用Ctrl+alt+1切换过去的文本终端。如何区分登录Shell和非登录Shell呢,可以通过查看$0的值,登录Shell返回-bash,而非登录Shell返回的是bash。平时gnome-terminal打开的Shell就是非登录Shell。也可以通过在bash后面加--login参数打开一个登录Shell。

回到本小节开头的问题,咱们可以用如下方式去区分一个命令是处于登录shell还是非登录shell:

[[ $- == *i* ]] && echo 'This is interactive shell.'

其中,$-中包含i意思是指当前的Shell是一个交互式(interactive)的Shell。

针对文中开头的问题,咱们加上如上的判断,就可以做到登录的时候有提示,同时 rsync 也不会报错了,可谓一举两得。

好了,今天的内容就到这儿了,其实 shell 作为一门古老的编程语言以及随着 linux 版本的多样化发展、不断的演变,”坑“很多,却也值得让人细细探索~

4、Refer:

[1] 什么是交互式登录 Shell [[ $- != *i* ]] && return

http://kodango.com/what-is-interactive-and-login-shell

[2] linux下的bash与sh 详解以及例子

http://bbs.chinaunix.net/thread-1068678-1-1.html

[3] 登录shell,交互式非登录shell,非交互式shell

http://bbs.chinaunix.net/thread-2018339-1-1.html

[4] Shell 默认选项 himBH 的解释

http://kodango.com/explain-shell-default-options

[5] 交互式SHELL和非交互式SHELL、登录SHELL和非登录SHELL的区别

http://smilejay.com/2012/10/interactive-shell-login-shell/

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏崔庆才的专栏

一言不合就改成 777 权限?会出人命的!

最近和几个朋友开发项目,期间使用了一台服务器跑模型,这台服务器是多人公用的,很多人都在上面有自己的账号,互不干涉内政,一切看起来十分井然有序。

72730
来自专栏Java进阶架构师

01: springboot快速入门之三分钟构建可运行项目

Spring Boot英文中是“引导”的意思,是用来简化Spring应用的搭建到开发的过程。可以这么说。SpringBoot是一个服务于框架的框架,服务范围是简...

9430
来自专栏雪胖纸的玩蛇日常

django2+uwsgi+nginx上线部署到服务器Ubuntu16.04(最新最详细版)

38960
来自专栏个人分享

通信协议

  由于没有存储共享器,分布式系统中的所有通信都是基于底层消息交换的。如果进程A要与进程B通信,A必须首先在自己的地址空间中生成该消息,再执行一个系统调用,通知...

11420
来自专栏Seebug漏洞平台

GNU tar 解压路径绕过漏洞(CVE-2016-6321) 分析

Author: LG (知道创宇404安全实验室) 漏洞简介 GNU tar文档管理命令是linux系统下常用的一个打包、压缩的命令。经CSS(FSC1V Cy...

42160
来自专栏云原生架构实践

JHipster生成微服务架构的应用栈(二)- 认证微服务示例

这里选择JHipster UAA server,这是一种基于OAuth认证机制的微服务。

34040
来自专栏pangguoming

使用Spring Cloud Security OAuth2搭建授权服务

前言:  本文意在抛砖引玉,帮大家将基本的环境搭起来,具体实战方案还要根据自己的业务需求进行制定。我们最终没有使用Spring Security OAuth2来...

98470
来自专栏Netkiller

PHP 安全与性能

PHP 安全与性能 摘要 我的系列文档 Netkiller Architect 手札Netkiller Developer 手札Netkiller PHP 手札...

53060
来自专栏技术专栏

SpringMVC添加异步请求支持

注意web.xml应用需在所有的servlet和filter配置加上<async-supported>true</async-supported>

1.2K10
来自专栏运维咖啡吧

LDAP落地实战(一):OpenLDAP部署及管理维护

上边来了一堆的名词解释,看的云里雾里,还不是很明白,怎么跟自己的组织架构对应起来呢?看看下边的图是不是清晰明了

56830

扫码关注云+社区

领取腾讯云代金券