在Bash中使用基于Perl的重命名命令和find

时间:2013-11-23 16:11:23

标签: linux perl bash redirect file-descriptor

今天我在玩Bash脚本时偶然发现了Perl。当我尝试删除多个文件名中的空格时,我找到了this帖子,这对我帮助很大。

经过大量的努力,我终于明白了重命名和替换命令及其语法。由于文件重复,我想尝试用“x”替换文件名末尾的所有“_(x)”。但是当我尝试自己做的时候,似乎没有用。我有以下代码的三个问题:

  • 我跑的时候为什么没有执行?
  • 我使用重定向向我显示成功说明是一个错误,所以我知道发生了什么。我做错了什么?
  • 经过大量的研究,我仍然不完全理解Bash中的文件描述符和重定向以及Perl中替换函数的语法。有人可以给我一个好的教程链接吗?
find -name "*_(*)." -type f | \
  rename 's/)././g' && \
find -name "*_(*." -type f | \
  rename 's/_(//g'  2>&1

1 个答案:

答案 0 :(得分:2)

您需要使用xargs或者您需要使用find执行命令的能力:

find -name "*_(*)." -type f | xargs rename 's/)././g'
find -name "*_(*."  -type f | xargs rename 's/_(//g'

或者:

find -name "*_(*)." -type f -exec rename 's/)././g' {} +
find -name "*_(*."  -type f -exec rename 's/_(//g'  {} +

在这两种情况下,文件名都会添加到rename的命令行中。实际上,rename必须读取其标准输入才能发现文件名 - 而事实并非如此。

第一个find是否找到了您想要的文件?是否需要图案末尾的点?正则表达式是否符合您的期望?好吧,让我们调试一些。

您可以使用更复杂的正则表达式在一个命令中完成所有操作:

find . -name "*_(*)" -type f -exec rename 's/_\((\d+)\)$/$1/' {} +

find模式已更正为失去追踪.的要求。如果在扩展名之前插入了_(x),那么您需要"*_(*).*"作为find的模式(并且您需要修改Perl正则表达式)。

Perl替代品需要解剖:

  • \(匹配左括号。
  • (启动了一个捕获组。
  • \d+会查找“一个或多个数字”。
  • )会停止捕获组。这是第一个也是唯一一个,因此给出数字1。
  • \)匹配一个右括号。
  • $与文件名的末尾匹配。
  • 替换中的$1将捕获组1的值放入替换文本中。

在您的代码中,2>&1将第二个rename命令的错误消息发送到标准输出而不是标准错误。这真的没什么用。

你需要两个单独的教程;你不会找到一个涵盖Bash中的I / O重定向和Perl中的正则表达式的教程。

'官方'Perl正则表达式教程是:

  • perlretut,也可在您的计算机上以perldoc perlretut格式使用。

Bash手册涵盖了I / O重定向,但它有些简洁: