排除 SCP-filepattern 的字元
有沒有辦法建構一個表達式
scp
,我可以用它來複製文件file-name-version-1.2.1.jar
無需複製文件
file-name-version-1.2.1-sources.jar file-name-version-1.2.1-javadoc.jar
雖然不知道確切的版本號?
file-name-version-*.*.*.jar
由於明顯的原因將無法工作。我正在尋找類似的語法file-name-version-\d.\d.\d.jar
或類似的東西。
要記住的一件事是文件名未經修改地傳遞給遠端使用者的登錄外殼。
如果你這樣做:
scp user@remote-machine:'something' ...
在遠端機器上,
sshd
將執行以下登錄 shelluser
:that-shell -c 'scp -f something'
正是那個外殼將在那裡擴展模式。
這意味著擴展模式的方式將取決於遠端使用者使用的登錄 shell。當那個 shell 是
bash
時,這也將取決於使用者在他的 中擁有~/.bashrc
什麼,或者裡面有什麼/etc/bash.bashrc
(例如bash-completion
,當安裝打開 ksh 風格的擴展萬用字元時從那裡呼叫),因為由於某種原因bash
在呼叫時讀取那些ssh
(即使這不是一個互動式外殼)。這也意味著,如果
something
是例如'blah; rm -rf "$HOME"'
,那將產生災難性的後果。這就是設計的錯誤之一
ssh
。如果你想強制一個特定的 shell 將它擴展
something
成一個文件列表,你可以使用這個技巧:LC_SCPFILES=something scp -o SendEnv=LC_SCPFILES "localhost:</dev/null bash -O extglob -c 'exec scp -f -- \$LC_SCPFILES';exit" /dest/dir
僅當遠端使用者的登錄 shell 是普通的 Unix shell(至少屬於 Bourne、csh、rc 或 fish 系列)並且
bash
安裝在那裡並sshd
允許傳遞名稱以LC_
.訣竅是大多數
sshd
部署允許傳遞名稱以開頭的環境變數LC_
(需要這樣西班牙使用者才能從西班牙語的遠端命令中獲取錯誤消息(而不是遠端系統上的預設語言或遠端使用者的語言)實例)。所以在這裡,我們傳入
something
一個LC_SCPFILES
環境變數。在遠端機器上,
sshd
將執行:that-shell -c 'scp -f </dev/null bash -O extglob -c '\''exec scp -f -- $LC_SCPFILES'\'';exit'
因為它的標準輸入是從 重定向的
/dev/null
,所以第一個scp
將立即退出。然後我們啟動我們選擇的 shell (bash
),使用extglob
選項和exec scp -f -- $LC_SCPFILES
命令行進行解釋。因為
bash
將在子程序中執行that-shell
(我們通過在之後添加一個來強制執行;exit
) ,bash
所以~/.bashrc
我們可以期待那裡的預設行為bash
(除非以某種方式that-shell
在啟動時設置BASHOPTS
或SHELLOPTS
環境BASH_ENV
變數)。因為
$LC_SCPFILES
沒有被引用,所以它會受到分詞和文件名生成(globbing)的影響,而不是其他 shell 擴展,它不會rm -rf "$HOME"
僅僅因為something
包含它而做喜歡的事情。現在我們確保了
bash -O extglob
在遠端機器上擴展了模式,我們可以使用它來匹配使用擴展 glob 運算符的模式(這裡使用輔助函式):safer_scp() ( file=$1; shift export LC_SCPFILES="${file#*:}" exec scp -o SendEnv=LC_SCPFILES "${file%%:*}:</dev/null bash -O extglob -c 'exec scp -f -- \$LC_SCPFILES';exit" "$@" ) safer_scp user@host:'file-name-version-+([0-9]).+([0-9]).+([0-9]).jar' .
,
+([0-9])
withextglob
on inbash
匹配一個或多個十進制數字。所以上面的模式會匹配file-name-version-1.2.3.jar
,file-name-version-12.123.1234.jar
例如。(請注意,
safer_scp
上面假設第一個參數是host:file-patterns
,類似safer_scp -r ...
或safer_scp host1:f1 host2:f2 ...
不起作用的東西。如果你想使用-r
,最簡單的方法是定義一個safer_scp_r
函式,scp -f
上面替換為scp -r -f
)。請注意,您可以通過
IFS=;
在exec scp...
上面添加 a 來禁用分詞。另請注意,我們在
bash
這裡使用它是基於它已安裝在所有 GNU 系統上,但如果您知道zsh
它安裝在遠端系統上,您可以使用zsh -o extendedglob -o globsust
zsh
而是從globbing的全部功能中受益(遞歸,限定符……)(
-o shwordsplit
如果您還想要分詞,請添加)。例如:
safer_scp() ( file=$1; shift export LC_SCPFILES="${file#*:}" exec scp -o SendEnv=LC_SCPFILES "${file%%:*}:</dev/null zsh -o extendedglob -o globsubst -c 'exec scp -f -- \$LC_SCPFILES';exit" "$@" ) safer_scp user@host:'file-name-version-<->(.<->)#.jar' .
將複製
file-name-version-1.jar
andfile-name-version-1.2.3.4.5.jar
(<x-y>
是從x
to的任何十進制整數y
,<->
是任何十進制整數,#
就像正則*
表達式運算符(前面的原子的 0 個或多個))