5

我正在寻找仅在当前目录中批量重命名文件并从文件名末尾删除某些字符串。

样本:

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 中实现这一点?有兴趣了解这两种解决方案。

4

7 回答 7

7

尝试:

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

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

如果这不起作用,请尝试prename代替rename; 在某些系统上安装了一个不同的、非基于 Perl 的rename命令,在这种情况下,可能会调用 Perl 命令prename

于 2013-01-09T22:26:52.400 回答
4

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

for file in *-\(ab-[0-9]*\)*; do
    newfile="${file/-(ab-[0-9]*)/}"
    mv "$file" "$newfile"
done
于 2013-01-09T22:28:27.080 回答
3

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

使用find,perlxargs, 你可以使用这个单线

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获取上一行的输入
于 2019-02-24T17:36:44.510 回答
2

当您说当前目录下时,您是指当前目录中,还是在当前目录及其后代中或下方的任何地方?

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
于 2013-01-09T22:38:20.930 回答
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
> 

有关详细说明,请查看此处

于 2013-01-10T05:53:22.977 回答
1

一个更简单、更短(更好?:))rename正则表达式:

rename 's@-\(.*?\)@@' foo*.txt
于 2013-01-09T22:29:18.763 回答
0

仅使用 perl 的另一种方法:

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

say ...很适合测试,只需将其替换为rename $_,$newor rename($_,$new)

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

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

于 2019-08-08T07:44:47.567 回答