【问题标题】:Bulk renaming files with bash and Perl based on file name根据文件名使用 bash 和 Perl 批量重命名文件
【发布时间】:2012-12-24 05:31:16
【问题描述】:

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

示例:

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

【问题讨论】:

  • 为什么不想使用任何 Perl 模块?
  • 在我的主脚本中插入代码后使其在多台机器上可移植,因此并非每台机器都必须安装模块依赖项。
  • 任何标准 Perl 安装都应该有很多 perl“核心”模块。其中一个是File::Find,但您的问题似乎不需要。

标签: regex linux perl bash shell


【解决方案1】:

试试:

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

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

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

【讨论】:

  • 奇数。我刚刚创建了与您问题中的名称完全相同的文件,然后粘贴到上面的rename 命令中,它工作正常。当你尝试它时发生了什么?有任何错误信息吗?如果您将-v 选项放在rename 命令中,会给出任何输出吗?
  • 显然不止一个命令叫做“重命名”;一些 Linux 发行版带有一个工作方式不同的非 perl 版本。见:stackoverflow.com/questions/22577767/…
  • Arnon Weinberg:很好,谢谢。已更新答案以反映这一点。
【解决方案2】:

在 bash 中,你可以这样写:

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

【讨论】:

  • 工作完美,就像我想要的,而其他解决方案却没有,节省了我的时间,非常感谢!
【解决方案3】:

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

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

【讨论】:

  • 没有用,抱歉,请注意文件名开头的字符串“foo”可能是由破折号分隔的多个单词 -
  • @sputnick 写的内容适用于文件名开头的任何内容,只要它有一个连字符、一个左括号和(稍后)一个右括号。您是否尝试创建您在问题中提到的确切文件名并查看它是否适用于这些文件名?
【解决方案4】:

当您说 under 当前目录时,您是指 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

【讨论】:

  • 当前目录只有一级,没有子目录。我会试试的,谢谢
  • 此代码将下降到子目录中,并且不是您想要的。
  • 我添加了仅在当前目录中重命名文件的解决方案。
  • 如果目录中的两个文件分别命名为foo-bar-(ab-4529111094).txtfoo-bar-(ab-189534).txt会怎样?
【解决方案5】:

检查一下:

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

【讨论】:

    【解决方案6】:

    使用 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 获取上一行的输入

    【讨论】:

      【解决方案7】:

      仅使用 perl 的另一种方式:

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

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

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

      (您也可以使用 perl -E'for (&lt;/tmp/my/directory/*.*&gt;){ ..... 对特定目录执行此操作

      【讨论】:

        猜你喜欢
        • 2010-10-10
        • 2012-09-02
        • 1970-01-01
        • 2021-04-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-10-31
        • 1970-01-01
        相关资源
        最近更新 更多