1. 程式人生 > >Perl文件、目錄常用操作

Perl文件、目錄常用操作

定義 沒有 r語 參數 虛擬文件系統 sys dir perl log

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