Shell-Script

ssh 上的 zmv (zsh) 在 shell 和腳本之間的行為不同

  • June 29, 2020

我非常感謝zmv通過腳本中的 ssh 按預期工作的幫助。

我正在嘗試更改我可以完全控制的遠端伺服器上的文件名。本地和遠端機器都執行 macOS 10.14.6,zsh 作為預設 shell。

如果我打開一個 zsh 終端視窗,通過 ssh 連接,然後鍵入zmv '(xxx_)(*)' 'yyy_$2',它會按預期工作。但是,如果我將 zmv 放在 ssh 中,我假設我必須將其打包到腳本中:

ssh me@myserver "cd /Users/me/mypath; autoload zmv; zmv '(xxx_)(*)' 'yyy_$2'"

它失敗了,因為 zmv 提到了每個文件對:“都映射到 yyy_”。換句話說,要麼它不能辨識匹配組,要麼反向引用不起作用。

我只是了解 zsh 和 ssh 是兩種不同的 shell 並且具有不同的環境,因此例如我發現autoload zmv即使它位於遠端電腦上的 .zshrc 中,我也需要它。我嘗試添加noglob zmv(再次設置在 .zshrc 中),並且嘗試轉義任何數量的東西。

我還嘗試了zmv 的-wand-W選項。該-W選項是唯一不會出錯的選項,因此例如我可以這樣做:

ssh me@myserver "cd /Users/me/mypath; autoload zmv; zmv -n -W 'xxx_*_*_*.*' '*-*-*.*'"

它有效。但是,如果我省略*了替換組中的一個,zmv 會說:“錯誤:每個模式中的萬用字元數量必須匹配”,當我試圖省略部分原始文件名時,這並沒有多大幫助。

我應該怎麼做?

這裡的問題是引用 - 並不特定於 zsh 或 zmv

在你的命令下

ssh me@myserver "cd /Users/me/mypath; autoload zmv; zmv '(xxx_)(*)' 'yyy_$2'"

“弱”外部雙引號不會阻止本地外殼程序$2將其擴展為(可能是空$2的)位置參數 - 所以遠端外殼程序看到的是

cd /Users/me/mypath; autoload zmv; zmv '(xxx_)(*)' 'yyy_'

如果匹配兩個文件,則zmv(xxx_)(*)嘗試將它們都重命名為yyy_both map to yyy_

替換中具有萬用字元模式的版本(由-W開關啟用)不會遇到同樣的問題,因為萬用字元(shell glob)即使在雙引號中也不會擴展。

解決此問題的最簡單方法是添加另一層引用,以便$2不受干擾地傳遞到遠端 shell:

ssh me@myserver "cd /Users/me/mypath && autoload zmv && zmv '(xxx_)(*)' 'yyy_\$2'"

這裡也使用&&而不是,;因為如果失敗,您不想zmv執行cd,否則您最終會重命名me’s 主目錄中的文件myserver

有關引用和 SSH 問題的更一般性討論,包括使用此處文件的替代解決方法,請參閱相關問題

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