zmv (zsh) 通过 ssh 在 shell 和脚本之间表现不同

zmv (zsh) 通过 ssh 在 shell 和脚本之间表现不同

我真的很感激帮助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 的-w-W选项。该-W选项是唯一不会出错的选项,所以例如我可以这样做:

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

它有效。但是,如果我省略替换组中的其中一个*,zmv 会说:“错误:每个模式中的通配符数量必须匹配”,当我试图省略原始文件名的部分内容时,这没有多大帮助。

我应该怎么做?

答案1

这里的问题是引用 - 并且不特定于 zsh 或 zmv

在你的指挥下

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

“弱”外部双引号不会阻止本地 shell$2扩展为(可能为空)位置参数$2- 所以远程 shell 看到的是

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

如果(xxx_)(*)匹配两个文件,则 zmv 尝试将它们重命名为,yyy_并产生错误both map to yyy_

替换中具有通配符模式的版本(由-W开关启用)不会遇到同样的问题,因为即使在双引号中,通配符(shell 全局变量)也不会扩展。

解决该问题的最简单方法是添加另一层引用,以便$2不受干扰地传递到远程 shell:

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

这里也使用&&代替,;因为如果失败你不想zmv运行cd,否则你最终会重命名me主目录中的文件myserver

有关引用和 SSH 问题的更一般性讨论,包括使用此处文档的替代解决方法,请参阅相关问题

相关内容