Вопрос или проблема
У меня уже некоторое время наблюдается очень странное поведение SCP: всякий раз, когда я пытаюсь скопировать файл, вывод SCP содержит кучу подчеркиваний, и файл не копируется.
$ scp test.txt 192.168.0.2:~
[email protected]'s password:
________________________________________
Когда я устанавливаю SSH-соединение, используя Midnight Commander, и копирую файлы, всё работает.
Некоторая информация о моей машине:
$ ssh -V
OpenSSH_5.8p1 Debian-1ubuntu3, OpenSSL 0.9.8o 01 Jun 2010
$ uname -a
Linux squatpc 2.6.38-10-generic #46-Ubuntu SMP Tue Jun 28 15:05:41 UTC 2011 i686 i686 i386 GNU/Linux
Я использую Kubuntu 11.04.
Редактирование: Дополнительная информация по просьбе комментариев:
$ scp -v test.txt 192.168.0.2:~
Executing: program /usr/bin/ssh host 192.168.0.2, user (unspecified), command scp -v -t -- ~
OpenSSH_5.8p1 Debian-1ubuntu3, OpenSSL 0.9.8o 01 Jun 2010
debug1: Reading configuration data /etc/ssh/ssh_config
debug1: Applying options for *
debug1: Connecting to 192.168.0.2 [192.168.0.2] port 22.
debug1: Connection established.
debug1: identity file /home/job/.ssh/id_rsa type 1
debug1: Checking blacklist file /usr/share/ssh/blacklist.RSA-2048
debug1: Checking blacklist file /etc/ssh/blacklist.RSA-2048
debug1: identity file /home/job/.ssh/id_rsa-cert type -1
debug1: identity file /home/job/.ssh/id_dsa type -1
debug1: identity file /home/job/.ssh/id_dsa-cert type -1
debug1: identity file /home/job/.ssh/id_ecdsa type -1
debug1: identity file /home/job/.ssh/id_ecdsa-cert type -1
debug1: Remote protocol version 2.0, remote software version OpenSSH_5.8p1 Debian-1ubuntu3
debug1: match: OpenSSH_5.8p1 Debian-1ubuntu3 pat OpenSSH*
debug1: Enabling compatibility mode for protocol 2.0
debug1: Local version string SSH-2.0-OpenSSH_5.8p1 Debian-1ubuntu3
debug1: SSH2_MSG_KEXINIT sent
debug1: SSH2_MSG_KEXINIT received
debug1: kex: server->client aes128-ctr hmac-md5 none
debug1: kex: client->server aes128-ctr hmac-md5 none
debug1: sending SSH2_MSG_KEX_ECDH_INIT
debug1: expecting SSH2_MSG_KEX_ECDH_REPLY
debug1: Server host key: ECDSA 28:f3:2b:31:36:43:9b:07:d8:33:ca:43:4f:ca:6c:4c
debug1: Host '192.168.0.2' is known and matches the ECDSA host key.
debug1: Found key in /home/job/.ssh/known_hosts:20
debug1: ssh_ecdsa_verify: signature correct
debug1: SSH2_MSG_NEWKEYS sent
debug1: expecting SSH2_MSG_NEWKEYS
debug1: SSH2_MSG_NEWKEYS received
debug1: Roaming not allowed by server
debug1: SSH2_MSG_SERVICE_REQUEST sent
debug1: SSH2_MSG_SERVICE_ACCEPT received
debug1: Authentications that can continue: publickey,password
debug1: Next authentication method: publickey
debug1: Offering RSA public key: /home/job/.ssh/id_rsa
debug1: Authentications that can continue: publickey,password
debug1: Trying private key: /home/job/.ssh/id_dsa
debug1: Trying private key: /home/job/.ssh/id_ecdsa
debug1: Next authentication method: password
[email protected]'s password:
debug1: Authentication succeeded (password).
Authenticated to 192.168.0.2 ([192.168.0.2]:22).
debug1: channel 0: new [client-session]
debug1: Requesting [email protected]
debug1: Entering interactive session.
debug1: Sending environment.
debug1: Sending env LANG = en_US.UTF-8
debug1: Sending command: scp -v -t -- ~
________________________________________
debug1: client_input_channel_req: channel 0 rtype exit-status reply 0
debug1: channel 0: free: client-session, nchannels 1
debug1: fd 0 clearing O_NONBLOCK
debug1: fd 1 clearing O_NONBLOCK
Transferred: sent 2120, received 1872 bytes, in 0.3 seconds
Bytes per second: sent 7783.1, received 6872.6
debug1: Exit status 0
и
$ type scp
scp is hashed (/usr/bin/scp)
Ха-ха, только что выяснил, в чем проблема.
Поскольку мне так нравятся коровы, я добавил fortune | cowsay
в начало моего файла .bashrc
, который при запуске bash
выдает следующий вывод:
_______________________________________
< Вы потеряете важный файл. >
---------------------------------------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
Все это прекрасно (и иногда смешно), когда bash
запускается в интерактивном режиме. Однако bash читает ~/.bashrc
, когда он работает в интерактивном режиме и не является логин-шеллом, или когда он является логин-шеллом и его процесс-родитель – это rshd
или sshd
. Когда вы запускаете scp
, сервер запускает оболочку, которая запускает удалённый экземпляр scp
. Вывод из .bashrc
запутывает scp
, так как он посылается так же, как и данные протокола scp
. Очевидно, это известная ошибка, подробнее читается здесь.
Кроме того, отметьте, что подчеркивания, которые я упомянул в вопросе, это те, что в верхней строке текстового облака.
Итак, решение было простым: я добавил следующее в начало .bashrc
на удалённой (целевой) машине:
# Если не интерактивный режим, ничего не делать
[[ $- == *i* ]] || return
Эта строка присутствует в .bashrc
по умолчанию, но оказалась намного ниже из-за моих многочисленных (очевидно, неаккуратных) правок.
Насколько мне известно, правильный способ сделать так, чтобы scp
работал без помех, больше связан не с условием для вывода на экран в вашем сценарии ~/.bashrc
, а просто с ограничением вывода на экран в сценарии ~/.bash_profile
. По крайней мере, так это работает в моей системе (CentOS).
Редактирование для ясности:
- Добавляйте в файл ~/.bashrc только те строки, которые требуются для “всех” удалённых подключений (например, установка определённых переменных окружения допустима, но вывод человекочитаемого текста – нет).
- Может различаться в зависимости от вашей системы
Это поведение может произойти, когда ваш файл .bashrc
выводит какой-либо текст или у вас есть MOTD (Сообщение дня)
. Вы можете использовать опцию -o
с scp
:
С помощью -o
вы можете передавать опции SSH, в данном случае вы можете задать опцию, такую как RequestTTY=no
, и она никогда не будет запрашивать вывод терминала.
scp -o RequestTTY=no source target
@Job прав. Тем не менее, эта проблема может стать большой, если графика приветственного экрана является частью /etc/bash.bashrc
.
Вы должны убедиться, что удалили такой графический контент с обоих:
- /etc/bash.bashrc
- ~/.bashrc
На системах debian и ubuntu в неинтерактивной оболочке сначала вызывается /etc/bash.bashrc, затем ~/.bashrc.
Я не уверен насчет этой ошибки с scp, давно его использовал. Я заменил scp на rsync, и это намного лучше. Rsync должен быть практически на каждом устройстве с Linux.
Я писал о rsync здесь, в теме о scp:
Как оптимально скопировать большое количество небольших файлов через scp?
Rsync описан там в записи от JohnU.
Я столкнулся с той же проблемой и нашел это обсуждение при поиске с сообщением об ошибке, используя Ubuntu 24.04 на исходной машине и Ubuntu 24.10 на целевой. Я добавил строку EXPORT в начало файла .bashrc, поэтому сделал то же самое, что и mtvec: переместил строки
# Если не интерактивный режим, ничего не делать
[ -z "$PS1" ] && return
затем сделал source файла .bashrc, повторил попытку, и это сработало!
.
Ответ или решение
Когда SCP завершается без видимой ошибки и не осуществляет копирование файлов, это может быть весьма озадачивающим, особенно если средство не указывает явной причины. Распечатка множества символов подчёркивания, как указано в примере, может служить ключом к пониманию проблемы. Даная ситуация может возникнуть, если в конфигурационные файлы оболочки, такие как .bashrc
или bash.bashrc
, включены команды, производящие вывод на экран. Давайте детально разберёмся в этом вопросе и выясним, как его можно решить.
Теория
ssh и scp взаимодействуют через текстовые потоки, ожидая обмен сообщениями между клиентом и сервером в определённом формате, заранее не предполагающем нестандартный вывод. Если какой-либо вывод появляется прежде, чем форматы данных SCP, это может вызвать сбой. Важной частью этой проблемы является форма команд, например, fortune | cowsay
, которые дают текстовый вывод при запуске оболочки.
SCP запускает удалённую оболочку для выполнения команд, и если в этих оболочках присутствует нестандартный вывод (кроме ожидаемых форматов), это нарушает работу SCP. Также поведение может быть вызвано изменениями как в локальных, так и в глобальных конфигурационных файлах Bash, как в .bashrc
в домашнем каталоге пользователя, так и в системных файлах, таких как /etc/bash.bashrc
.
Пример
Многие пользователи могут не осознавать, что вывод, порождаемый их .bashrc
, может негативно влиять на работу SCP. Рассмотрим пример: пользователь добавляет строку fortune | cowsay
в начало своего .bashrc
. Эта команда выполняется всякий раз, когда открывается сессия и порождает текстовый вывод в виде ASCII-арт. В интерактивных сессиях такая надстройка может быть безвредной и даже развлекательной, но в случае SCP такой вывод не допускается.
Применение
Для предотвращения подобных проблем необходимо изменить .bashrc
с учетом совместимости неинтерактивных сессий.
-
Проверьте содержимое вашего
.bashrc
на наличие команд, которые могут давать непосредственный вывод. Такие команды, какecho
, не должны запускаться по умолчанию. -
В начало файла
.bashrc
добавьте оболочный условный оператор, который прекратит выполнение при неинтерактивной сессии:# Если не в интерактивной сессии, не делать ничего [[ $- != *i* ]] && return
-
При наличии аналогичных проблем в глобальном
/etc/bash.bashrc
убедитесь, что в нём так же установлены условия для избежания вывода в неинтерактивных сессиях. -
Для достижения наибольшей безопасности можно использовать специальные опции SCP, такие как
-o RequestTTY=no
, что предотвращает запрос терминала, минимизируя риск нежелательного вывода работы, например:scp -o RequestTTY=no <source> <destination>
-
Рассмотрите возможность использования более надежных инструментов, таких как
rsync
, которые лучше адаптированы к копированию данных и могут игнорировать посторонний вывод.
Следуя этим шагам, вы должны обеспечить корректную и надёжную работу SCP, избегая проблем, связанных с нежелательным выводом. Важно помнить, что ключ к успешному решению подобных проблем заключается в детальной проверке файлов конфигурации оболочки и устранении всех неподходящих для удалённых сценариев элементов.