Perl文件、目錄常用操作
註意,這些操作的對象是文件名(相對路徑/絕對路徑),而非文件/目錄句柄,句柄只是perl和文件系統中文件的關聯通道,而非實體對象。
創建文件
在unix類操作系統中有一個touch命令可以非常方便的創建文件,還能批量創建一些名稱規律的文件。但實際上touch的主要介紹中卻是"修改文件時間戳",創建文件只不過是它的輔助能力。如果沒有touch命令,如何在shell環境下創建文件?最佳方式是通過重定向的方式。
在perl中沒有touch類似的功能,所以原始地只能通過open打開輸出類的文件句柄和輸出操作來創建文件(同時也可以寫入數據)。
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進行交互。不過這樣的效率畢竟一般,每次交互都fork進程並解析執行shell語句。例如:
`touch dd{1..10}.log`;
但是如果想要批量創建的文件不能用一個touch(或少數幾個)來創建的話,還是建議采用perl的創建方式,因為每次和shell交互touch都fork一次perl進程並解析執行shell語句,文件數量多時,這樣的效率很一般。不過畢竟不太可能用到這種情形。
刪除文件
在unix系統裏,使用rm刪除文件/目錄,但它內部調用的是unlink函數。
在perl中刪除文件使用perl自帶的unlink函數,它也會調用操作系統的unlink函數來刪除文件。它可以接一個文件元素,也可以接一個列表,或者說它的參數上下文就是列表。
但是註意,unlink無法刪除目錄,要刪除目錄,見下文。
unlink @lotfiles; # 刪除數組中的文件 unlink 'cc.log'; # 刪除單個文件 unlink 'cc1.log','cc2.log'; # 刪除文件列表 unlink qw(cc3.log cc4.log); # 刪除文件列表 unlink glob dd*.log; # 通配文件名刪除
關於文件名通配詳細內容,見後文。
需要註意,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,它會發起系統調用並返回布爾值:成功/失敗,失敗時會設置
$!
- mkdir時可以同時指定文件權限,權限需要指定4位的8進制。如果使用變量傳遞這個權限位,應當使用oct()函數保護它不被當作十進制數
- mkdir不能遞歸創建目錄(unix系統下
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,且只能刪除空目錄
- 要刪除非空目錄,可以使用File::Path裏的rmtree函數或remove_tree函數,它們等價
- 刪除目錄時,可隨意對待尾隨斜線問題,因為perl會自動刪除尾隨斜線,以滿足多種平臺對尾隨斜線的定義標準
例如,刪除一個目錄
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/*>){
-d $_ ? rmtree $_ : unlink $_;
}
圖方便的話,直接和shell交互也非常方便。
`rm -rf /test/foo1/*`;
chdir切換目錄
- chdir用於切換到指定目錄,如果不給參數,則回到家目錄
- chdir因為直接發起系統調用,所以報錯時會設置
$!
- chdir不能使用shell裏的
~
來表示家目錄
chdir /tmp or die "Can't change dir to /tmp: $!";
修改權限
- chmod函數修改文件、文件列表的權限值,它會直接發起系統調用,所以錯誤的話會設置
$!
- 只接受8進制的權限值,不允許使用rwx的權限字符
- 它返回成功設置權限的數量
例如,設置目錄、文件的權限:
chmod 0700,qw(/test/foo /test/foo1/a.log);
chmod 0700,'/test/foo','/test/foo1/a.log';
修改所有者、所屬組
- chown可以同時修改文件/目錄、文件/目錄列表的所有者、所屬組,它會直接發起系統調用,所以報錯時會設置
$!
- chown只接受uid和gid作為參數,不接受username和groupname
- 但在unix上顯示的時候,還是會顯示為username和groupname,這是操作系統的映射機制
- 可以使用getpwnam和getgrnam函數將username/groupname映射為uid/gid
- 在uid或gid的參數位置上指定特殊值"-1",表示該位置的所有者或所屬組屬性保持不變
- 它返回成功設置的文件數量
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';
重命名文件/目錄
文件名通配
文件查找:關於find2perl腳本
Perl文件、目錄常用操作