根据文件名使用 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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 04:12:50  来源:igfitidea点击:

Bulk renaming files with bash and Perl based on file name

regexlinuxperlbashshell

提问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?

它是如何工作的?

  1. find . -type foutputs file paths (or file names...you control what gets processed by regex here!)
  2. -pprints file paths to be processed by regex, -eexecutes inline script
  3. print $_prints the original file name first (independent of -p)
  4. -n2prints two elements per line
  5. mvgets the input of the previous line
  1. find . -type f输出文件路径(或文件名……您可以在此处控制正则表达式处理的内容!)
  2. -p打印正则表达式要处理的文件路径,-e执行内联脚本
  3. print $_首先打印原始文件名(独立于-p
  4. -n2每行打印两个元素
  5. 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 $_,$newrename($_,$new)

  1. <*.*>read every file in the current directory
  2. ($new = $_) =~saves the following substitution in $newand leaves $_as intact
  3. (^.+?)save this match in $1 and non-greedy match from the beginning until...
  4. (-\(.+)the sequence "-( ...anything..." is found. (this match would be saved in $2)
  5. (\..*$)save everything from the last "." (period) before the end ($) of the line until and including the end of the line -> into $3
  6. substitute the match with the string generated from $1$3
  1. <*.*>读取当前目录中的每个文件
  2. ($new = $_) =~保存以下替换$new$_保持不变
  3. (^.+?)将此匹配保存在 $1 和非贪婪匹配中,从开始到...
  4. (-\(.+)找到了序列 "-( ...anything..."。(此匹配将保存在 $2 中)
  5. (\..*$)保存最后一个“.”的所有内容 (句号) 在行尾 ($) 之前直到并包括行尾 -> 进入 $3
  6. 用生成的字符串替换匹配项 $1$3

( you could also do it for a specific directory with perl -E'for (</tmp/my/directory/*.*>){ .....

(您也可以为特定目录执行此操作 perl -E'for (</tmp/my/directory/*.*>){ .....