为什么每当我使用完整路径而不是当前路径时,“重命名”的行为会有所不同?

为什么每当我使用完整路径而不是当前路径时,“重命名”的行为会有所不同?

好吧,我是回答问题其中 OP 在 Ubuntu 中有多个存储库,可能会导致安装不相关软件时出现问题。我建议使用单个衬垫禁用 PPA,rename然后按照一系列说明进行操作。一切都很好,我只是把这个问题留下来回答……不。结果rename没有达到我的预期:

sudo rename s/list/list\.disable/g /etc/apt/sources.list.d/*.list

有了这个,我期望重命名来查看以/etc/apt/sources.list.d/结尾的任何文件.list并将.list其替换为.list.disable.我用几乎相同的命令得到了另一个答案,但OP从未给出反馈,而且我有点在没有先测试的情况下就抛出了这个理论。因此,令我惊讶的是,OP 发现了该行的问题:

Can't rename /etc/apt/sources.list.d/iaz-battery-status-quantal.list /etc/apt/sources.list.disable.d/iaz-battery-status-quantal.list.disable: No such file or directory
Can't rename /etc/apt/sources.list.d/ubuntu-wine-ppa-quantal.list /etc/apt/sources.list.disable.d/ubuntu-wine-ppa-quantal.list.disable: No such file or directory
Can't rename /etc/apt/sources.list.d/webupd8team-java-raring.list /etc/apt/sources.list.disable.d/webupd8team-java-raring.list.disable: No such file or directory

我有一种奇怪的感觉,所以我自己测试了这个理论,并看到了相同的结果。然后,每当你遇到问题时,通常是正则表达式,不?我用很多扭曲的方式改变了正则表达式:

  • s/.list/.list.disable/g
  • s/.list/.list.disable/g
  • /列表/列表.禁用/
  • 其他我不记得的组合

好吧,我认为正则表达式不是问题,所以我瞪了选择器,然后更改它/etc/apt/sources.list.d/*并回收正则表达式测试。没有喜悦。我有点沮丧touch some.list并应用了我的命令

rename s/\.list/\.list\.disable/g *

答对了!现在我感觉浑身都被控制了。我修正了我的答案并继续我的生活......不!这是不可接受的。为什么?我查阅了手册,令我惊讶的是,该手册仅使用当前路径示例。这是正常的吗?还是只是功能没有实现?或者我应该开始不相信我的理论?

答案1

使用该-n参数在空运行模式下运行rename,当您想要测试模式时,这非常有用:

martin@martin ~ % rename -n s/list/list.disable/g /etc/apt/sources.list.d/*.list | sed 's/renamed as/\n =>/g'
[...]
/etc/apt/sources.list.d/spotify.list 
 => /etc/apt/sources.list.disable.d/spotify.list.disable
/etc/apt/sources.list.d/steam.list 
 => /etc/apt/sources.list.disable.d/steam.list.disable
[...]

这里明显的错误是模式list匹配,因此您尝试重命名该文件夹及其包含的文件。sources.list.d

请改用此模式:

rename -n 's/\.list$/.list.disable/' /etc/apt/sources.list.d/*.list | sed 's/renamed as/\n =>/g'
[...]
/etc/apt/sources.list.d/spotify.list 
 => /etc/apt/sources.list.d/spotify.list.disable
/etc/apt/sources.list.d/steam.list 
 => /etc/apt/sources.list.d/steam.list.disable
[...]

差异是:

  1. .在搜索模式中引用 the\.可以确保该点仅匹配真实的点,而不是任何字符(这就是正则表达式中未加引号的点通常所做的事情)。

  2. 后面$的列表表示“字符串结尾”。它确保只有文件名末尾的“.list”匹配并被替换,而不是路径或文件名中其他位置的“.list”。

  3. 您不需要在替换字符串中引用点;因此,“.list.disable”无需反斜杠即可工作,因为.那里不再具有特殊含义。

  4. 另请注意,我已用单引号引用了正则表达式,以防止 shell 以任何方式修改它。

答案2

问题在于g,当您确实应该锚定模式时,却使用了全局开关。正如你所写的:

s/a/b/g

将字符串中所有位置的 a 替换为 b。这导致您尝试重命名为不存在目录的路径。这也是为什么当您在目录中执行操作时问题消失了,因此只有一个匹配项可供替换。

我认为你可能打算锚定该模式

s/\.list$/.list.disable/

这将阻止尝试将文件移动到不存在的目录 /etc/apt/sources.list.disable.d/ 中(因此您无法将文件移动到其中)。

相关内容