Wildcards

排除 SCP-filepattern 的字元

  • October 4, 2016

有沒有辦法建構一個表達式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將執行以下登錄 shell user

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在啟動時設置BASHOPTSSHELLOPTS環境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])with extglobon inbash匹配一個或多個十進制數字。所以上面的模式會匹配file-name-version-1.2.3.jarfile-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.jarand file-name-version-1.2.3.4.5.jar(<x-y>是從xto的任何十進制整數y<->是任何十進制整數,#就像正則*表達式運算符(前面的原子的 0 個或多個))

引用自:https://unix.stackexchange.com/questions/103058