有一个奇怪的 scp 问题:
$ scp [email protected]:~/test.txt ./
Password:
\033H \033H \033H \033H \033H \033H \033H \033H \033H \033H \033H \033H \033H \033H \033H \033H \033H \033H \033H \033H
密码输入正常,但出现奇怪的 \033H 字符。文件无法传输。有人知道吗?
答案1
修复这个问题的方法通常很简单。通常你可以检查.bashrc
,找到导致问题的行或几行,然后移动或删除它们。困难的部分是让人们相信这个问题是真实存在的。详细信息如下,但如果你只是想使固定这个问题,那么您只需要使用这个较短的第一部分。
问题及其解决方法
.bashrc
当远程计算机上的用户主目录中包含产生输出的命令时,就会发生这种情况甚至可以在非交互式 shell 中运行。不太常见的是,如果系统范围内包含此类命令,也会发生这种情况/etc/bash.bashrc
。具体输出取决于生成输出的内容。但收到意外输出和不是任何转会成功甚至开始非常强烈指向这个原因(特别是当服务器是 Debian 或 Ubuntu 系统时)。scp
使用标准输入和输出发送和接收数据,如果通过它们传输不相关的数据,那么它就无法传输文件。
如果你在想,“这不可能,.bashrc
这只适用于交互式 shell!”或者对为什么会出现这种情况的详细解释感兴趣,请参阅下面的第二部分。
此问题不会破坏正常的 SSHing。因此,假设系统配置为允许您ssh
成功进入交互式登录 shell,您可以这样做,.bashrc
在远程用户的主目录中打开,然后删除或注释掉(使用#
)有问题的命令(如果您不需要它们)。或者,如果您确实需要它们,则将它们移至 shell 非交互式时中止的另一个命令下方。这样的命令可能已经存在。在 Ubuntu 和其他一些发行版中,用户的.bashrc
文件和系统范围/etc/bash.bashrc
通常从此类检查开始。
.bashrc
Ubuntu 中的默认文件是从/etc/skel
创建用户帐户时复制而来的,其中包含此代码,用于检查正在运行的 shell 是否是交互式的,如果是,则阻止文件中的任何其他命令运行不是:
# If not running interactively, don't do anything
case $- in
*i*) ;;
*) return;;
esac
另一种常见方法是,有些人在他们的.bashrc
文件中使用这种方法,并且目前在所有用户的系统范围文件中都使用这种方法/etc/bash.bashrc
:
# If not running interactively, don't do anything
[ -z "$PS1" ] && return
如果文件已被替换或修改,则您可能会看到任一文件中都使用了任一技术。还有其他可能的方法来检查交互式操作,但它们并不常见。如果用户.bashrc
从头开始编写了自己的文件或将其从 Debian、Ubuntu 或其他 Debian 衍生产品以外的其他操作系统中带过来,那么他们很可能根本没有这样的代码。但如果您需要它,您仍然可以添加它。
任何产生输出并出现在.bashrc
或中的命令/etc/bash.bashrc
,除非它出现后像上面显示的代码将导致在会话开始时发送意外数据scp
,并会阻止scp
传输文件。
如果您最近自己编辑了其中一个文件,并在顶部添加了命令,那么您应该很容易找出导致问题的具体更改。即使不能,上面的描述也可能为您提供足够的信息。
但是,我建议你编辑问题时提供完整的详细信息,包括这些文件的内容,无论你是否能够根据上述解释解决问题。请记住这些是远程服务器上的文件,而不是客户端计算机上的文件。这应该可以帮助其他发现您的问题的人了解问题,并且如果需要的话,还可以提供更具体的建议。
我认为您的问题由完全不同的东西引起的可能性非常低,但无论如何,添加的信息应该可以使您确定。其他人比这个问题的作者有类似的问题,需要帮助来解决它们当然应该不是编辑这个问题,但应该发布他们自己的问题。
问题发生的原因
人们常说这只.bashrc
适用于交互式 shell,但这是一种误解,或者充其量是一种严重的过度简单化。 bash
运行命令的时间~/.bashrc
和/etc/bash.basrhc
时间如下:
- shell 是交互式的,或者
- 另一个启动脚本,例如
/etc/profile
或~/.profile
来源,但是也 - when
bash
既不是以交互方式运行,也不是作为登录 shell 运行,但确定它可能作为初始 shell 运行在远程连接中。
什么 bash
将其作为远程 shell 的充分证据(因此,在实践中,这种影响是否会发生在 SSH 上)主要取决于如何编译,不同操作系统有所不同,其次是版本bash
和版本sshd
正在使用。
在当前的 Debian 和 Ubuntu 系统上,当作bash
为非交互式非登录 shell 运行时,它会检查SSH_CLIENT
环境变量是否已设置且非空。(它还会检查其他内容,但对于当前 Ubuntu 系统上的 SSH,它们不会显示任何内容。)如果是,并且SHLVL
环境变量设置为小于 2 的值 - 表示它是会话的最初的shell--运行和bash
中的命令。/etc/bash.bashrc
~/.bashrc
为了在不修改配置文件的情况下快速验证这一点,读者可以将这些变量手动传递到bash -c ''
环境中并跟踪其读取的内容或检查run_startup_files
函数shell.c
(该版本从第 1022 行开始)。
非交互式非登录bash
shell 是你使用 运行脚本时得到的bash
,方法是在设置必要的权限后执行它并赋予它合适的哈希线或者通过显式运行。这也是使用选项运行一行程序时获得的结果,例如:bash your-script
bash
-c
bash -c 'echo hello world'
正如你所期望的,当你登录通过 SSH互动环节是一个交互式登录 shell。当您运行以下命令时(假设成功),您将获得以下结果:
ssh [email protected]
但这里就出现了非直观的部分:当你登录通过 SSH非交互式会话是非交互式的未登录shell。这就是通过 SSH 运行单个命令所获得的结果:
ssh [email protected] command args...
也就是说,通过 SSH 运行单个命令bash
就像您使用 在本地(或在已建立的远程会话中)运行单个命令一样,是一种非交互式、非登录的 shell——非交互式 shell bash -c
。
ssh
与一般情况一样,scp
会导致以远程用户身份在远程计算机上运行 shell。这仍然是他们配置为 shell 的内容,即用户在 中的输入/etc/passwd
或 的输出中列出的 shell(在用户登录时getent passwd
也会将其设置为环境变量的值)。除非他们通过运行 对其进行了更改,否则这是默认的用户 shell,在 Ubuntu 中为。$SHELL
chsh
bash
这就是为什么像这样的命令这bash
在远程服务器上也运行非交互式非登录shell:
scp [email protected]:~/test.txt ./
除非它们被代码保护,以在 shell 为非交互式时停止,否则此类 shell 中的命令.bashrc
或命令/etc/bash.bashrc
将由此类 shell 运行。如果它们产生输出(有意或无意),那么scp
将无法复制文件。