Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/regex/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Regex 基于文件名使用bash和Perl批量重命名文件_Regex_Linux_Perl_Bash_Shell - Fatal编程技术网

Regex 基于文件名使用bash和Perl批量重命名文件

Regex 基于文件名使用bash和Perl批量重命名文件,regex,linux,perl,bash,shell,Regex,Linux,Perl,Bash,Shell,我希望只批量重命名当前目录中的文件,并从文件名末尾删除某些字符串 样本: 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

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

样本:

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

试试:

$ rename 's/-\(ab-\d+\)(?=\.txt$)//' *.txt
有一个用Perl编写的
rename
命令。它的第一个参数是描述如何转换文件名的Perl代码。您可以在自己的Perl程序或一行程序中使用相同的
s//
命令


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

,您可以编写如下代码:

for file in *-\(ab-[0-9]*\)*; do
    newfile="${file/-(ab-[0-9]*)/}"
    mv "$file" "$newfile"
done
更简单、更短(更好?:)
rename
regex:

rename 's@-\(.*?\)@@' foo*.txt
当你说在当前目录下时,你是指在当前目录下,还是指在当前目录及其子目录中的任何地方

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
选中此项:

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
> 
有关详细说明,请检查使用Perl正则表达式重命名文件 通过使用
find
perl
xargs
,您可以使用这一行程序

find . -type f | perl -pe 'print $_; s/input/output/' | xargs -n2 mv
不调用
mv
的结果应该是

OldName NewName
OldName NewName
OldName NewName
它是如何工作的?
  • find-键入f
    输出文件路径(或文件名…您可以在此处控制正则表达式处理的内容!)
  • -p
    打印要由正则表达式处理的文件路径,
    -e
    执行内联脚本
  • print$\ucode>首先打印原始文件名(独立于
    -p
  • -n2
    每行打印两个元素
  • mv
    获取上一行的输入

  • 仅使用perl的另一种方法:

    perl -E'for (<*.*>){ ($new = $_) =~ s/(^.+?)(-\(.+)(\..*$)/$1$3/; say  $_." -> ".$new}'
    
    perl-E'for(){($new=$\)=~s/(^.+?)(\(.+)(\..*$)/$1$3/;比如说$.->“$new}”
    
    say…
    很适合测试,只需将其替换为
    rename$\u$new
    rename($\u$new)

  • 读取当前目录中的每个文件
  • ($new=$\u)=~
    将以下替换保存在
    $new
    中,并保持
    $\ucode>不变
  • (^.+?)
    将此匹配保存在$1中,从开始到
  • (\(.+)
    找到序列“-(…任何东西…”)。(此匹配项将保存在$2中)
  • (\..*$)
    将行结束($)之前最后一个“.”(句点)的所有内容保存到并包括行结束->到$3中
  • $1$3

  • (您也可以使用
    perl-E'for(){…

    为特定目录执行此操作。为什么不想使用任何perl模块?为了在我的主脚本中插入代码后使其在多台机器上可移植,因此并非每台机器都必须安装模块依赖项。有很多perl“核心”任何标准Perl安装都应该提供的模块。其中一个模块是
    File::Find
    ,但您的问题似乎不需要它。当前目录只有一级,没有子目录。我将尝试一下,谢谢。此代码将下降到子目录中,而不是您想要的。我添加了一个解决方案,仅重命名文件当前目录中的y。如果目录中的两个文件名为
    foo-bar-(ab-4529111094).txt
    foo-bar-(ab-189534).txt
    ,会发生什么情况?对不起,请注意字符串“foo”文件名的开头可以是任何类似于用破折号分隔的多个单词的内容,@sputnick编写的内容将适用于文件名开头的任何内容,只要它有一个连字符、一个开头部分和(稍后的某一点)结尾部分。您是否尝试过创建您在问题中提到的确切文件名,并查看其是否适用于这些文件名?工作完全符合我的要求,而其他解决方案则没有,节省了我的时间,非常感谢!奇怪。我只是创建了与您的问题相同的文件名,然后粘贴在上面的
    rename
    命令中,效果很好。尝试时发生了什么?是否有任何错误消息?如果将
    -v
    选项置于
    重命名
    命令中,是否会产生任何输出?显然有多个名为“重命名”的命令;一些Linux发行版附带了一个非perl版本,其工作方式有所不同。请参阅:Arnon Weinberg:很好,谢谢。答案已更新以反映这一点。