SOURCE HTML: http://socvista.com/bbs/redirect.php?fid=71&tid=932&goto=nextnewset
2008.08.25 PERL 第12章 目录操作
== 游历目录树
我们的程序带有一个默认的working directory,他是所有相对路径的参考点。
如果我们寻找一个文件“kobe”,那就意味着是“工作目录下的kobe文件”。
使用chdir可以改变工作目录。比如:
chdir "/etc" or die "can not chdir to /etc: $!";
由于chdir是一个系统请求,如果产生错误,$!会显示perl从系统处接收到的错误信息。
所有perl启动的进程都会继承这个工作目录。
如果没有指定的话,可能perl会将我们的home目录作为默认的工作目录。
== globbing
什么叫globbing? 比如
$ echo *.pm
a.pm b.pm c.pm
$
这种根据文件名pattern寻找文件并将名称扩展显示的功能就叫globbing。
== shell 提供了globbing功能
globbing功能是shell提供的,perl无需知道就可以直接使用。比如一个命令
$ perl show-args *.pm
执行结果是
one arg is a.pm
one arg is b.pm
one arg is c.pm
这个结果是怎么产生的呢?我们来看perl程序show-args
foreach $arg (@ARGV) {
print "one arg is $arg\n";
}
== 显式使用globbing功能
上面的例子中,我们只是提供了pattern参数。然后perl就自动调用了shell来globbing。虽然好,但是不是那么直观。那么如何显式调用这个功能呢?
my @all_files = glob "*"; # 不包括用点号开始的文件,其余的文件都包括,而且按照字母顺序排序。
my @pm_files = glob "*.pm";
my @all_files_inc_dot = glob ".* *"; # 包括所有文件
== globbing 的另一种写法<*>
用<>符号也可以完成globbing功能。看例子
my @all_files = <*>; # glob "*" 一样
再看一个例子。
my $dir = "/etc";
my @dir_files = <$dir/* $dir/.*>; # 和glob "* .*"一样
== 如何判断<>是一个glob还是一个file handle
如果<>中的内容是一个identifier,那么这就是一个file handle read。否则就是一个glob。比如
my @files = <FRED>; #一个filehandle read
my @files = <FRED/*>; # 一个glob
== 如何明确指定一个 filehandle read
方法:使用readline。
1. my @lines = readline FRED;
2. my @lines = readline $name;
== 用perl实现glob的方法:Directory handle
directory handle 和 file handle 有一些类似的地方,比如:
opendir - - open
readdir - - readline
closedir - - close
== 用dir handle实现 glob 的典型案例
我们来看一个例子,这个例子和 glob "* .*" 等效。
opendir DH, "/etc"
or die "Can not open /etc : $!";
foreach $file (readdir DH) {
print "$file \n";
}
我们来看一个例子,这个例子和 glob "*.pm" 等效。
while ($name = readdir DIR) {
next unless $name =~ /\.pm$/;
... more processing ...
}
我们来看一个例子,这个例子和 glob "*" 等效。
next if $name =~ /~\./;
我们来看一个例子,这个例子跳过那两个特殊文件。
next if $name eq "." or $name eq "..";
== readdir 只能获得local path
所以如果要获得全局路径要这样做。
opendir DIR, $dirname or die "Cannot open $dirname: $! \n";
while (my $name = readdir DIR) {
$name = "$dirname/$name";
... more processing ...
}
== 目录的recursive遍历
可能最初的时候用不着这个功能。但是我们必须知道 Perl 提供了一个库的调用,叫做 File::Find,他能让你使用 recursive directory processing。实践证明,很多人会经常用到这个功能。
== 删除文件
unlink "filea", "fileb", "filec";
== 删除一个模式的多个文件
unlink glob "*.o";
== 确认删除的文件数目
my $del_no = unlink glob "*.o"; # 返回值就是删除的文件数
== 逐个删除文件并获取出错信息
foreach my $file (qw(filea fileb filec)) {
unlink $file or warn "delete $file failed: $! \n"
}
== 文件重命名
rename "old", "new";
== 文件移动(重命名的扩展)
rename "dir1/dir11/dir111/some_file", "some_file"; # 将文件移动到当前目录下
== 一个好用的重命名程序
foreach my $file (glob "*.old") {
(my $newfile = $file) =~ s/\.old$/.new/;
if (-e $newfile) {
warn "...exist!";
} elsif (rename $file, $newfile) {
# success,
} else {
warn "rename failed: $! \n";
}
}
== 创建目录
mkdir "kobe", 0755 or warn "...";
== 目录权限必须显式声明是8进制
$permissions = "0755";
mkdir $name, oct($permissions);
建议尽量显式声明。
== 删除空目录
rmdir glob "fred/*"; # 删除所有fred下的空目录
rmdir $dir;
== 删除非空目录(无子目录)
unlink glob "$temp/* $temp/.*"; # 先删除内部文件,使目录为空
rmdir $temp;
== 删除非空目录(无子目录)
使用 File:Path 提供的 rmtree 函数。
== 修改权限
chmod 0755, "file-a", "file-b";
== 修改所有权(利用ID)
my $user = 1004; # user ID
my $group = 100; # group ID
chown $user, $group, glob "*.o";
== 修改所有权(利用name)
defined(my $user = getpwnam "merlyn") or die "no such user";
defined(my $group = getgrnam "users") or die "no such group";
chown $user, $group, glob "*.o";
== 修改 timestamp
my $now = time;
my $ago = $now - 24*60*60;
utime $now, $ago, glob "* .*";