使用基于原始文件夹的regexp仅比较和重命名目录中的文件

时间:2022-06-21 10:33:43

I need to rename only files in sub-directories of a folder based on another folder (original folder) and its sub-directories ...

我需要重命名基于另一个文件夹(原始文件夹)及其子目录的文件夹子目录中的文件...

Folder1 contain the correct files name so if a file in some sub-directory under folder2 and exist in same location as folder1 (original) will be renamed as original file.

Folder1包含正确的文件名,因此如果folder2下的某个子目录中存在与folder1(original)相同的位置的文件将被重命名为原始文件。

Example :

示例:

.
├── folder1
│   ├── Somedir
│   │   ├── file.xml
│   │   ├── doc
│   │   │   ├── CHANGELOG
│   │   │   ├── TEST
│   │   │   ├── file_test.txt
│   │   │   ├── sample
│   │   │   ├── README
│   │   │   ├── mydir
│   │   │   │   ├── exploitation-file.rst
│   │   │   │   ├── advanced-file.txt


.
├── folder2
│   ├── Somedir
│   │   ├── file.xml
│   │   ├── doc
│   │   │   ├── CHANGELOG
│   │   │   ├── TEST
│   │   │   ├── filetest.txt
│   │   │   ├── sample
│   │   │   ├── README
│   │   │   ├── mydir
│   │   │   │   ├── exploitationfile.rst
│   │   │   │   ├── advancedfile.txt

after running "diff -qr /folder1 /folder2" I got the differences between these two folders is this case are :

运行“diff -qr / folder1 / folder2”之后我得到了这两个文件夹之间的区别是这种情况是:

/folder2/somedir/filetest.txt (missing underscore)  vs /folder1/somedir/file_test.txt 

/folder2/somedir/doc/mydir/exploitation-file.rst (missing hyphen) vs /folder1/somedir/doc/mydir/exploitation-file.rst 

/folder2/somedir/doc/mydir/advanced-file.txt (missing hyphen) vs /folder1/somedir/doc/mydir/advanced-file.txt

2 个解决方案

#1


1  

I would recommend a combination of Path::Class and Path::Class::Rule.

我建议使用Path :: Class和Path :: Class :: Rule的组合。

The most difficult part of creating a solution to a problem like this is testing it. I therefore provide a completely self-contained script that creates a testing environment based off the example structure that you provided.

为这样的问题创建解决方案最困难的部分就是测试它。因此,我提供了一个完全独立的脚本,该脚本根据您提供的示例结构创建测试环境。

This script basically scans the __DATA__ section for files and directories to create in a special testing directory. Then the subsequent section of code actually fixes the folder2 directory based off the information in folder1.

该脚本基本上扫描__DATA__部分以查找要在特殊测试目录中创建的文件和目录。然后,后续的代码部分实际上根据folder1中的信息修复了folder2目录。

Note, this will require installation of the two above cpan modules and their dependencies.

注意,这将需要安装上面两个cpan模块及其依赖项。

use strict;
use warnings;
use autodie;

use Path::Class;
use Path::Class::Rule;

my $testdir = dir('testing');

# Setup Testing Environment
$testdir->rmtree();
$testdir->mkpath();
chdir($testdir);

while (<DATA>) {
    my ( $type, $name ) = split;

    if ( $type eq 'd' ) {
        dir($name)->mkpath();
    } else {
        file($name)->spew($name);
    }
}

# Actual Solution
my $backup_dir = dir('folder1');
my $main_dir   = dir('folder2');

my $next = Path::Class::Rule->new->file->name(qr{[_-]})->iter($backup_dir);

while ( my $file = $next->() ) {
    my $correct_name = $file->basename();
    ( my $stripped_name = $correct_name ) =~ s{[_-]}{}g;

    my $from_file = file( $main_dir, $file->dir->relative($backup_dir), $stripped_name );
    my $to_file   = file( $main_dir, $file->dir->relative($backup_dir), $correct_name );

    if ( -e $from_file ) {
        print "$from_file -> $to_file\n";
        $from_file->move_to($to_file);
    }
}

