如何在一系列逐渐编号的文件中创建下一个文件或文件夹?

发布于 2024-12-03 05:01:29 字数 1006 浏览 4 评论 0 原文

抱歉标题不好,但这是我能做的最好的了! :D

我有一个脚本,每次调用指定函数时都会创建一个新项目。

每个项目必须存储在其自己的文件夹中,并带有项目名称。但是,如果您不指定名称,脚本只会将其命名为“new projectX”,其中 X 是一个渐进数字。

随着时间的推移,用户可以重命名文件夹或删除一些文件夹,因此每次脚本运行时,它都会检查可用的最小数量(未被其他文件夹使用)并创建相关文件夹。

现在我设法制作了一个程序,我认为该程序可以按需要工作,但由于我对语言缺乏经验,我想听听您的意见是否可以,或者是否存在我无法发现的错误。

    while ( defined( $file = readdir $projects_dir ) )
    {
        # check for files whose name start with "new project"
        if ( $file =~ m/^new project/i )
        {
            push( @files, $file );
        }
    }

    # remove letters from filenames, only the number is left
    foreach $file ( @files )
    {
        $file =~ s/[a-z]//ig;
    }

    @files = sort { $a <=> $b } @files;

    # find the smallest number available
    my $smallest_number = 0;

    foreach $file ( @files )
    {
        if ( $smallest_number != $file )
        {
            last;
        }
        $smallest_number += 1;
    }

    print "Smallest number is $smallest_number";

Sorry for the bad title but this is the best I could do! :D

I have a script which creates a new project every time the specified function is called.

Each project must be stored in its own folder, with the name of the project. But, if you don't specify a name, the script will just name it "new projectX", where X is a progressive number.

With time the user could rename the folders or delete some, so every time the script runs, it checks for the smallest number available (not used by another folder) and creates the relevant folder.

Now I managed to make a program which I think works as wanted, but I would like to hear from you if it's OK or there's something wrong which I'm unable to spot, given my inexperience with the language.

    while ( defined( $file = readdir $projects_dir ) )
    {
        # check for files whose name start with "new project"
        if ( $file =~ m/^new project/i )
        {
            push( @files, $file );
        }
    }

    # remove letters from filenames, only the number is left
    foreach $file ( @files )
    {
        $file =~ s/[a-z]//ig;
    }

    @files = sort { $a <=> $b } @files;

    # find the smallest number available
    my $smallest_number = 0;

    foreach $file ( @files )
    {
        if ( $smallest_number != $file )
        {
            last;
        }
        $smallest_number += 1;
    }

    print "Smallest number is $smallest_number";

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

断念 2024-12-10 05:01:29

这是解决此类问题的基本方法:

sub next_available_dir {
    my $n = 1;
    my $d;
    $n ++ while -e ($d = "new project$n");
    return $d;
}

my $project_dir = next_available_dir();
mkdir $project_dir;

如果您愿意使用与 Perl 的 字符串自动递增功能,可以进一步简化代码,不再需要$n。例如,newproject000

Here's a basic approach for this sort of problem:

sub next_available_dir {
    my $n = 1;
    my $d;
    $n ++ while -e ($d = "new project$n");
    return $d;
}

my $project_dir = next_available_dir();
mkdir $project_dir;

If you're willing to use a naming pattern that plays nicely with Perl's string auto-increment feature, you can simplify the code further, eliminating the need for $n. For example, newproject000.

╰ゝ天使的微笑 2024-12-10 05:01:29

我想我会使用类似的东西:

use strict;
use warnings;

sub new_project_dir
{
    my($base) = @_;
    opendir(my $dh, $base) || die "Failed to open directory $base for reading";
    my $file;
    my @numbers;
    while ($file = readdir $dh)
    {
        $numbers[$1] = 1 if ($file =~ m/^new project(\d+)$/)
    }
    closedir($dh) || die "Failed to close directory $base";
    my $i;
    my $max = $#numbers;
    for ($i = 0; $i < $max; $i++)
    {
        next if (defined $numbers[$i]);
        # Directory did not exist when we scanned the directory
        # But maybe it was created since then!
        my $dir = "new project$i";
        next unless mkdir "$base/$dir";
        return $dir;
    }
    # All numbers from 0..$max were in use...so try adding new numbers...
    while ($i < $max + 100)
    {
        my $dir = "new project$i";
        $i++;
        next unless mkdir "$base/$dir";
        return $dir;
    }
    # Still failed - give in...
    die "Something is amiss - all directories 0..$i in use?";
}

测试代码:

my $basedir = "base";
mkdir $basedir unless -d $basedir;

for (my $j = 0; $j < 10; $j++)
{
    my $dir = new_project_dir($basedir);
    print "Create: $dir\n";
    if ($j % 3 == 2)
    {
        my $k = int($j / 2);
        my $o = "new project$k";
        rmdir "$basedir/$o";
        print "Remove: $o\n";
    }
}

I think I would use something like:

use strict;
use warnings;

