在目录树中移动:
程序运行时会以自己的工作目录作为相对路径的起点,也就是说,当我们提及fred这个文件时,其实指的是"当前工作目录下的fred"
chdir '/etc' or die "Cannot chdir to /etc: $!";
如果掉用chdir时不加参数,perl会猜想你要回到自己的用户主目录并试着将工作目录设成主目录
chdir后面跟路径不能是以~开头的
文件名通配:
文件名通配(glob)
echo *.pl 会输出当前文件下所有.pl文件,没有.pl文件的话,就输出*.pl
下面程序只是简单输出所有命令行参数:
foreach $arg (@ARGV)
{
print "one arg is $arg\n";
}
用的时候,perl ex13_1.pl *.pl
输出:
one arg is ex12_1.pl
one arg is ex12_test.pl
one arg is ex13_1.pl
one arg is ex13_test.pl
one arg is ex5_1.pl
one arg is ex5_test.pl
one arg is ex6_1.pl
one arg is ex6_test.pl
glob操作符
my @all_files = glob '*'; #文件名按字母排序
my @pm_files = glob '*.pm';
文件名通配的另一种语法:
my @all_files = <*>; #效果和这样的写法完全一致:my @all_files = glob '*';
my @dir_files = <$dir/* $dir/.*>;
my @files = <FRED/*>; #文件名通配操作
my @lines = <FRED>; #从文件句柄读取
my @lines = <$fred>; #从文件句柄读取
my $name = 'FRED';
my @files = <$name>; #文件名通配操作
readline:
my $name = 'FRED';
my @lines = readline FRED; #从FRED读取
my @lines = readline $name; #从FRED读取
目录句柄:
my $dir_to_process = '/etc';
opendir my $dh, $dir_to_process or die "Cannot open $dir_to_process: $!";
foreach $file (readdir $dh)
{
print "One file in $dir_to_process if $file\n";
}
closedir $dh;
也可以是裸字作为文件句柄,如DIR
目录句柄遍历文件时把.,..,.xx.xx也匹配了进来,所以处理时要避开这些不合要求的文件,
跳过.开头的文件;
next if $name =~ /^\./;
去除.和..;
next if $name eq '.' or $name eq '..';
open my $somedir, $dirname or die "Cannot open $dirname: $!";
while(my $name = readdir $somedir)
{
next if $name =~ /^\./; #跳过名称以点开头的文件
$name = "$dirname/$name"; #拼合为完整的路径
next unless -f $name and -r $name; #只需要可读的文件
}
为了让程序更具有可移植性,可以用File::Spec::Functions模块构造用于本地系统的合适文件名:
use File::Spec::Functions;
opendir my $somedir, $dirname or die "Cannot open $dirname: $!";
while(my $name = readdir $somedir)
{
next if $name =~ /^\./;
$name = catfile($dirname, $name);
next unless -f $name and -r $name;
}
若是没有接上路径,文件测试操作符会在当前目录下查找文件,而不是在$dirname制定的目录下,这是使用目录句柄时最常犯的错误。
递归访问目录:
CPAN上的File::Find::Rule和File::Finder,都在File::Fine基础上的,提供了更为直观,易用的用户界面
文件和目录的操作:
删除文件:
unlink操作符,指定要删除的文件列表
unlink 'slate', 'bedrock', 'lava'; #这会把三个文件放进粉碎机,从此消失在系统中。
unlink glob '*.o'; #glob得到一个列表,unlink删除一个列表
unlink的返回值是代表成功删除的文件数目。
my $successful = unlink "slate", "bedrock", "lava";
print "I deleted $successful file(s) just down\n";
foreach my $file (qw(slate bedrock lava))
{
unlink $file or warn "failed on $file: $!\n";
}
重命名文件:
rename 'old', 'new';
rename 'over_there/some/place/some_file' => 'some_file';
和大部分调用操作系统功能的函数一样,rename执行失败时返回假,并将操作系统返回的错误信息存到$!里,从而让你可以用ordie或orwarn来向用户汇报问题。
批量将.old结尾的文件名改为以.new结尾:
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";
}
}
链接与文件:
mounted volume
link 'chicked', 'egg'
or warn "Can't link chicked to egg: $!";
软链接:
symlink 'dodgson', 'carroll'
or warn "Can't symlink dodgson to carroll: $!";
要取得符号链接指向的位置,请使用readlink函数,他会返回符号链接指向的位置,如果参数不是符号链接,则返回undef:
my $where = readlink 'carrol'; #得到'dodgson'
my $perl = readlink '/usr/local/bin/perl'; #告诉你实际的perl程序究竟躲在何处
这两种链接都可以用ulink移除,你现在该了解它取这个名字的含义,unlink只是从目录里移除该文件名的链接条目,并将它的链接数递减,必要时再释放inode
创建和删除目录:
要在现有的目录下创建目录是件容易的事,只需调用mkdir函数即可:
mkdir 'fred', 0755 or warn "Cannot make fred directory: $!";
mkdir $name, oct($permissions);
my ($name, $perm) = @ARGV;
mkdir $name, oct($perm) or die "Cannot create $name: $!";
删除目录:
my $temp_dir = "/tmp/scratch_$$";
mkdir $temp_dir, 0700 or die "Cannot create $temp_dir: $!";
#将临时目录$temp_dir作为所有临时文件存放的场所
...
unlink glob "$temp_dir/* $temp_dir/.*"; #先删除文件夹中的内容
rmdir $temp_dir; #再删除文件夹
$$:pid存在$$中
如果我们在临时目录里创建了子目录,那么unlink操作符在处理它们时将会失败,rmdir也会跟着失败,请参考perl自带的File::Path模块,里面的rmtree函数提供了比较完整的解决方案。
如果你去确实想要创建一个临时文件或目录,可以用perl自带的File::Temp模块
修改权限:
chmod 0755, 'fred', 'barney';
和许多其他操作系统接口函数一样,chmod会返回成功更改的条目的数量,哪怕只有一个参数,它也会在失败时将$!设成合力的错误信息,第一个参数代表Unix的权限值,unix的chmod命令能接受用符号表示的权限(例如+x或go=u-w),但是chmod函数并不接受这类参数。
修改隶属关系:
只要操作系统允许,你可以用chown函数修改一系列文件的拥有者以及其所属组,拥有者和所属组会被同时更改,并且在指定时必须给出数字形式的用户标示符及组标示符。
my $user = 1004;
my $group = 100;
chown $user, $group, glob '*.o';
如果要处理的不是数字,而是像merlyn这样的字符串呢?只要用getpwnam函数将用户名转换成用户编号,再用相应的getgrnam函数把用户名转换成组编号:
defined(my $user = getpwnam 'merlyn') or die 'bad user';
defined(my $grpup = getgrnam 'users') or die 'bad group';
chown $user, $group, glob '/home/merlyn/*';
成功操作后,chown函数会返回受影响的文件数量,在错误发生时会在$!中设定出错信息。
修改时间戳:
用utime函数来修改,它的前两个阐述是新的访问时间和更改时间,其余参数就是要修改时间戳的文件名列表,时间格式采用的是内部时间戳的格式(stat和lstat函数返回值类型)
my $now = time;
my $ago = $now - 24 * 60 * 60; #一天的秒数
utime $now, $ago, $glob '*'; #将最后访问时间改为当前时间,最后修改时间改为一天前
简单练习:
#!/usr/bin/perl -w
use strict;
#use autodie;
#use File::HomeDir; #第三方模块,不管在什么操作系统上都能进入指定用户的主目录
system 'ls';
chdir '/Users/it-0003005';
=pod
eval
{
chdir '~/';
}; #这里有分号,eval里面的程序发生fatal error 但是并不会结束程序,还会继续执行下去
=cut
print "+++++++++++++++++++++++++++++++++++++++++++++++\n";
system 'ls';
print "+++++++++++++++++++++++++++++++++++++++++++++++\n";
foreach my $arg (@ARGV)
{
print "one arg is $arg\n";
}
print "+++++++++++++++++++++++++++++++++++++++++++++++\n";
my @allFiles = glob '*'; #取出的文件文件并没有\n
foreach my $value (@allFiles)
{
print $value, "\n";
}
&search_file('/Users', '.+\.py$');
sub search_file
{
my ($dir, $partInfo) = @_;
#print $partInfo, "\n";
opendir my $dh, $dir or die "Cannot open dir $dir\n";
my @files = readdir $dh; #标量上下文和列表上下文
foreach my $file (@files)
{
my $filePath = "$dir/$file";
if(($file =~ m#$partInfo#i) and (-f $filePath))
{
print "$filePath\n";
}
if((-d $filePath) and ($file ne '.') and ($file ne '..'))
{
&search_file($filePath, $partInfo);
}
}
}