__DATA__
d folder1
d folder1/Somedir
f folder1/Somedir/file.xml
d folder1/Somedir/doc
f folder1/Somedir/doc/CHANGELOG
f folder1/Somedir/doc/TEST
f folder1/Somedir/doc/file_test.txt
f folder1/Somedir/doc/sample
f folder1/Somedir/doc/README
d folder1/Somedir/doc/mydir
f folder1/Somedir/doc/mydir/exploitation-file.rst
f folder1/Somedir/doc/mydir/advanced-file.txt
d folder2
d folder2/Somedir
f folder2/Somedir/file.xml
d folder2/Somedir/doc
f folder2/Somedir/doc/CHANGELOG
f folder2/Somedir/doc/TEST
f folder2/Somedir/doc/filetest.txt
f folder2/Somedir/doc/sample
f folder2/Somedir/doc/README
d folder2/Somedir/doc/mydir
f folder2/Somedir/doc/mydir/exploitationfile.rst
f folder2/Somedir/doc/mydir/advancedfile.txt

Outputs:

输出:

folder2/Somedir/doc/filetest.txt -> folder2/Somedir/doc/file_test.txt
folder2/Somedir/doc/mydir/advancedfile.txt -> folder2/Somedir/doc/mydir/advanced-file.txt
folder2/Somedir/doc/mydir/exploitationfile.rst -> folder2/Somedir/doc/mydir/exploitation-file.rst

#2


1  

You can use the general strategy detailed in “Better way to rename files based on multiple patterns” which breaks down the renaming task in three stages:

您可以使用“更好地重命名基于多个模式的文件”中详述的一般策略,该策略分三个阶段分解重命名任务:

job_select | job_strategy | job_process

where job_select is responsible for selecting the objects of your job, job_strategy prepares a processing plan for these objects and job_process eventually executes the plan.

job_select负责选择作业对象,job_strategy为这些对象准备处理计划,job_process最终执行计划。

# job_select SRCDIR
#  Find all files having a dash or a hyphen in name
job_select()
{
  (cd "$1" && find . -type f -name '*[-_]*')
}

# job_strategy
#  Compute the renaming plan
#
# This assume that wrong names are deduced from good names by removing `_` and `-`.
# The output has three columns,
#
#   reldir|goodname|badname
#
# For instance, ./somedir/file_test.txt yields the plan
#
#   ./somedir|file_test.txt|filestest.txt
job_strategy()
{
  sed -e '
    s@/\([^/]*\)$/@|\1@
    h
    s@^.*|@@
    s@[-_]@@g
    x
    G
    s/\n/|/
  '
}

# job_process TGTDIR
{
   cd "$1" || exit
   IFS='|'
   while read reldir goodname badname; do
     relgoodname="$reldir/$goodname"
     relbadname="$reldir/$badname"
     if [ -r "$relbadname" ]; then
       printf 'Rename %s to %s\n' "$relbadname" "$relgoodname"
       mv "$relbadname" "$relgoodname"
     else
       printf 'Skip %s\n' "$relbadname"
     fi
   done
}

job_select /folder1 | job_strategy | job_process /folder2

#1


1  

I would recommend a combination of Path::Class and Path::Class::Rule.

我建议使用Path :: Class和Path :: Class :: Rule的组合。

The most difficult part of creating a solution to a problem like this is testing it. I therefore provide a completely self-contained script that creates a testing environment based off the example structure that you provided.

为这样的问题创建解决方案最困难的部分就是测试它。因此,我提供了一个完全独立的脚本,该脚本根据您提供的示例结构创建测试环境。

This script basically scans the __DATA__ section for files and directories to create in a special testing directory. Then the subsequent section of code actually fixes the folder2 directory based off the information in folder1.

该脚本基本上扫描__DATA__部分以查找要在特殊测试目录中创建的文件和目录。然后,后续的代码部分实际上根据folder1中的信息修复了folder2目录。

Note, this will require installation of the two above cpan modules and their dependencies.

注意,这将需要安装上面两个cpan模块及其依赖项。

use strict;
use warnings;
use autodie;

use Path::Class;
use Path::Class::Rule;

