有一个奇怪的 scp 问题:
$ scp user@server.org:~/test.txt ./
Password:
\033H \033H \033H \033H \033H \033H \033H \033H \033H \033H \033H \033H \033H \033H \033H \033H \033H \033H \033H \033H
Run Code Online (Sandbox Code Playgroud)
密码没问题,但得到那个奇怪的 \033H 东西。并且文件不会传输。谁有想法?
对此的修复通常很简单。通常您可以检查.bashrc,找到导致问题的顶部附近的一行或几行,然后移动或删除它们。困难的部分是说服人们这个问题实际上是真实的。详细信息如下,但如果您只是想解决这个问题,那么您只需要使用这个较短的第一部分。
当.bashrc远程计算机上的用户主目录中包含生成输出并且甚至在非交互式 shell 中运行的命令时,就会发生这种情况。不太常见的是,如果系统范围内/etc/bash.bashrc包含此类命令,也会发生这种情况。具体输出取决于产生它的东西。但是收到意外输出和没有任何传输成功甚至开始的组合非常强烈地指向了这个原因(特别是当服务器是 Debian 或 Ubuntu 系统时)。scp使用标准输入和输出来发送和接收数据,如果通过它们传输无关的数据,则无法传输文件。
如果您在想,“那是不可能的,.bashrc仅适用于交互式 shell!” 或以其他方式对发生这种情况的详细解释感兴趣,请参阅下面的第二部分。
此问题不会破坏正常的 SSH。因此,假设系统配置为允许您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
Run Code Online (Sandbox Code Playgroud)
另一种常见的方法,有些人在他们的 .bashrc文件中并且目前在/etc/bash.bashrc所有用户的系统范围文件中使用,是:
# If not running interactively, don't do anything
[ -z "$PS1" ] && return
Run Code Online (Sandbox Code Playgroud)
如果文件已被替换或修改为默认值,那么您可能会看到任一文件中使用的任一技术。还有其他可能的方法来检查交互式操作,但它们并不常见。如果用户.bashrc从头开始编写自己的文件,或者从不是 Debian、Ubuntu 或其他 Debian 衍生产品的其他操作系统带来它,那么他们很可能根本没有这样的代码。但是如果你需要它,你仍然可以添加它。
任何产生输出并出现在.bashrc或 中的命令/etc/bash.bashrc,除非它出现在如上所示的代码会导致在scp会话开始时发送意外数据,并会阻止scp传输文件。
如果您最近通过在顶部添加命令来自己编辑这些文件之一,那么您应该很容易找出导致问题的特定更改。即使没有,上面的描述也可能为您提供足够的信息。
但是,无论您是否能够根据上述说明解决问题,我都建议您使用完整的详细信息(包括这些文件的内容)来编辑您的问题。请记住,这些是远程服务器上的文件,而不是客户端计算机上的文件。这应该可以帮助发现您问题的其他人理解问题,并在需要时提供更具体的建议。
我相信您的问题由完全不同的原因引起的可能性非常低,但无论哪种方式,添加的信息都应该可以确定。除了这个问题的作者之外,其他有类似问题并需要帮助解决的人当然不应该编辑这个问题,而应该发布他们自己的问题。
人们常说这.bashrc仅适用于交互式 shell,但这是一种误解,或者充其量是一种严重的过度简化。 bash从运行命令~/.bashrc和/etc/bash.basrhc时:
/etc/profile或提供~/.profile 它,但也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 行开始)。
非交互式非登录bashshell 是您使用 运行脚本时获得的结果bash,可以在设置必要的权限后执行它并为其提供适当的 hashbang 行,或者通过显式运行。这也是您使用选项运行单行时所得到的,例如:bash your-scriptbash-c
bash -c 'echo hello world'
Run Code Online (Sandbox Code Playgroud)
正如你所期望的,当你你得到的壳登录通过SSH进行的交互式会话是一个交互式登录shell。这就是运行这样的命令时得到的结果(假设它成功):
ssh user@server.org
Run Code Online (Sandbox Code Playgroud)
但这就是非直观部分的用武之地:当您通过 SSH登录进行非交互式会话时获得的 shell是非交互式非登录shell。这就是通过 SSH 运行单个命令的结果:
ssh user@server.org command args...Run Code Online (Sandbox Code Playgroud)
也就是说,通过 SSH 运行单个命令bash与使用bash -c.
与ssh一般情况一样,scp导致 shell 作为远程用户在远程机器上运行。这仍然是他们配置为他们的 shell 的任何东西,即,在用户输入/etc/passwd或输出中列出的 shell getent passwd($SHELL当他们登录时,它也被设置为环境变量的值)。除非他们通过运行更改了它,否则chsh这是默认的用户 shell,在 Ubuntu 中是bash.
这就是为什么像命令这个运行非交互式非登录bash远程服务器上的壳,太:
scp user@server.org:~/test.txt ./
Run Code Online (Sandbox Code Playgroud)
除非它们由代码保护以在 shell 是非交互式的情况下停止,否则命令在这样的 shell中.bashrc或/etc/bash.bashrc由这样的 shell 运行。如果他们有意或无意地产生输出,scp则将无法复制文件。
| 归档时间: |
|
| 查看次数: |
804 次 |
| 最近记录: |