有一個奇怪的 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
,方法是在設定必要的權限並授予它後執行它合適的 hashbang 線或透過顯式運行。這也是當您使用選項運行單行程式碼時所得到的結果,例如:bash your-script
bash
-c
bash -c 'echo hello world'
正如你所期望的,當你登入透過 SSH互動環節是一個互動式登入 shell。這就是當您執行這樣的命令時得到的結果(假設成功):
ssh [email protected]
但這就是不直觀的部分出現的地方:當你登入透過 SSH 進行非互動式會話是非互動式的未登入殼。這就是透過 SSH 運行單一命令所得到的結果:
ssh [email protected] command args...
也就是說,透過 SSH 執行單一命令的運作bash
方式與您在本機(或在已建立的遠端會話中)執行單一命令時的 shell 類型相同(非互動式、非登入 shell)bash -c
。
與通常情況一樣ssh
,scp
導致 shell 以遠端使用者身分在遠端電腦上執行。這仍然是他們配置為 shell 的任何內容,即使用者輸入/etc/passwd
或輸出中列出的 shell(當他們登入時,getent passwd
它也被設定為環境變數的值)。$SHELL
除非他們透過運行更改了它chsh
,否則這是預設的使用者 shell,在 Ubuntu 中是bash
。
這就是為什麼像這樣的命令這bash
也在遠端伺服器上執行非互動式非登入shell:
scp [email protected]:~/test.txt ./
除非它們受程式碼保護以在 shell 是非互動式的情況下停止,否則此類 shell 中的命令.bashrc
或/etc/bash.bashrc
由此類 shell 運行。如果它們產生輸出——有意或無意——那麼scp
將無法複製文件。