注意,这些操做的对象是文件名(相对路径/绝对路径),而非文件/目录句柄,句柄只是perl和文件系统中文件的关联通道,而非实体对象。html
在unix类操做系统中有一个touch命令能够很是方便的建立文件,还能批量建立一些名称规律的文件。但实际上touch的主要介绍中倒是"修改文件时间戳",建立文件只不过是它的辅助能力。若是没有touch命令,如何在shell环境下建立文件?最佳方式是经过重定向的方式。node
在perl中没有touch相似的功能,因此原始地只能经过open打开输出类的文件句柄和输出操做来建立文件(同时也能够写入数据)。shell
open FH,">>/tmp/cc.log"; print FH; # 建立空文件 close FH;
若是想批量建立命名规范的文件,能够将建立操做放进循环中进行迭代。例如建立cc{1..10}.log
这10个文件:数组
foreach (1..10){ open FH,">cc${_}.log"; print FH; close FH; }
固然,perl能够经过system或反引号或exec来和shell进行交互。例如:函数
`touch dd{1..10}.log`;
可是若是想要批量建立的文件不能用一个touch(或少数几个)来建立的话,仍是建议采用perl的建立方式,由于每次和shell交互touch都fork一次perl进程并解析执行shell语句,文件数量多时,这样的效率很通常。不过毕竟不太可能用到这种情形。工具
在unix系统里,使用rm删除文件/目录,但它内部调用的是unlink函数。ui
在perl中删除文件使用perl自带的unlink函数,它也会调用操做系统的unlink函数来删除文件。它能够接一个文件元素,也能够接一个列表,或者说它的参数上下文就是列表。操作系统
可是注意,unlink没法删除目录,要删除目录,见下文。unix
unlink @lotfiles; # 删除数组中的文件 unlink 'cc.log'; # 删除单个文件 unlink 'cc1.log','cc2.log'; # 删除文件列表 unlink qw(cc3.log cc4.log); # 删除文件列表 unlink glob dd*.log; # 通配文件名删除
关于文件名通配详细内容,见后文。code
须要注意,unlink有返回值,返回的是成功删除的文件数量。
因此,unlink删除3个文件时,若是它的返回值为3,表示全删除成功了,若是返回值为0表示一个都没删除,但若是返回的是1或者2,咱们就没法判断哪些文件删除成功,哪些文件删除失败。这时须要在循环中一个一个文件地迭代删除操做,并给出错误提示。
`touch dd{1..10}.log`; foreach (1..10){ unlink "dd${_}.log" and ++$count # 注意,++放在变量的前面 or warn "Can't remove file dd${_}.log: $!"; } print "removed $count files\n";
注意上面的and语句中,自增++$count
的自增符号放在变量的前面,若是放在后面,会由于初始化$count为0,$count++
表达式返回的值为0(但$count加完后返回1)而执行or语句。也就是说,删除第一个文件dd1.log时也会报告警告信息。
$!
mkdir -p
的功能),能够使用File::Path里的make_path函数或mkpath函数,他们等价例如,建立一个目录
mkdir "/tmp/test1"; mkdir; # 等价于mkdir "$_" mkdir "/tmp/test2",0755 # 权限不能加引号包围,它是8进制数值 or die "Can't create directory: $!";
若是是使用变量传递权限位,应当使用oct()函数来保护它做为8进制数。
$perm="0755"; mkdir "/tmp/test3",oct($perm);
mkdir函数没法递归建立目录。也就是说,当要建立的目录的上级目录不存在时,mkdir函数将失败。若是想递归建立目录,可以使用File::Path里的make_path函数或mkpath函数,他们是等价的。
这个函数的语法是:
make_path(dir1,dir2,...,{opts}) opts能够是如下几种: mask => NUM # mask和mode是同义词,NUM指定八进制权限值, mode => NUM # 这种方式指定权限值受umask影响,若目录已存在,则不修改 chmod => NUM # 直接赋予必定权限值,不受umask影响,若目录已存在,则不修改 verbose => $bool # 是否输出详细信息,默认啥也不输出 error => \$err owner => $owner # 这3条都表示为建立的目录设置全部者,若是已存在,则不设置 user => $user # 能够使用username,也能够使用uid,但若是username没法 uid => $uid # 映射为uid,或者uid不存在,或者无权限的时候,将报错 group => $group # 设置所属组,处理方式和上面全部者的处理方式同样
use File::Path qw(make_path); make_path "/test/foo/bar"; # 一次性建立3级目录 make_path "/test/foo1/bar1",{ chmod => 0777, verbose => 1 }
固然,和shell交互来建立目录也很是方便:
`mkdir -p /test/a/b/c`;
例如,删除一个目录
rmdir "/tmp/test";
由于rmdir没法删除非空目录,因此要删除非空目录,能够采用File::Path模块的rmtree函数。
rmtree的语法:
rmtree($dir1, $dir2,..., \%opt) opts能够是如下几种: verbose => $bool # 是否显示删除信息,默认啥也不显示 safe => $bool # 删除时,跳过没法删除的对象。例如虚拟文件系统(VMS,如/proc)下有不少是没法删除的 keep_root => $bool # 设置为真值时,保留顶级目录,也就是说自删除目录内的文件和子目录,顶级目录自身不删除 result => \$res error => \$err
use File::Path qw(rmtree); rmtree '/test/foo1',{verbose => 1};
因为perl没法向shell同样能够直接使用"*"通配,因此若是想删除目录内的文件和子目录,而保留foo1目录自身,应该设置keep_root选项,而不是用/test/foo1/*
的方式来删除:
rmtree '/test/foo1',{verbose => 1,keep_root => 1};
实在想通配删除,能够使用glob来通配,关于通配,见后文:
rmtree((glob '/test/foo1/*'),{verbose => 1});
另外一种保留目录自身的删除方式是遍历顶级目录,而后迭代删除遍历出来的每一个子项:
foreach (</test/foo1/*>){ # 括号内等价于 glob "/test/foo1/*" -d $_ ? rmtree $_ : unlink $_; }
图方便的话,直接和shell交互也很是方便。
`rm -rf /test/foo1/*`;
$!
~
来表示家目录chdir /tmp or die "Can't change dir to /tmp: $!";
perl没有内置函数能够直接获取当前工做目录,但Cwd
模块和更通用的File::Spec
模块都提供了相关工具获取当前路径。
例如,Cwd模块:
use Cwd(getcwd,cwd); print getcwd(); print cwd();
cwd()比getcwd()要更可移植,它和pwd命令基本一致。注意,cwd()会移除尾随斜线。
$!
例如,设置目录、文件的权限:
chmod 0700,qw(/test/foo /test/foo1/a.log); chmod 0700,'/test/foo','/test/foo1/a.log';
$!
chown 1001,1001,glob '*.log'; # 第一个1001是user位,第二个1001是group位 chown -1,1002,'a.log'; # uid不变
若是想按照用户名、组名来设置,使用getpwnam和getgrnam函数:
defined(my $user = getpwnam 'longshuai') or die "bad user"; defined(my $group = getgrnam 'longshuai') or die 'bad group'; chown $user,$group,glob '*.log';
关于文件的时间戳属性,这里简单说明下,若是须要详细了解,参看:http://www.cnblogs.com/f-ck-need-u/p/6995195.html#blog1.3
在unix系统中,要求操做系统维护atime/mtime/ctime三种文件的时间戳属性:
unix的touch命令能够修改atime和mtime,ctime是操做系统自身维护的,没法经过上层命令工具直接修改。
Perl的utime函数也能够修改文件时间戳,语法以下:
utime(Atime,Mtime,FILE_LIST)
$!
例如,下面修改一堆文件的atime为当前时间,mtime为前一小时时间:
$atime=time; $mtime=$atime - 60*60; utime $atime,$mtime,glob '*.log';
实现touch文件的等同功能:将文件时间戳设置为当前时间:
utime undef,undef,'a.txt' or die "touch file failed: $!";
若是只想修改atime,不想修改mtime,则使用stat函数先将当前的mtime属性值取出保存下来:
$mtime = (stat('a.txt'))[9]; utime time,$mtime,'a.txt' or die "touch failed: $!";
其中stat()[9]对应的属性是mtime,stat()[8]对应的属性是atime。