您的位置:首页 > 其它

Perl笔记:11、目录操作

2013-10-14 12:54 375 查看

在目录树中切换

程序运行时会以自己的工作目录作为相对路径的起点。可以使用chdir操作符来改变当前的工作目录,这和shell下的cd命令差不多:

chdir "/etc" or die "can't
chdir to /etc:$!";


注意这里我用到了$!变量,由于这是对操作系统的调用,所以发生错误时便会设定标量标量$!的值。如果chdir的返回为假,则表示有问题发生,这时通常需要检查一下$!变量的内容。

如果chdir省略参数则跳到当前的目录,这实际上是没有什么意义的。

文件名通配

一般来说shell会将命令行里的文件名模式展开成所有匹配的文件名。这称之为文件名通配。如,假设将*.pm这个文件名模式交给echo命令,shell会将它展开成名成相匹配的文件列表:

$
echo
*.pm

barney.pm dino.pm fred.pm wilma.pm

这里的echo命令不必知道该如何展开*.pm,因为shell会将它展开,再交给echo处理,这也同样适合于perl程序:

#!/usr/bin/perl
-w

use
strict;

foreach (@ARGV) {

print "one
arg is $_\n";

}

$ perl show-args *.txt

one arg is file.txt

one arg is letter.txt

在这里我上文的程序并不了解如何进行文件通配的处理,放在@ARGV里的已经是展开好了的名称。

有些时候在程序内部,也可能会想要用*.txt之类的模式。我们可以使用glob操作符将它展开成相匹配的文件名:

my
@all_files
=
glob "*";

my @txt_files = glob "*.txt";


--其中@all_files会取得当前目录中的所有文件,并按字母顺序排序,但不包含以点号开头的文件。@txt_files得到所有以.txt结尾的文件。

下面是一次匹配多个模式的例子:

my
@all_files_including_dot
=
glob ".*
*";


--其中".*"代表以点开头的文件名,另外注意引号之内两个模式中间的空格是有意的,它分隔了两个要进行文件名通配处理的条目。

文件通配符的另外一种写法

除了上面介绍的glob操作符之外我们可以使用一种简单的方式在perl使用文件通配符,那就是"尖括号写法"(<>):

my @all_files = <*>

# 与 my @my_files =
glob "*" 一样

my $dir =
"/etc";

my @dir_files = <$dir/*
$dir/.*>;

#
$dir变量也会替换为相应的内容

注意:尖括号在perl中即代表了从文件句柄读取,又代表了文件名通配操作,那Perl是如何决定是哪一种的呢?因为合理的文件句柄必须是严格意义上的Perl标识符,所以如果尖括号满足Perl标识符条件的,就作为文件句柄来读取,否则它代表的iushi文件名通配操作。举例来说:

my @files = <FRED/*>; ## glob

my @lines = <FRED>;
##
从文件句柄读取

my $name =
"FRED";

my @files = <$name/*>; ## glob

my @lines = <$name>; ##
对句柄FRED进行间接文件句柄读取

目录句柄

若要从目录中取得文件名列表,那就要用到目录句柄,它和文件句柄类似,可以使用opendir打开,readdir读取,closedir关闭,只不多读取的时候是目中的文件名而不是文件的内容,如下例子:

readdir.pl

#!/usr/bin/perl
-w

use
strict;

my $dir_to_process = "/etc";

opendir DH, $dir_to_process or die "Cannot open $dir_to_process:
$!";

foreach my $file (readdir DH) {

print "one
file in $dir_to_process is $file\n";

}

closedir DH;

运行:perl readdir.pl

one file in /etc is .

one file in /etc is ..

one file in /etc is bashrc

one file in /etc is auto.misc

one file in /etc is firmware

one file in /etc is libaudit.conf

...

one file in /etc is netplug.d

--和文件句柄一样,目录句柄会在程序结束或再用这个句柄打开另一个目录前自动关闭。上面的例子中将.
和..文件都输出了,我现在不想显示这些文件,只想显示*.conf的文件,且按照字母顺序排序,那将如何修改之前的程序呢:

readdir_2.pl

#!/usr/bin/perl
-w

use
strict;

my @file;

my $dir_to_process = "/etc";

opendir DH, $dir_to_process or die "Cannot open $dir_to_process:
$!";

foreach my $file (readdir DH) {

next if $file =~ /^\./;

next unless $file =~ /\.conf$/;

push @file,"$dir_to_process/$file\n";

}

print sort @file;

closedir DH;

--这样输出的文件是按照字母顺序且都是.conf的文件

删除文件

使用unlink操作符删除文件:

unlink "slate", "bedrock", "lava";


既然unlink的参数是列表,glob函数又恰好返回列表,我们融合两者可以一次删除多个文件:

unlink glob "*.o";


unlink的返回值是成功删除了多少个文件,下面的例子可以检查unlink是否执行成功:

my $successful = unlink "slate", "bedrock", "lava";

print "I
deleted $successful file(s) just now\n";

重命名文件

使用rename函数来重命名文件,写法: rename
"old","new";

下面的例子是将所有的.old文件重命名为.new

rename.pl

foreach my $file (glob "*.old") {

my $newfile = $file;

$newfile =~ s/\.old$/.new/;

if (-e
$newfile) {

warn "can't rename $file to $newfile: $newfile
exists\n";

} elsif (rename $file,
$newfile) {

##
改名成功,什么都不做

} else {

warn "rename $file to $newfile failed: $!\n";

--此程序会先检查$newfile是否村咋,因为只要用户有删除目标文件的权限rename就会毫不忧郁的覆盖现有的文件。加上这项敬爱奶茶可以减低损失数据的几率

建立和删除目录

mkdir
DIRNAME,MASK

mkdir执行后成功返回true失败返回false并设置$!的内容。

[ccie lang="perl"]mkdir "fred", 0755 or warn "Cannot make fred
directory: $!";[/cce]

注意:MASK最好不要用变量的形式指定,否则perl会认为这个变量时十进制的数字,而非mkdir认为的八进制,因此,在指定MASK最好使用数字,或者用oct函数转换一下变量,如下:

my $name =
"fred";

my $permissions = "0755";

mkdir $name,
oct($permissions);

修改权限

chmod 0755, "fred", "barney";

chmod函数与shell下的命令是一致的

更改属主

my $user =
1004;

my $group = 100;

chown $user,
$group, glob "*.o";

--如果要处理的不是数字,而是像apache这样的字符串该如何处理呢?很简单,使用getpwnam与getgrnam函数来把用户名或组名转成数字即可,如下:

defined(my
$user = getpwnam "merlyn") or
die "bad
user";

defined(my
$group = getgrnam "users") or
die "bad
group";

chown $user,
$group, glob "/home/merlyn/*";

--这里我们使用了defined函数来确认返回值不是undef,也就是说验证指定的用户或组是否真的存在。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: