2013-01-09 113 views
3

我正在寻找批量重命名当前目录中的文件,并从文件名末尾删除某些字符串。使用bash和Perl批量重命名文件基于文件名

样品:

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中完成该操作?有兴趣知道两种解决方案。

+0

为什么你不希望使用任何Perl模块? – Borodin

+0

在我的主脚本中插入代码之后,可以在多台机器上进行移植,因此并非每台机器都必须安装模块依赖关系。 – SilverShadow

+0

perl“核心”模块非常多,应该可以在任何标准的Perl安装中使用。一旦它们是'File :: Find',但它似乎不是您的问题所必需的。 – Borodin

回答

4

在bash,你可以写这样的:

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

工作完美像我想要的其他解决方案没有,保存我的时间,非常感谢! – SilverShadow

5

尝试:

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

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

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

+0

没有工作的伴侣,但我仍然在努力,谢谢 – SilverShadow

+0

奇怪。我只是在你的问题中创建了具有确切名称的文件,然后粘贴到上面的'rename'命令中,并且它工作正常。当你尝试时发生了什么?有没有错误信息?如果你在'rename'命令中加入了'-v'选项,它是否会提供任何输出? – Smylers

+1

显然有不止一个叫做“重命名”的命令;一些Linux发行版带有一个非perl版本,其工作方式不同。见:http://stackoverflow.com/questions/22577767/get-the-perl-rename-utility-instead-of-the-built-in-rename –

1

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

rename '[email protected]\(.*?\)@@' foo*.txt 
+1

试试吧,谢谢:)) – SilverShadow

+0

没有工作,对不起,请注意,字符串“foo”在文件名的开头可以是任何类似多个单词用短划线分隔 - – SilverShadow

+0

What @sputnick写的将与文件名开头的任何内容,只要它有一个连字符,一个开头的paren,以及(稍后的某个点)一个关闭的paren。你有没有尝试创建你在问题中提到的确切文件名,看看它是否适用于这些? – Smylers

2

当你说当前目录下,你的意思是的当前目录,或者任何地方或者beaneath当前目录及其后代?

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 
+0

当前目录只有一个级别,没有子目录。我会尝试,谢谢 – SilverShadow

+0

这段代码将下降到子目录,是*不*你想要的。 – Borodin

+0

好的,谢谢你的时间兄弟 – SilverShadow

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