sub new_project_dir
{
    my($base) = @_;
    opendir(my $dh, $base) || die "Failed to open directory $base for reading";
    my $file;
    my @numbers;
    while ($file = readdir $dh)
    {
        $numbers[$1] = 1 if ($file =~ m/^new project(\d+)$/)
    }
    closedir($dh) || die "Failed to close directory $base";
    my $i;
    my $max = $#numbers;
    for ($i = 0; $i < $max; $i++)
    {
        next if (defined $numbers[$i]);
        # Directory did not exist when we scanned the directory
        # But maybe it was created since then!
        my $dir = "new project$i";
        next unless mkdir "$base/$dir";
        return $dir;
    }
    # All numbers from 0..$max were in use...so try adding new numbers...
    while ($i < $max + 100)
    {
        my $dir = "new project$i";
        $i++;
        next unless mkdir "$base/$dir";
        return $dir;
    }
    # Still failed - give in...
    die "Something is amiss - all directories 0..$i in use?";
}

Test code:

my $basedir = "base";
mkdir $basedir unless -d $basedir;

for (my $j = 0; $j < 10; $j++)
{
    my $dir = new_project_dir($basedir);
    print "Create: $dir\n";
    if ($j % 3 == 2)
    {
        my $k = int($j / 2);
        my $o = "new project$k";
        rmdir "$basedir/$o";
        print "Remove: $o\n";
    }
}
晨光如昨 2024-12-10 05:01:29

试试这个:

#!/usr/bin/env perl

use strict;
use warnings;

# get the current list of files
# see `perldoc -f glob` for details.
my @files = glob( 'some/dir/new\\ project*' );

# set to first name, in case there are none others
my $next_file = 'new project1';

# check for others
if( @files ){

  # a Schwartian transform
  @files = map  { $_->[0]                                     }  # get original
           sort { $a->[1] <=> $b->[1]                         }  # sort by second field which are numbers
           map  { [ $_, do{ ( my $n = $_ ) =~ s/\D//g; $n } ] }  # create an anonymous array with original value and the second field nothing but digits
           @files;

  # last file name is the biggest
  $next_file = $files[-1];

  # add one to it
  $next_file =~ s/(.*)(\d+)$/$1.($2+1)/e;
}

print "next file: $next_file\n";

Try this:

#!/usr/bin/env perl

use strict;
use warnings;

# get the current list of files
# see `perldoc -f glob` for details.
my @files = glob( 'some/dir/new\\ project*' );

# set to first name, in case there are none others
my $next_file = 'new project1';

# check for others
if( @files ){

  # a Schwartian transform
  @files = map  { $_->[0]                                     }  # get original
           sort { $a->[1] <=> $b->[1]                         }  # sort by second field which are numbers
           map  { [ $_, do{ ( my $n = $_ ) =~ s/\D//g; $n } ] }  # create an anonymous array with original value and the second field nothing but digits
           @files;

  # last file name is the biggest
  $next_file = $files[-1];

  # add one to it
  $next_file =~ s/(.*)(\d+)$/$1.($2+1)/e;
}

print "next file: $next_file\n";
南七夏 2024-12-10 05:01:29

本身没有什么问题,但是要实现一个目标(获取目录的最小索引)需要编写大量代码。

一个核心模块、几个子模块和一些 Schwartzian 变换将使代码更加灵活:

use strict;
use warnings;
use List::Util 'min';

sub num { $_[0] =~ s|\D+||g } # 'new project4' -> '4', 'new1_project4' -> '14' (!)

sub min_index {

    my ( $dir, $filter ) = @_;

    $filter = qr/./ unless defined $filter; # match all if no filter specified

    opendir my $dirHandle, $dir or die $!;

    my $lowest_index = min                 # get the smallest ...
                        map  { num($_)   }  # ... numerical value ...
                         grep {    -d     }  # ... from all directories ...
                          grep { /$filter/ }  # ... that match the filter ...
                           readdir $dirHandle; # ... from the directory contents
    $lowest_index++ while grep { $lowest_index == num( $_ ) } readdir $dirhandle;
    return $lowest_index;
}

# Ready to use!

my $index = min_index ( 'some/dir' , qr/^new project/ );

my $new_project_name = "new project $index";

Nothing wrong per se, but that's an awful lot of code to achieve a single objective (get the minimum index of directories.

A core module, couple of subs and few Schwartzian transforms will make the code more flexible:

use strict;
use warnings;
use List::Util 'min';

sub num { $_[0] =~ s|\D+||g } # 'new project4' -> '4', 'new1_project4' -> '14' (!)

sub min_index {

    my ( $dir, $filter ) = @_;

    $filter = qr/./ unless defined $filter; # match all if no filter specified

    opendir my $dirHandle, $dir or die $!;

    my $lowest_index = min                 # get the smallest ...
                        map  { num($_)   }  # ... numerical value ...
                         grep {    -d     }  # ... from all directories ...
                          grep { /$filter/ }  # ... that match the filter ...
                           readdir $dirHandle; # ... from the directory contents
    $lowest_index++ while grep { $lowest_index == num( $_ ) } readdir $dirhandle;
    return $lowest_index;
}

# Ready to use!

my $index = min_index ( 'some/dir' , qr/^new project/ );

my $new_project_name = "new project $index";
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文