是否有一個簡單的命令可以 SCP 遠端主機上目錄中最近修改的檔案?我可以弄清楚如何從本地到遠端做到這一點...類似:
scp ``ls -Art | tail -n 1\`` usr@remote:/var/log/yeet
我怎麼做同樣的事情,但從遠端到本地。 (所以從yeet取得最近修改的檔案並將其複製到本地主機)
答案1
這裡有幾個問題。
解析ls
首先你不應該解析ls
。你的ls -Art | tail -n 1
有缺陷,無法可靠地修復。標準的可靠替代方案是find
和/或使用空終止線。
另外,我假設您需要直接在當前目錄(而不是子目錄)中最近修改的檔案(不是目錄)。
POSIX 通常不需要以空終止列表的形式解析輸入項的能力。如果您的工具選項足夠豐富,那麼這是您的強大替代品ls -Art | tail -n 1
:
find . -maxdepth 1 -type f -printf '%T@ %p\0' |
sort -zrn |
head -zn 1 |
cut -z -d " " -f 2-
它產生的結果是一個以 null 結尾的檔名。要使用它執行某些操作,您需要將其通過管道傳輸到xargs -0 …
,例如:
… | xargs -0r cp -t "/target/dir/" --
或(如果您cp
不支持-t
):
… | xargs -0r -I {} cp -- {} "/target/dir/"
在這些命令中,有許多 POSIX 不需要的東西(因此不可移植),包括--
停止cp
解析選項,因此例如檔案-R
不會觸發遞歸而不是被複製。請注意,檔案名稱肯定會find . …
以開頭開頭,因此可以安全地省略。我用它只是為了指出處理.另一個好的做法是引用路徑:文字可以在沒有引號的情況下工作,但是在用特定的目標路徑替換此範例後,您可能需要引號,所以無論如何我都會使用它們。.
--
cp
/target/dir/
在您的(本地到遠端)情況下,您將使用scp
而不是cp
.它在解析參數時可能有自己的怪癖。
符合 POSIX 標準但效能不佳的命令可能是:
find . ! -name . -prune -type f -exec sh -c '
[ "$(find . ! -name . -prune -type f -newer "$1" -exec printf a \; |
wc -c)" -eq 0 ]' sh {} \; -print
它採用了一種方法這是另一個答案替換(非 POSIX)-maxdepth 1
。它sh
可靠地生成嵌套兩個find … -exec …
子句。外部find
探測所有文件並將它們一一提供給內部find
。內部尋找比給定文件更新的所有文件,為每個較新的文件find
列印一個字元 ( )。計算這些字元。如果沒有,則表示給定的文件是最近修改的;然後才在外面列印它。a
wc -c
find
在極少數情況下,外部find
可能會列印多個文件:
- 有兩個或多個檔案具有相同的“最新”mtime;
- 命令運行時目錄中的檔案被修改;
- 內部
find
無法統計某些文件。
因此-quit
,外部的最終動作find
將是有用的(請注意,它對於內部也很有用find
,但出於不同的原因)。不幸的-quit
是不是 POSIX。
我使用-print
(-print0
不是 POSIX),但非標準文件名仍然不是問題,因為您不需要將輸出通過管道傳輸到另一個命令。只需使用-exec
它來處理所有可能的檔案名稱即可;例如,而不是-print
你使用:
-exec yet_another_command {} \;
現在您知道如何在本機目錄中尋找最近修改的檔案而不解析ls
.
在遠端系統上尋找文件
無論您選擇什麼方法(包括有缺陷的ls … | tail …
),您都需要在遠端系統上運行該命令(或不運行,我稍後會討論這個異常),以便在遠端目錄中找到所需的檔案。
最明顯的方法是ssh
進入遠端系統。在新的上下文中,遠端系統是本地的,而本地電腦是遠端的。 (這裡我使用上面的 POSIX 相容命令作為範例,但find … | sort -z … | head -z … | cut -z … | xargs -0 …
如果只有遠端系統支援所有必需的選項,您可以使用我們的第一個命令)。
ssh usr@remote
# now on the remote system
cd "/source/dir/" &&
find . ! -name . -prune -type f -exec sh -c '
[ "$(find . ! -name . -prune -type f -newer "$1" -exec printf a \; |
wc -c)" -eq 0 ]' sh {} \; -exec scp {} usr@local:"/target/dir/" \;
請注意,如果您想避免cd
並使用find /source/dir …
,那麼還有更多.
-s 需要替換為/source/dir
。使用 就容易多了cd
。
您需要可以透過 SSH 從遠端系統存取本機系統。如果途中有 NAT,您可以透過遠端連接埠轉送繞過它,如下所示:
ssh -R 12322:127.0.0.1:22 usr@remote
# now on the remote system the same cd + find as above
# only the scp part is different
… -exec scp -P 12322 {} [email protected]:"/target/dir/" \;
請注意,它使遠端端口12322
指向您的本地端口sshd
,遠端系統的任何用戶都可能會嘗試濫用它。另一個問題:遠端系統可能被配置為不允許您先轉送連接埠。
您可能需要在本機系統上呼叫單一命令。在這種情況下,需要正確的引用,這會變得更加麻煩:
ssh usr@remote '
cd "/source/dir/" &&
find . ! -name . -prune -type f -exec sh -c '"'"'
[ "$(find . ! -name . -prune -type f -newer "$1" -exec printf a \; |
wc -c)" -eq 0 ]'"'"' sh {} \; -exec scp {} usr@local:"/target/dir/" \;
'
不過,如果遙控器scp
需要詢問您的密碼,我預計會出現麻煩。由於這個原因,或者如果您無法運行/到達本地sshd
,您可能需要另一種方法。
此本機命令將列印從遠端系統取得的所需檔案名稱:
ssh usr@remote '
cd "/source/dir/" &&
find . ! -name . -prune -type f -exec sh -c '"'"'
[ "$(find . ! -name . -prune -type f -newer "$1" -exec printf a \; |
wc -c)" -eq 0 ]'"'"' sh {} \; -print
'
你可以使用它當地的xargs
和等工具scp
。請注意,解析-print
yield 的結果僅比解析 稍好ls
。使用-print0
(非 POSIX,可能無法使用) 或-exec printf "%s\0" {} \;
(應該可以) 來-print
取得所需的檔案名稱作為空終止字串。現在由您決定在本地如何處理它。如果您需要具有 POSIX 相容的遠端命令,但本機系統中的工具有豐富的選項,這非常有用。
值得注意的例外:sshfs
sshfs
允許您安裝usr@remote:"/source/dir/"
為/local/path/
.看我的這個答案,我不會重複自己來涵蓋所有細節。在您的情況下,具有豐富(不限於 POSIX)工具的(本地)流程如下:
sshfs usr@remote:"/source/dir/" "/local/path/"
find "/local/path/" -maxdepth 1 -type f -printf '%T@ %p\0' |
sort -zrn |
head -zn 1 |
cut -z -d " " -f 2- |
xargs -0r cp -t "/target/dir/" --
fusermount -u "/local/path/"
這很棒。你所做的一切當地的工具。如果您可以使用sshfs
遠端的工具,那麼它們的可用選項就不再重要了。如果您可以從外部存取本機系統也沒關係。而且方法都是一樣的:遠端到本地或本地到遠端,都沒有關係。