Perl脚本,使前8个字符全部大写,但不是整个文件名

Perl脚本,使前8个字符全部大写,但不是整个文件名,perl,file,rename,Perl,File,Rename,我应该使用什么Perl脚本只将文件名中的前8个字符更改为all caps,而不是将整个文件名更改为all caps 下面是我如何设置它的: #!/usr/bin/perl chdir "directory path"; #@files = `ls *mw`; @files = `ls | grep mw`; chomp @files; foreach $oldname (@files) { $newname = $oldname; $newname =~ s/mw//; prin

我应该使用什么Perl脚本只将文件名中的前8个字符更改为all caps,而不是将整个文件名更改为all caps


下面是我如何设置它的:

#!/usr/bin/perl

chdir "directory path";
#@files = `ls *mw`;
@files = `ls | grep mw`;
chomp @files;

foreach $oldname (@files) {
  $newname = $oldname;
  $newname =~ s/mw//;
  print "$oldname -> $newname\n";
  rename("$oldname","$newname");
}

您可以使用此正则表达式:

my $str = 'Hello World!';
$str =~ s/^(.{8})/uc($1)/se; # $str now contains 'HELLO WOrld!'
那么:

#!/usr/bin/perl
use strict;
use warnings;
use File::Copy;

chdir'/path/to/directory';
# Find all files that contain 'mw'
my @files = glob("*mw*");

foreach my $file(@files) {
    # skip directories
    next if -d $file;
    # remve 'mw' from the filename
    (my $FILE = $file) =~ s/mw//;
    # Change filename to uppercase even if the length is <= 8 char
    $FILE =~ s/^(.{1,8})/uc $1/se;
    move($file, $FILE);
}
#/usr/bin/perl
严格使用;
使用警告;
使用文件::复制;
chdir'/path/to/directory';
#查找包含“mw”的所有文件
my@files=glob(“*mw*”);
foreach my$文件(@files){
#跳过目录
下一个if-d$文件;
#从文件名中删除“mw”
(my$FILE=$FILE)=~s/mw/;
#将文件名更改为大写,即使长度始终为“检查系统调用的返回值”!
当您调用OS服务时,应该始终检查返回值

chdir EXPR

chdir文件句柄

chdir DIRHANDLE

chdir

如果可能,将工作目录更改为EXPR。如果省略EXPR,则更改为
$ENV{HOME}
指定的目录(如果已设置);如果未设置,则更改为
$ENV{LOGDIR}
指定的目录(在VMS下,还将检查变量
$ENV{SYS$LOGIN}
)如果两者都未设置,
chdir
不执行任何操作。成功时返回true,否则返回false。参见die下的示例

在支持fchdir(2)的系统上,可以传递文件句柄或目录句柄作为参数。在不支持fchdir(2)的系统上,传递句柄会引发异常

正如您在问题中所写,您的代码丢弃了重要信息:系统调用
chdir
rename
成功还是失败

提供有用的错误消息 在Perl中检查返回值的常用习惯用法的一个例子是

chdir $path or die "$0: chdir $path: $!";
错误消息包含三个重要信息位:

  • 发出错误的程序
  • 在本例中,它试图做什么,
    chdir
  • 为什么失败,
另请注意,如果错误消息未以换行符结尾,则
die
还将显示程序控制所在的文件名和行号。当
chdir
失败时,标准错误类似于

./myprogram: chdir: No such file or directory at ./myprogram line 3. 要使
重命名
有希望,您必须保留
$oldname
的值,因此,上面的代码立即将其复制到
$newname
,并开始更改副本而不是原始副本。您将看到

($new = $old) =~ s/.../.../;  # or /.../
在Perl代码中,因此它也是一个需要理解的重要习惯用法

定义用于字符串和正则表达式替换的方便转义序列:

\l
下一个字符仅小写
\u
titlecase(非大写!)仅下一个字符
\L
将所有字符小写,直到看到为止
\U
看到之前所有字符的大写字母
\Q
引用非单词字符直到\E
\E
结束案例修改或引用部分(以最后看到的为准)

上面的代码获取前八个字符(如果
$newname
长度较短,则不超过八个字符),并将其替换为大写的对应字符

示例输出 请参阅正在运行的代码:

$ ls directory\ path/ defmwghijk mwabc nochange qrstuvwxyzmw $ ./prog $ ls directory\ path/ ABC DEFGHIJK QRSTUVWXyz nochange $ls目录\路径/ defmwghijk mwabc nochange qrstuvwxyzmw 美元/进度 $ls目录\路径/ ABC-DEFGHIJK-qrstuvxyz-nochange

s/^(.{1,8})/\U$1/
将字符串的前八个字符设置为大写

use strict;
use warnings;

chdir "directory path" or die "Unable to change current directory: $!";

opendir my $dh, '.' or die $!;
my @files = grep -f && /mw/, readdir $dh;

foreach my $file (@files) {
  (my $new = $file) =~ s/mw//;
  $new =~ s/^(.{1,8})/\U$1/s;
  print "$file -> $new\n";
  rename $file, $new;
}

我想您的要求比您告诉我们的更多,例如文件扩展名的大写部分不匹配。我将匹配前八个字符,而不是匹配前八个字母:

其他一些注意事项:

  • 您可以直接在Perl中进行全局编译,不需要
    ls
  • 看起来你正在剥离mv,所以我就这么做了。如果这不是你想要的,很容易改变

取代正则表达式,将可使用的4参数形式的前八个字符大写。这提供了原位替换

my $old = q(abcdefghij);
my $new = $old;
substr( $new, 0, 8, substr( uc($old), 0, 8 ) );
print "$old\n$new\n";

abcdefghij
ABCDEFGHij

使用
rename
File::Copy::move
(如M42所示)执行实际重命名。

下面是我如何设置它的#!/usr/bin/perl chdir“目录路径”;#@files=
ls*mw
;files=
ls | grep mw
;chomp@files;foreach$oldname(@files){$newname=$oldname;$newname=~s/mw/;print“$oldname->$newname\n”重命名($oldname“,“$newname”);}#!/usr/bin/perl chdir“目录”;对于每个我的$file(@files){#将文件名更改为大写,即使长度<8 char$file=~s/^.{1,8}/uc和/e;move($file,$file);}从效率和安全角度来看,我不确定这是否正确格式化。最好尽可能避免使用经过计算的替换。此外,如果文件名少于8个字符,则代码不会将任何内容设置为大写。
s/(^.{1,8})/\U$1/
很好用。@Borodin,你把/e和
eval EXPR
混淆了
s///e
实际上更像
do BLOCK
s///e
绝对没有安全问题,另一方面,它相当于
s///eval/e
,而且它是有问题的。@Borodinr估算效率效益。
s//\U$1//
s//uc$1)/e
都是在编译s///时编译的(而不是在运行时),两者都打电话给
uc
。这里有答案吗?@Borodin谢谢你的反馈。请建议我如何让我的答案更有帮助。OP自我描述为Perl的新手,所以我提供了额外的上下文。决定要包含多少背景信息是一个艰难的决定
use v5.14;
use utf8;

chdir "/Users/brian/test/";
my @files = glob( 'mw*' );

foreach my $old (@files) {
    my $new = $old =~ s/\Amw(\pL{1,8})/\U$1/ir;
    print "$old → $new\n";
    }
my $old = q(abcdefghij);
my $new = $old;
substr( $new, 0, 8, substr( uc($old), 0, 8 ) );
print "$old\n$new\n";

abcdefghij
ABCDEFGHij