使用基于文件名的bash和Perl批量重命名文件

时间:2013-01-09 22:21:37

标签: regex linux perl bash shell

我希望仅批量重命名当前目录中的文件,并从文件名末尾删除某些字符串。

样品:

foo-bar-(ab-4529111094).txt
foo-bar-foo-bar-(ab-189534).txt
foo-bar-foo-bar-bar-(ab-24937932201).txt

输出应如下所示:

foo-bar.txt
foo-bar-foo-bar.txt
foo-bar-foo-bar-bar.txt

我想删除每个文件名末尾的字符串-(ab-2492201) 知道数字的长度会有所不同。

Perl正则表达式比模块更受欢迎,并且不使用任何实用程序,因此非常喜欢使用bash oneliner命令。

如何在Linux上的Perl和Bash Shell中实现这一点?有兴趣了解这两种解决方案。

7 个答案:

答案 0 :(得分:5)

尝试:

$ rename 's/-\(ab-\d+\)(?=\.txt$)//' *.txt

用Perl编写了一个rename命令。它的第一个参数是描述如何转换文件名的Perl代码。您可以在自己的Perl程序或单行程序中使用相同的s///命令。

如果不起作用,请尝试prename而不是rename;在某些系统上安装了一个不同的,基于非Perl的rename命令,在这种情况下,可以将Perl命令称为prename

答案 1 :(得分:4)

在bash中,您可以编写如下内容:

for file in *-\(ab-[0-9]*\)*; do
    newfile="${file/-(ab-[0-9]*)/}"
    mv "$file" "$newfile"
done

答案 2 :(得分:2)

当您在当前目录下说时,您是指 in 当前目录,还是当前目录及其后代中的任何位置?

File::Find是一种简单的方法,它是一个核心模块,因此不需要安装。像这样:

use strict;
use warnings;

use autodie;

use File::Find;

find(\&rename, '.');

sub rename {
  return unless -f;
  my $newname = $_;
  return unless $newname =~ s/-\(ab-[0-9]+\)(\.txt)$/$1/i;
  print "rename $_, $newname\n";
}

<强>更新

此程序将仅在当前目录中重命名具有给定文件名模式的所有文件。

请注意,初始open循环仅用于创建用于重命名的示例文件。

use strict;
use warnings;

use autodie;

open my $fh, '>', $_ for qw(
  foo-bar-(ab-4529111094).txt
  foo-bar-foo-bar-(ab-189534).txt
  foo-bar-foo-bar-bar-(ab-24937932201).txt
);

for (glob '*.txt') {
  next unless -f;
  my $newname = $_;
  next unless $newname =~ s/-\(ab-[0-9]+\)(\.txt)$/$1/i;
  print "rename $_, $newname\n";
  rename $_, $newname;
}

<强>输出

rename foo-bar-(ab-4529111094).txt, foo-bar.txt
rename foo-bar-foo-bar-(ab-189534).txt, foo-bar-foo-bar.txt
rename foo-bar-foo-bar-bar-(ab-24937932201).txt, foo-bar-foo-bar-bar.txt

答案 3 :(得分:1)

更简单,更短(更好?:))rename正则表达式:

rename 's@-\(.*?\)@@' foo*.txt

答案 4 :(得分:1)

检查一下:

ls -1 | nawk '/foo-bar-/{old=$0;gsub(/-\(.*\)/,"",$0);system("mv \""old"\" "$0)}'

> ls -1 foo*
foo-bar-(ab-4529111094).txt
foo-bar-foo-bar-(ab-189534).txt
foo-bar-foo-bar-bar-(ab-24937932201).txt

> ls -1 | nawk '/foo-bar-/{old=$0;gsub(/-\(.*\)/,"",$0);system("mv \""old"\" "$0)}'

> ls -1 foo*
foo-bar-foo-bar-bar.txt
foo-bar-foo-bar.txt
foo-bar.txt
> 

有关详细说明,请查看here

答案 5 :(得分:0)

使用Perl正则表达式重命名文件

通过findperlxargs,您可以使用这种单线纸

find . -type f | perl -pe 'print $_; s/input/output/' | xargs -n2 mv

不调用mv的结果应该只是

OldName NewName
OldName NewName
OldName NewName

它如何工作?

  1. find . -type f输出文件路径(或文件名...您在这里控制正则表达式要处理的内容!)
  2. -p打印正则表达式要处理的文件路径,-e执行内联脚本
  3. print $_首先打印原始文件名(独立于-p
  4. -n2每行打印两个元素
  5. mv获取上一行的输入

答案 6 :(得分:0)

仅使用perl的另一种方法:

perl -E'for (<*.*>){ ($new = $_) =~ s/(^.+?)(-\(.+)(\..*$)/$1$3/; say  $_." -> ".$new}'

({say ...非常适合测试,只需将其替换为rename $_,$newrename($_,$new)

  1. <*.*>读取当前目录中的每个文件
  2. ($new = $_) =~将以下替换保存在$new中,并使$_保持不变
  3. (^.+?)将此匹配项从开始一直保存到$ 1,并将非贪心匹配项保存到...
  4. (-\(.+)序列“-(...任何...”。(此匹配项将保存在$ 2中)
  5. (\..*$)保存最后一个“”中的所有内容。 (句点)在行尾($)之前,直到并包括行尾->进入$ 3
  6. 使用从$1$3生成的字符串替换匹配项

(您也可以使用perl -E'for (</tmp/my/directory/*.*>){ .....

对特定目录执行此操作