根据文件名使用 bash 和 Perl 批量重命名文件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14247582/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Bulk renaming files with bash and Perl based on file name
提问by SilverShadow
I'm looking to bulk rename files in the current directory only and remove certain strings from the end of file names.
我只想批量重命名当前目录中的文件,并从文件名的末尾删除某些字符串。
Sample:
样本:
foo-bar-(ab-4529111094).txt
foo-bar-foo-bar-(ab-189534).txt
foo-bar-foo-bar-bar-(ab-24937932201).txt
the output should look like this:
输出应如下所示:
foo-bar.txt
foo-bar-foo-bar.txt
foo-bar-foo-bar-bar.txt
I want to remove the string -(ab-2492201)at the end of each file name
knowing that the digits can vary in length.
我想删除-(ab-2492201)每个文件名末尾的字符串,因为知道数字的长度可能不同。
A Perl regex is preferred over modules and without using any utilities and for bash oneliner command is highly preferred.
Perl 正则表达式比模块更受欢迎,并且不使用任何实用程序,对于 bash oneliner 命令是非常受欢迎的。
How to accomplish that in both Perl and Bash Shell on Linux? interested to know both solutions.
如何在 Linux 上的 Perl 和 Bash Shell 中实现这一点?有兴趣了解这两种解决方案。
采纳答案by larsks
In bash, you could write something like:
在 bash 中,你可以这样写:
for file in *-\(ab-[0-9]*\)*; do
newfile="${file/-(ab-[0-9]*)/}"
mv "$file" "$newfile"
done
回答by Smylers
Try:
尝试:
$ rename 's/-\(ab-\d+\)(?=\.txt$)//' *.txt
There's a renamecommand written in Perl. Its first argument is Perl code describing how to transform a filename. You could use the same s///command in your own Perl program or one-liner.
有一个rename用 Perl 编写的命令。它的第一个参数是描述如何转换文件名的 Perl 代码。您可以s///在自己的 Perl 程序或单行程序中使用相同的命令。
If that doesn't work, try prenameinstead of rename; there's a different, non-Perl-based, renamecommand installed on some systems, in which case the Perl one may be called prename.
如果这不起作用,请尝试prename代替rename; rename在某些系统上安装了一种不同的、非基于 Perl 的命令,在这种情况下,可以调用 Perl 命令prename。
回答by Borodin
When you say underthe current directory, do you mean inthe current directory, or anywhere in or beaneath the current directory and its descendants?
当您说在当前目录下时,您是指在当前目录中,还是在当前目录及其子目录中或之下的任何位置?
File::Findis a simple way to do the latter, and is a core module so won't need installing. Like so:
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)$//i;
print "rename $_, $newname\n";
}
Update
更新
This program will rename all the files with the given filename pattern only within the current directory.
该程序将仅在当前目录中使用给定的文件名模式重命名所有文件。
Note that the initial openloop is there only to create sample files for renaming.
请注意,初始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)$//i;
print "rename $_, $newname\n";
rename $_, $newname;
}
output
输出
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
回答by Jonathan Komar
Using Perl Regex to Rename Files
使用 Perl 正则表达式重命名文件
With find, perl, and xargs, you could use this one-liner
随着find, perl, 和xargs,你可以使用这个单行
find . -type f | perl -pe 'print $_; s/input/output/' | xargs -n2 mv
Results without calling mvshould just be
没有调用的结果mv应该只是
OldName NewName
OldName NewName
OldName NewName
How does it work?
它是如何工作的?
find . -type foutputs file paths (or file names...you control what gets processed by regex here!)-pprints file paths to be processed by regex,-eexecutes inline scriptprint $_prints the original file name first (independent of-p)-n2prints two elements per linemvgets the input of the previous line
find . -type f输出文件路径(或文件名……您可以在此处控制正则表达式处理的内容!)-p打印正则表达式要处理的文件路径,-e执行内联脚本print $_首先打印原始文件名(独立于-p)-n2每行打印两个元素mv获取上一行的输入
回答by Vijay
check this:
检查这个:
ls -1 | nawk '/foo-bar-/{old=rename 's@-\(.*?\)@@' foo*.txt
;gsub(/-\(.*\)/,"",perl -E'for (<*.*>){ ($new = $_) =~ s/(^.+?)(-\(.+)(\..*$)//; say $_." -> ".$new}'
);system("mv \""old"\" "##代码##)}'
> 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=##代码##;gsub(/-\(.*\)/,"",##代码##);system("mv \""old"\" "##代码##)}'
> ls -1 foo*
foo-bar-foo-bar-bar.txt
foo-bar-foo-bar.txt
foo-bar.txt
>
For detailed explanation check here
有关详细说明,请查看此处
回答by Gilles Quenot
A simpler, shorter (better ? :) ) renameregex :
一个更简单、更短(更好?:))的rename正则表达式:
回答by eli
Another way using just perl:
仅使用 perl 的另一种方法:
##代码##(say ...is nice for testing, just replace it with rename $_,$newor rename($_,$new))
(say ...很适合测试,只需将其替换为rename $_,$new或rename($_,$new))
<*.*>read every file in the current directory($new = $_) =~saves the following substitution in$newand leaves$_as intact(^.+?)save this match in $1 and non-greedy match from the beginning until...(-\(.+)the sequence "-( ...anything..." is found. (this match would be saved in $2)(\..*$)save everything from the last "." (period) before the end ($) of the line until and including the end of the line -> into $3- substitute the match with the string generated from
$1$3
<*.*>读取当前目录中的每个文件($new = $_) =~保存以下替换$new并$_保持不变(^.+?)将此匹配保存在 $1 和非贪婪匹配中,从开始到...(-\(.+)找到了序列 "-( ...anything..."。(此匹配将保存在 $2 中)(\..*$)保存最后一个“.”的所有内容 (句号) 在行尾 ($) 之前直到并包括行尾 -> 进入 $3- 用生成的字符串替换匹配项
$1$3
( you could also do it for a specific directory with perl -E'for (</tmp/my/directory/*.*>){ .....
(您也可以为特定目录执行此操作 perl -E'for (</tmp/my/directory/*.*>){ .....

