2013-11-23 40 views
1

我今天在玩Bash脚本时偶然发现了Perl。当我试图删除多个文件名中的空格时,我发现了this后,这对我有很大帮助。在Bash中使用基于Perl的重命名命令

经过很多努力,我终于明白了重命名和替换命令及其语法。我想尝试在文件名末尾用“x”取代所有“_(x)”,这是由于文件重复。但是当我尝试自己做这件事时,它似乎并不奏效。我有三个问题用下面的代码:

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

回答

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重定向,但它是有点简洁:

+0

谢谢,这确实让我非常吃惊。但我仍然不明白为什么没有xargs或exec在[我提到的例子]中使用(http://stackoverflow.com/questions/2709458/bash-script-to-replace-spaces-in-file-names) 。 在那里,正则表达式之后的重命名命令足以删除文件名中的空白。 另外,如果我与exec或xargs一起工作,这有什么关系吗?其中一种解决方案更适合于此目的吗? – nst1nctz

+0

它取决于'rename'或'prename'命令的定义。有些版本可能每行读取一个文件名;我有的版本(最初从骆驼书第一版中选择)就是这样做的。如果使用命令行参数进行调用,则会重命名这些参数;如果在没有命令行参数的情况下调用(除了正则表达式),它会读取标准输入,在换行符上分割并将其作为文件进行处理。我的版本粗心大意地淹没整个标准输入;如果处理千兆字节的文件名,这是次优的。 –