注意,這些操做的對象是文件名(相對路徑/絕對路徑),而非文件/目錄句柄,句柄只是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。