my $testdir = dir('testing');

# Setup Testing Environment
$testdir->rmtree();
$testdir->mkpath();
chdir($testdir);

while (<DATA>) {
    my ( $type, $name ) = split;

    if ( $type eq 'd' ) {
        dir($name)->mkpath();
    } else {
        file($name)->spew($name);
    }
}

# Actual Solution
my $backup_dir = dir('folder1');
my $main_dir   = dir('folder2');

my $next = Path::Class::Rule->new->file->name(qr{[_-]})->iter($backup_dir);

while ( my $file = $next->() ) {
    my $correct_name = $file->basename();
    ( my $stripped_name = $correct_name ) =~ s{[_-]}{}g;

    my $from_file = file( $main_dir, $file->dir->relative($backup_dir), $stripped_name );
    my $to_file   = file( $main_dir, $file->dir->relative($backup_dir), $correct_name );

    if ( -e $from_file ) {
        print "$from_file -> $to_file\n";
        $from_file->move_to($to_file);
    }
}

__DATA__
d folder1
d folder1/Somedir
f folder1/Somedir/file.xml
d folder1/Somedir/doc
f folder1/Somedir/doc/CHANGELOG
f folder1/Somedir/doc/TEST
f folder1/Somedir/doc/file_test.txt
f folder1/Somedir/doc/sample
f folder1/Somedir/doc/README
d folder1/Somedir/doc/mydir
f folder1/Somedir/doc/mydir/exploitation-file.rst
f folder1/Somedir/doc/mydir/advanced-file.txt
d folder2
d folder2/Somedir
f folder2/Somedir/file.xml
d folder2/Somedir/doc
f folder2/Somedir/doc/CHANGELOG
f folder2/Somedir/doc/TEST
f folder2/Somedir/doc/filetest.txt
f folder2/Somedir/doc/sample
f folder2/Somedir/doc/README
d folder2/Somedir/doc/mydir
f folder2/Somedir/doc/mydir/exploitationfile.rst
f folder2/Somedir/doc/mydir/advancedfile.txt

Outputs:

输出:

folder2/Somedir/doc/filetest.txt -> folder2/Somedir/doc/file_test.txt
folder2/Somedir/doc/mydir/advancedfile.txt -> folder2/Somedir/doc/mydir/advanced-file.txt
folder2/Somedir/doc/mydir/exploitationfile.rst -> folder2/Somedir/doc/mydir/exploitation-file.rst

#2


1  

You can use the general strategy detailed in “Better way to rename files based on multiple patterns” which breaks down the renaming task in three stages:

您可以使用“更好地重命名基于多个模式的文件”中详述的一般策略,该策略分三个阶段分解重命名任务:

job_select | job_strategy | job_process

where job_select is responsible for selecting the objects of your job, job_strategy prepares a processing plan for these objects and job_process eventually executes the plan.

job_select负责选择作业对象,job_strategy为这些对象准备处理计划,job_process最终执行计划。

# job_select SRCDIR
#  Find all files having a dash or a hyphen in name
job_select()
{
  (cd "$1" && find . -type f -name '*[-_]*')
}

# job_strategy
#  Compute the renaming plan
#
# This assume that wrong names are deduced from good names by removing `_` and `-`.
# The output has three columns,
#
#   reldir|goodname|badname
#
# For instance, ./somedir/file_test.txt yields the plan
#
#   ./somedir|file_test.txt|filestest.txt
job_strategy()
{
  sed -e '
    s@/\([^/]*\)$/@|\1@
    h
    s@^.*|@@
    s@[-_]@@g
    x
    G
    s/\n/|/
  '
}

# job_process TGTDIR
{
   cd "$1" || exit
   IFS='|'
   while read reldir goodname badname; do
     relgoodname="$reldir/$goodname"
     relbadname="$reldir/$badname"
     if [ -r "$relbadname" ]; then
       printf 'Rename %s to %s\n' "$relbadname" "$relgoodname"
       mv "$relbadname" "$relgoodname"
     else
       printf 'Skip %s\n' "$relbadname"
     fi
   done
}

job_select /folder1 | job_strategy | job_process /folder2