| | mp3的檔案存取 檔案存取指mp3本身除了存儲mp3音樂之外,是否還可以作為移動存(u盤)使用,這樣可以進行各種格式文件的下載、上傳,也可以在硬碟裏存放簡報、照片、文件以及數碼影片等等。
存儲:分成無驅和有驅型兩種。大部分mp3出於版權保護的考慮,要求使用自帶的管理程序實現mp3機和電腦間的文件上傳、下載。現在出的mp3一般對非音樂格式的文件都支持檔案管理,就是可以實現這些文件的上傳、下載。而是否需要安裝驅動,衹影響具體使用環境——如果是固定電腦,即便有驅的也無所謂;如果是經常在不同電腦間轉移文件的,當然推薦無驅型的了,畢竟免除了安裝管理程序的煩惱(這裏的無驅也是相對win98後的操作係統而言)。
對於mp3的檔案存取功能來說,windows98及98以下的操作係統需要安裝隨機的驅動程序;而windows2000、xp、me等係統不需要安裝驅動程序,係統就會自動識別。perl的檔案存取
檔案係統在寫程式時是非常重要的一個部份,尤其對於perl的使用者來說,因為perl能夠處理大量而且復雜的資料,所以經常被拿來作為unix作業係統的管理工具,尤其對於unix-like係統管理員而言,在進行係統日志的管理時,存取檔案,讀取檔案內容並加以分析就是最基本的部份。當然,你還可能進行目錄的修改,檔案權限的維護等等跟係統有密切關係的操作。
10.1 檔案代號 (filehandle)
當你的perl想要透過作業係統進行檔案存取時,可以利用檔案代號取得和檔案間的係結,接下來的操作就是透過這個檔案代號和實體的檔案間進行溝通。也就是說,我們要進行檔案操作時,可以先定義相對應實體檔案的代號,以便我們用更簡便的方式對檔案進行存取。
而所謂的檔案代號其實就是由使用者自行命名,並且用來跟實體檔案進行連結的名稱,他的命名規則還是依循perl的命名規則,大傢對於這個規則應該相當熟悉了,不過我們還是再次提醒一下:可以數字,字母及底綫組成,但是不能以數字作為開始。而且一般來說,我們幾乎都習慣以全部大寫來作為檔案代號,因為檔案代號並不像其他變數,會使用某些符號作為識別,所以幾乎約定成俗的全部大寫習慣也是有存在的道理。
當然,你也可以依照自己的習慣來為檔案代號命名(註一),這表示所謂的全部大寫絶對不是一種鐵律,就像perl程式語言本身,希望以最少的限製來進行程式設計的工作。
10.2 預設的檔案代號
對於檔案的輸出,輸入而言,其實就跟平常時候,你利用perl在進行其他的操作非常接近,有時候衹是輸出到不同的媒介上。所以perl其實已經預定了幾種檔案代號,讓你不需要每次寫perl的程式就必須去重新定義這些代號,很顯然的,幾乎大部份的程式都會需要這些檔案代號。
這六個預設的檔案代號分別是:stdin,stdout,stderr,data,argv,argout,看起來相當熟悉吧?沒錯,因為很多時候,我們其實就是靠這些預設的檔案代號在進行程式的輸出,輸入。衹是我們還沒有瞭解這些其實就是檔案代號。換個角度來看,其實即使我們都不知道他們是預設的檔案代號,我們就能運作自如,那麽對於檔案代號的使用顯然就不是太難。不過,我們還是要再來看看這六個perl預設的檔案代號。其中有些我們已經使用過了,我們就先對其中幾個預設的檔案代號來進行介紹:
stdin:這也就是我們常看到的“標準輸入裝置”,當perl開始執行時,它預設接受的外部資訊就是從這裏而來。就像我們之前曾經看過的寫法:
my $input = <stdin>; # 從標準輸入裝置取得資料
print $input;
這時候,當我們從鍵盤輸入時,perl就可以正確的取得資訊,並且透過stdin取得使用者用鍵盤打入的一行字串。因此他的運作方式就是以一個檔案代號來進行。當然,你可以透過係統函式庫的配合,讓你的標準輸入轉為其他設備之後你就進行其他運用,不過這顯然不是這裏的主題,還是讓我們言歸正傳。對於perl來說,他從檔案係統讀入資料是以行為單位,因此即使是利用stdin,perl還是會等到使用者鍵入換行鍵時纔會有所動作。
stdout:相對於標準輸入,這就是所謂的標準輸出,也就是在正常狀況下,你希望perl輸出的結果就是透過stdout來進行輸出的。而一般來說,我們所使用的就是熒幕輸出。你可以看看這個程式裏的寫法:
my $output = "標準輸出";
print "$output ";
print stdout "$output ";
沒錯,就像我們所預期的,perl透過熒幕印出了兩行一模一樣的結果,也就是印了兩行“標準輸出”。原因非常簡單,因為當我們使用print的指令時,perl會使用stdout當作預設的檔案代號,所以一般狀況下,如果我們沒有指定檔案代號時,perl就會自動輸出到stdout。所以事實上,我們早就開始使用檔案代號了,衹是我們自己並沒有發覺。或說,perl原來的期望就是希望使用者都可以在最沒有負擔的狀況下任意輸出到熒幕,或從鍵盤輸入,畢竟perl程式設計師那麽的怕麻煩,一般的鍵盤輸入,熒幕輸出又是使用的那麽頻繁,當然要讓程式設計師以最簡單的方式達成。而且非常顯然,這個目的也算達到了。
stderr:標準的錯誤串流,也就是程式錯誤的標準輸出。正常而言,當程式發生錯誤時,程式可以發出錯誤訊息來通知使用者,這時候這些錯誤訊息也能透過檔案代號處理,把這些訊息丟進錯誤訊息串流。不過這樣說實在不太容易理解,那我們來玩個遊戲吧:
my $output = "標準輸出";
print "$output ";
print stderr "$output ";
我們一開始定義了一個字串$output,一開始我們先直接從標準輸出印出這個字串,接下來我們便要求perl把這個字串送出到錯誤串流中。這樣會發生甚麽有趣的事呢?讓我們來看看:
[hcchien@apple]% perl stderr.pl
標準輸出
標準輸出
[hcchien@apple]% perl stderr.pl > error.txt
標準輸出
第一次,我們直接執行了stderr.pl這支程式,而結果顯然有點平淡無奇。於是我們第二次執行時,就在後面加上了">error.txt",對於熟悉unix操作的人大概知道,這樣的方式其實是把程式執行時的錯誤訊息導嚮檔案"error.txt"了。所以stdout衹輸出了第一行的print結果,而係統也産生了另外的error.txt的檔案,因為我們把標準錯誤串流送到了這個檔案裏,所以我們可以發現檔案裏正好有我們輸出到標準錯誤串流的字串。這樣的作法對於可能把perl拿來進行係統管理的腳本程式時,就可以發揮很大的功能。因為我們也許希望某個程式可以幫我們進行一些日常的瑣事,而在處理這些瑣事的同時,如果發生甚麽異常狀況,可以把錯誤訊息存在某個檔案中,這樣一來我們就可以衹檢查這個日志檔案。
argv:我們可以直接利用參數來讀取某些檔案的內容,使用者衹需要在執行程式時,在程式後加上檔案名稱作為參數,然後在程式中我們就可以直接讀到檔案的內容了。還是用個例子比較容易理解:
my $input = <argv>;
print "$input ";
於是我們試着執行它,並且加上參數"error.txt"
[hcchien@apple]% perl argv.pl > error.txt
標準輸出
沒錯,當我們用了剛剛得到的error.txt當參數時,程式裏面直接使用預設檔案代號argv來讀取檔案內容,所以當我們印出來時,就可以看到剛剛寫入檔案的內容了。不過由於perl讀檔案的性質,其實我們衹印出了檔案內的第一行,不過這部份我們稍後會再提到,這裏暫且略過不談。
不過perl的argv其實非常好用,讓我們來看看使用陣列形式的@argv。也就是程式的參數,跟我們曾經提過的副常式參數有幾分相似。它也是把取得的參數放入陣列中,然後在程式裏,就可以直接叫用陣列,取出參數,就像這樣:
my $input = shift @argv;
print "$input ";
我們用同樣的方式執行,可以看到這樣的結果:
[hcchien@apple]% perl argv.pl error.txt
error.txt
另外,我們也可以對argv進行一般檔案代號的操作方式,不過這些將在稍後提到檔案操作時再來討論。
10.3 檔案的基本操作
我們剛剛提到了一些perl預設的檔案代號,這些檔案代號都是由perl自動産生的。因此當我們開始執行perl的程式時,就可以直接使用這些檔案代號。可是除此之外,當我們希望自己來對某些檔案進行存取時,就必須手動控製某些程序。所以現在應該來關心一下,當我們要手動進行這些檔案的控管時,應該怎麽做呢?
10.3.1 開檔/關檔
最基本的,我們要先開啓一個檔案,也就是我們必須將檔案代號和我們想要存取的檔案接上綫。首先,我們可以使用open這個指令來開啓檔案代號,並且指定這個檔案代號所對應的檔案名稱,所以我們使用的指令應該會會這樣:
open file, "file.txt";
open output, "<output.txt";# 從檔案輸出
open input, ">input.txt";# 輸入到檔案
open append, ">>append.txt";# 附加在現有檔案結尾
其實要開起一個檔案代號非常的容易,至少從上面的例子來看,應該還算是非常的平易近人。那麽我們衹需要稍微的解釋一些特殊的部份,大部份的人應該就可以輕鬆的開始使用檔案代號了。
首先,最基本的語法也就是利用open這個指令來結合檔案代號跟係統上實際的檔案。所以我們看到了所有的敘述都是以open接下檔案代號,接着是檔案的名稱。這樣一來,我們就把檔案代號跟檔案名稱連接起來,當然,前提是沒有錯誤發生。不過不管如何,這看起來應該非常容易了。接下來,看看在檔案名稱前面有一些大,小於符號,這些又是甚麽意思呢?這些符號主要在於對於檔案操作需求不同而産生不同的形式。首先我們看到的是一個小於(<)符號,這個符號代表我們會從這個檔案輸出資料,其實如果你對unix係統有一點熟悉,你會發現這些表示方式跟在一般使用轉嚮的方式接近。所以當你使用小於符號時,就像把檔案的資料轉嚮到檔案代號中。如果你可以想像小於符號的方向性,那麽大於符號也就是同樣道理了。大於符號也就是把資料從檔案代號中轉入實際的檔案係統裏,也就是寫入到某個檔案中。而如果係統中沒有這個檔案,perl會細心的幫你建立這個檔案,然後你透過檔案代號送出的資料就會由perl幫你寫入檔案中。不過有一個部份必須要特別註意的地方,也就是如果你透過大於符號建立的檔案係結,perl會把你指定的檔案視為全新的檔案,就如我們所說的,如果你的係統中沒有這個檔案,perl會先幫你建立一個新的檔案。不過如果你的係統本來就已經存在同樣的檔名,那麽perl會把原來的檔名清空,然後再把資料寫入。 當然,這樣就遇到問題了,因為如果你的程式正在監視網站伺服器,而你希望衹要伺服器有狀況發生就把發生的狀況寫入日志檔。這時候你大多會希望保留舊的日志,那麽如果perl每次都清空舊的日志內容就會讓我們造成睏擾。這時候我們總會希望perl能把新的狀況附加在原來的檔案最後面的位置,那麽我們就應該使用兩個大於(>>)的符號,這也就是">>"跟">"的不同之處。
既然你開啓了一個檔案代號,最好的方式就是在你使用完後要歸回原處(從小媽媽就這麽告誡我們)。因此如果你不再使用某個檔案代號時,你最好養成關閉這些檔案代號的習慣,對了,應該還要提醒的是“適時”關閉不需要的檔案代號。雖然perl會在程式結束時自動幫你關閉所有還開着的檔案代號,不過有些時候,你如果沒有在檔案處理完之後就盡快處理的話,恐怕會有讓係統資源的負擔增加。
至於關閉檔案代號的方式也是非常簡單,你衹要使用close這個關鍵字,然後告訴perl你所要關閉的檔案代號,這樣就沒問題了。因此你如果需要關閉檔案代號,你衹需要這麽做:
close file;
沒錯,就是這麽容易。不過卻也相當重要,至少你應該考慮好你自己的係統資源管理。否則等到等到持續拖纍係統資源時纔要怪罪perl時可就有失公允了。另外,perl也會在你關閉檔案代號時檢查緩衝區是否還存有資料,如果有的話,perl也會先把資料寫入檔案,然後關閉檔案。另外,檔案也可能因為你的開啓而導致其他人無法對它正常的操作,因此盡可能在完成檔案操作後馬上關閉檔案代號是重要的習慣。
10.3.2 意外處理
有些時候,當我們想要開啓檔案時卻會發現一些狀況。例如我們想要從某個已經存在的檔案中讀入某些資料,可是卻發生檔案不存在,或是權限不足,而無法讀入的狀況。我們先看看以下的例子:
#!/usr/local/bin/perl
use strict;
open file, "<foo.txt";
while (<file>) {
print $_;
}
在這裏,我們希望開啓一個檔案"foo.txt",並且從檔案中讀取資料,接着再把檔案內容逐行印出。不過非常可惜,我們的係統中並沒有這個檔案。不過perl預設並不會提醒你這樣的狀況,而且如果你沒有使用任何的警告或中斷,perl也能安穩的執行完這個程式,當然結果是“沒有結果”。可是當我們在寫程式,或是使用者在跟程式進行互動時,實在難保這些時候都不會甚麽錯誤會發生,也許衹要把檔案名稱打錯,可是perl卻不會自動的警告你。於是我們應該考慮發出一些警告,讓發生錯誤的人可以即時修正錯誤。當然,你可以使用warnings來讓perl對於人為的錯誤發生一些警告,不過我們還有另外一種方法可以讓你更輕易的掌握錯誤發生的狀況,也就是讓程式“死去(die)”。
die函式就像他的字面意思,他可以讓程式停止執行,也就是讓程式“死去”。因此當我們希望程式在某些狀況下應該停止執行時,我們就可以使用die函式來達成。而檔案發生問題的狀況則是die函式經常被使用的地方。因為很多時候我們一但開啓了某個檔案,大多就會把操作內容圍繞着這個被開啓的檔案,可是如果檔案其實沒有被正確的開啓,就很容易産生一些難以預料的問題,因此我們可以在檔案開啓失敗時就讓程式停止執行。以剛剛的程式作為例子,我們就可以把開啓檔案的部份寫成:
open file, "foo.txt" or die "開啓檔案失敗: $!";
在這裏,有幾個地方需要解釋的,首先自然就是die的用法。我們先嘗試開啓foo.txt這個檔案,接着用了一個邏輯運算元'or',後面接着使用die這個敘述。根據我們對or運算符的瞭解,程式會先嘗試開啓檔案"foo.txt",如果成功開啓,就會傳回1,因此or後面的敘述就會被省略。相反的,如果開啓檔案失敗,open敘述會傳回0。如此一來,perl就會去執行or後面的敘述,因此他就會die了,也就是衹執行到這裏為止。
利用die結束程式的執行時,我們會希望知道程式為甚麽進入die的狀況,因此我們便利用die印出目前的情況。這聽起來就像程式說完遺言之後就不動了。而die的列印就跟我們一般使用print沒甚麽不同,因此我們可以加上可以提醒程式寫作者或使用者的字串。不過在剛剛的例子,我們看到了一個不尋常的變數:"$!"。這是perl預設的一個變數,他會儲存係統産生出來的錯誤訊息。因為當我們透過perl要進行檔案的存取時,其實衹是透過perl和作業係統進行溝通,因此一但perl對作業係統的要求産生失敗的狀況,他便會從作業係統得到相關的錯誤訊息,而這個訊息也會被存入$!這個變數中。
所以如果我們執行剛剛改過的那個程式,就可以得到像這樣的結果:
[hcchien@apple]% perl ch3.pl
開啓檔案失敗: no such file or directory at ch3.pl line 5.
因為檔案不存在的原因,導致這一支perl程式無法繼續執行而在執行完die之後就停止了。而且die這個指令也在我們的要求下,傳達了係統的錯誤訊息給我們,問題發生在你要開啓檔案時卻沒有發現這個檔案或資料夾。所以利用die這個指令,你就可以在程式無法正確開啓檔案時,就馬上中斷程式,以避免不可預知的問題産生。
既然提到die,我們就順便來談一下die的親戚,"warn"吧!當你發生一些狀況,可能導致程式發生無法正常運作時,你會希望使用die來強製中斷程式的執行。可是有些時候,錯誤也許並沒有這麽嚴重,那麽你就衹需要發出一些警告,讓執行者知道程式出了一點問題,讓他們决定是否應該中斷程式吧!我門把剛剛的程式改成這樣:
#!/usr/local/bin/perl
use strict;
open file, "<foo.txt" or warn "open failed: $!";
while (<file>) {
print $_;
}
print "程式在這裏結束了 ";
你應該發現了,我們把die改成了warn,然後最後加了一行列印的指令,告訴我們程式的結尾在那裏。接下來我們來試着執行這支修改過的程式,你會看到這樣的結果:
[hcchien@apple]% perl ch3.pl
open failed: no such file or directory at ch3.pl line 5.
the end of the script
10.3.3 讀出與寫入
在我們可以正確的開啓檔案代號之後,接下來我們就可以開始存取檔案中的資料,當然最主要的就是讀取,以及寫入檔案。
透過檔案代號來讀取檔案內容倒是不太有甚麽睏難。我們大多使用鑽石符號(<>)來進行檔案內容的讀取。所以我們可以像這樣進行檔案操作:
#!/usr/local/bin/perl -w
use strict;
open log, "/var/log/messages"; # 打開這個日志檔
while (<log>) { # 利用鑽石符號讀入資料
print if (/sudo/); # 符合比對的資料就列印出來
}
看起來非常容易,不是嗎?
我們先用剛剛瞭解的方式開啓了一個檔案代號,並且利用這個檔案代號聯繫到檔案"/var/log/messages"。在一些unix係統中也許會看到這個檔案,它會紀錄一些使用者登入或是使用root權限的消息。而在這個檔案中,如果有使用者利用sudo這個指令進行某些操作時也會被記錄下來。因此我們就可以透過這個檔案知道伺服器上有些甚麽狀況正在發生。
接下來我們透過鑽石符號開始逐行讀取日志檔案中的資料,透過回圈while讀取檔案中的資料時,while會把所讀到的資料內容放進perl的預設變數$_中,一直到檔案結束,傳回eof時,回圈便會結束。因此我們就將所讀取的資料進行比對,以sudo這個關鍵字作為比對樣式,把符合的結果印出來。
這樣一來,衹要係統中有人使用sudo進行係統操作時,我們就可以檢查出來,而且印出來的結果會像是這樣:
tty=ttyp0 ; pwd=/var/log ; user=root ; command=/bin/rm -rf httpd-error.log
tty=ttyp0 ; pwd=/var/log ; user=root ; command=/bin/rm -rf httpd-access.log
tty=ttyp0 ; pwd=/var/log ; user=root ; command=/bin/rm -rf 192.168.1.1_access_log
192.168.1.1_error_log
tty=ttyp0 ; pwd=/usr/home ; user=root ; command=/bin/rm -rf interchange/
tty=ttyp0 ; pwd=/usr/home ; user=root ; command=/bin/rm -rf gugod/
tty=ttyp0 ; pwd=/usr/home ; user=root ; command=/bin/rm -rf mysql/
tty=ttyp0 ; pwd=/ ; user=root ; command=/bin/rm kernel.old
tty=ttyp0 ; pwd=/ ; user=root ; command=/bin/rm -rf modules.old/
tty=ttyp0 ; pwd=/ ; user=root ; command=/bin/rm -rf opt/
如果你是負責管理一些unix的伺服器,利用這樣簡單的方式,確實可以幫忙你完成不少工作。很顯然,利用檔案的操作,你還可以進行更多對日志檔案的分析。例如你可以分析網站伺服器的各項資料,雖然其實已經有很多人用perl幫你完成這樣的工作了。(註二)
基本上,從檔案內讀取內容的方式就是這麽容易,因此你可以簡單的運用檔案的內容進行所需要的工作。還記得我們在介紹open時的說明嗎?我們有幾個開啓檔案的方式包括了幾種描述子,例如大於(>),小於(<),以及兩個大於(>>)。而且我們也都簡單的描述過他們的差異,現在也許就是測試這些描述子的好時機,我們先來看看小於符號用於開檔的時候,會有甚麽影響。
我們之前也提過小於符號用在開檔作為描述的話,是用來表示從檔案內讀取資料。那我們是不是就衹能允許使用者讀取資料呢?先來看看這個小小的程式吧:
open log, "<log.txt" or die $!;
while (<log>) {
print $_;
}
print log "write to log" or die $!;
假設我們已經有了"log.txt"這個檔案,否則程式就會挂在中間,沒辦法繼續執行。那麽我們來看看執行結果吧:
file for log
bad file descriptor at ch3.pl line 9, <log> line 1.
第一行就是原來log.txt裏面的內容,我們可以很輕鬆的讀出其中的資料,並且印出來,可是當我們要將資料寫入時,卻出現了錯誤訊息。沒錯,當初我們在開啓這個檔案時,衹要求perl給我們一個可以讀出資料的檔案,如今要求寫入,果然就遭到拒絶。
看來一但我們使用了小於符號作為開啓檔案代號的描述子,那麽我們就不能輕易的把資料寫入所開啓的檔案中。想當然爾,perl應該也不會讓我們在開啓一個利用大於符號指定為寫入的檔案中把資料讀出吧?要想測試這樣的結論,我們衹需要把剛剛的程式修改一個字元,也就是把小於符號改成大於,那麽就讓我們來看看執行後的結果吧:
我們嘗試着執行被我們修改了一個字元的程式,結果發生了甚麽事呢?檔案沒有輸出任何結果。好像很出乎意料?其實一點也不,而且正如perl所要求我們的,我們使用了大於符號表明我們想要把資料寫入檔案log.txt,因此當我們想要從檔案讀取資料並且逐行印出結果時就無法成真。不過我們接下來去看看log.txt的內容。正如我們所預料的,程式已經正確的把字串"write to log"寫到檔案log.txt裏面了。
既然使用大於符號跟小於符號都符合我們的期待,那麽如果我們甚麽描述子都沒有使用,會是甚麽樣的情況呢?我們衹需要使用剛剛的測試程式,並且把描述子全部取消,再來試試結果如何吧!
結果我們發現,perl還是可以讀出檔案的內容,可是卻無法寫入。也就是跟我們使用小於符號時是一樣的狀況,這點其實對於經常必須使用檔案的人來說其實是非常重要的。所以如果你有機會使用檔案的存取時,可別忘了這一點。
另外,大於符號與兩個大於的差別我們也曾經提過,這部份對於可能使用perl來進行日常管理工作的人更是必須牢記。我們之前提過,一樣是開啓一個可以寫入的檔案,使用一個大於符號(>)的時候,perl會判斷你是否已經有存在這個檔名的檔案,如果檔案已經存在,那麽perl將會清空檔案內容,把他視作一個新的檔案來進行操作。如果在係統中檔案並不存在,那麽perl就會跟係統要求開啓一個新的檔案。當然,在你使用兩個大於符號的時候,perl會把你要寫入檔案的內容以附加的方式存入。當然,如果你的係統中並沒有這個檔案,那麽perl也會先開啓一個新檔,並且把你所要求的內容寫入檔案中。這對於想要建立類似日志檔的需求有着絶對的幫助,例如你可能會需要perl來作為監控網路的狀況,這時候你會需要每次有新狀況時就把它記錄下來,而且需要保留原來的紀錄。那麽如果你還是使用大於符號的話,你可就要小心原來的資料內容遺失了。
當然,我們知道開啓檔案時可以利用三種描述子去指定所要開啓檔案代號的狀態,不過如果你甚麽都沒加的狀況下,perl又會作怎麽樣的處理呢?我們繼續用剛剛的例子來進行實驗吧。我們把開啓檔案的描述子拿掉,其他的部份一切照舊。所以你的程式就像這樣:
open log, "log.txt" or die $!;
print log "write to log " or die $!;
接着我們發現,這樣的結果就跟我們使用小於符號的效果是相同的,也就是perl衹會從檔案中讀出資料,卻無法寫入。
有了基本讀寫檔案的能力之後,我們還必須瞭解該怎麽樣透過perl去控製係統的檔案以及資料夾。這樣才能確實掌握係統的檔案管理,尤其當你希望使用perl來進行係統管理時,也就會更需要這樣的能力,所以我們接下來就要討論利用perl對檔案係統的操作。
註一:不過當你打算這麽作的時候,也許要考慮這支程式未來衹有你在維護,否則你這樣的動作很可能會因為接下來維護的人需要花更多的時間來看懂程式而提高不少維護成本。
註二:其實跟這章主題不太有關,不過例如awstats就是這類型的工具。
linux/unix 的檔案存取權限
使用權限 : 所有使用者
使用方式 : chmod [-cfvr] [--help] [--version] mode file...
說明 : linux/unix 的檔案存取權限分為三級 : 檔案擁有者、群組、其他。利用 chmod 可以藉以控製檔案如何被他人所存取。
把計 :
mode : 權限設定字串,格式如下 : [ugoa...][[+-=][rwxx]...][,...],其中u 表示該檔案的擁有者,g 表示與該檔案的擁有者屬於同一個群體(group)者,o 表示其他以外的人,a 表示這三者皆是。
+ 表示增加權限、- 表示取消權限、= 表示唯一設定權限。
r 表示可讀取,w 表示可寫入,x 表示可執行,x 表示衹有當該檔案是個子目錄或者該檔案已經被設定過為可執行。
-c : 若該檔案權限確實已經更改,纔顯示其更改動作
-f : 若該檔案權限無法被更改也不要顯示錯誤訊息
-v : 顯示權限變更的詳細資料
-r : 對目前目錄下的所有檔案與子目錄進行相同的權限變更(即以遞回的方式逐個變更)
--help : 顯示輔助說明
--version : 顯示版本
範例 :將檔案 file1.txt 設為所有人皆可讀取 :
chmod ugo+r file1.txt
將檔案 file1.txt 設為所有人皆可讀取 :
chmod a+r file1.txt
將檔案 file1.txt 與 file2.txt 設為該檔案擁有者,與其所屬同一個群體者可寫入,但其他以外的人則不可寫入 :
chmod ug+w,o-w file1.txt file2.txt
將 ex1.py 設定為衹有該檔案擁有者可以執行 :
chmod u+x ex1.py
將目前目錄下的所有檔案與子目錄皆設為任何人可讀取 :
chmod -r a+r *
此外chmod也可以用數字來表示權限如 chmod 777 file
語法為:chmod abc file
其中a,b,c各為一個數字,分別表示user、group、及other的權限。
r=4,w=2,x=1
若要rwx屬性則4+2+1=7;
若要rw-屬性則4+2=6;
若要r-x屬性則4+1=7。
範例:
chmod a=rwx file
和
chmod 777 file
效果相同
chmod ug=rwx,o=x file
和
chmod 771 file
效果相同
若用chmod 4755 filename可使此程式具有root的權限
指令名稱 : chown
使用權限 : root
使用方式 : chmod [-cfhvr] [--help] [--version] user[:group] file...
說明 : linux/unix 是多人多工作業係統,所有的檔案皆有擁有者。利用 chown 可以將檔案的擁有者加以改變。一般來說,這個指令衹有是由係統管理者(root)所使用,一般使用者沒有權限可以改變別人的檔案擁有者,也沒有權限可以自己的檔案擁有者改設為別人。衹有係統管理者(root)纔有這樣的權限。
把計 :
user : 新的檔案擁有者的使用者 idgroup : 新的檔案擁有者的使用者群體(group)-c : 若該檔案擁有者確實已經更改,纔顯示其更改動作-f : 若該檔案擁有者無法被更改也不要顯示錯誤訊息-h : 衹對於連結(link)進行變更,而非該 link 真正指嚮的檔案-v : 顯示擁有者變更的詳細資料-r : 對目前目錄下的所有檔案與子目錄進行相同的擁有者變更(即以遞回的方式逐個變更)--help : 顯示輔助說明--version : 顯示版本
範例 :
將檔案 file1.txt 的擁有者設為 users 群體的使用者 jessie :
chown jessie:users file1.txt
將目前目錄下的所有檔案與子目錄的擁有者皆設為 users 群體的使用者 lamport :
chmod -r lamport:users *
-rw------- (600) -- 衹有屬主有讀寫權限。
-rw-r--r-- (644) -- 衹有屬主有讀寫權限;而屬組用戶和其他用戶衹有讀權限。
-rwx------ (700) -- 衹有屬主有讀、寫、執行權限。
-rwxr-xr-x (755) -- 屬主有讀、寫、執行權限;而屬組用戶和其他用戶衹有讀、執行權限。
-rwx--x--x (711) -- 屬主有讀、寫、執行權限;而屬組用戶和其他用戶衹有執行權限。
-rw-rw-rw- (666) -- 所有用戶都有文件讀、寫權限。這種做法不可取。
-rwxrwxrwx (777) -- 所有用戶都有讀、寫、執行權限。更不可取的做法。
以下是對目錄的兩個普通設定:
drwx------ (700) - 衹有屬主可在目錄中讀、寫。
drwxr-xr-x (755) - 所有用戶可讀該目錄,但衹有屬主才能改變目錄中的內容
suid的代表數字是4,比如4755的結果是-rwsr-xr-x
sgid的代表數字是2,比如6755的結果是-rwsr-sr-x
sticky位代表數字是1,比如7755的結果是-rwsr-sr-t | | 檔案存取指MP3本身除了存儲MP3音樂之外,是否還可以作為移動存(U盤)使用,這樣可以進行各種格式文件的下載、上傳,也可以在硬碟裏存放簡報、照片、文件以及數碼影片等等。
存儲:分成無驅和有驅型兩種。大部分MP3出於版權保護的考慮,要求使用自帶的管理程序實現MP3機和電腦間的文件上傳、下載。現在出的MP3一般對非音樂格式的文件都支持檔案管理,就是可以實現這些文件的上傳、下載。而是否需要安裝驅動,衹影響具體使用環境——如果是固定電腦,即便有驅的也無所謂;如果是經常在不同電腦間轉移文件的,當然推薦無驅型的了,畢竟免除了安裝管理程序的煩惱(這裏的無驅也是相對WIN98後的操作係統而言)。
對於MP3的檔案存取功能來說,Windows98及98以下的操作係統需要安裝隨機的驅動程序;而Windows2000、XP、ME等係統不需要安裝驅動程序,係統就會自動識別。 | | 檔案係統在寫程式時是非常重要的一個部份,尤其對於Perl的使用者來說,因為Perl能夠處理大量而且復雜的資料,所以經常被拿來作為Unix作業係統的管理工具,尤其對於Unix-like係統管理員而言,在進行係統日志的管理時,存取檔案,讀取檔案內容並加以分析就是最基本的部份。當然,你還可能進行目錄的修改,檔案權限的維護等等跟係統有密切關係的操作。
10.1 檔案代號 (FileHandle)
當你的Perl想要透過作業係統進行檔案存取時,可以利用檔案代號取得和檔案間的係結,接下來的操作就是透過這個檔案代號和實體的檔案間進行溝通。也就是說,我們要進行檔案操作時,可以先定義相對應實體檔案的代號,以便我們用更簡便的方式對檔案進行存取。
而所謂的檔案代號其實就是由使用者自行命名,並且用來跟實體檔案進行連結的名稱,他的命名規則還是依循Perl的命名規則,大傢對於這個規則應該相當熟悉了,不過我們還是再次提醒一下:可以數字,字母及底綫組成,但是不能以數字作為開始。而且一般來說,我們幾乎都習慣以全部大寫來作為檔案代號,因為檔案代號並不像其他變數,會使用某些符號作為識別,所以幾乎約定成俗的全部大寫習慣也是有存在的道理。
當然,你也可以依照自己的習慣來為檔案代號命名(註一),這表示所謂的全部大寫絶對不是一種鐵律,就像Perl程式語言本身,希望以最少的限製來進行程式設計的工作。
10.2 預設的檔案代號
對於檔案的輸出,輸入而言,其實就跟平常時候,你利用Perl在進行其他的操作非常接近,有時候衹是輸出到不同的媒介上。所以Perl其實已經預定了幾種檔案代號,讓你不需要每次寫Perl的程式就必須去重新定義這些代號,很顯然的,幾乎大部份的程式都會需要這些檔案代號。
這六個預設的檔案代號分別是:STDIN,STDOUT,STDERR,DATA,ARGV,ARGOUT,看起來相當熟悉吧?沒錯,因為很多時候,我們其實就是靠這些預設的檔案代號在進行程式的輸出,輸入。衹是我們還沒有瞭解這些其實就是檔案代號。換個角度來看,其實即使我們都不知道他們是預設的檔案代號,我們就能運作自如,那麽對於檔案代號的使用顯然就不是太難。不過,我們還是要再來看看這六個Perl預設的檔案代號。其中有些我們已經使用過了,我們就先對其中幾個預設的檔案代號來進行介紹:
STDIN:這也就是我們常看到的“標準輸入裝置”,當Perl開始執行時,它預設接受的外部資訊就是從這裏而來。就像我們之前曾經看過的寫法:
my $input = <STDIN>; # 從標準輸入裝置取得資料
print $input;
這時候,當我們從鍵盤輸入時,Perl就可以正確的取得資訊,並且透過STDIN取得使用者用鍵盤打入的一行字串。因此他的運作方式就是以一個檔案代號來進行。當然,你可以透過係統函式庫的配合,讓你的標準輸入轉為其他設備之後你就進行其他運用,不過這顯然不是這裏的主題,還是讓我們言歸正傳。對於Perl來說,他從檔案係統讀入資料是以行為單位,因此即使是利用STDIN,Perl還是會等到使用者鍵入換行鍵時纔會有所動作。
STDOUT:相對於標準輸入,這就是所謂的標準輸出,也就是在正常狀況下,你希望Perl輸出的結果就是透過STDOUT來進行輸出的。而一般來說,我們所使用的就是熒幕輸出。你可以看看這個程式裏的寫法:
my $output = "標準輸出";
print "$outputn";
print STDOUT "$outputn";
沒錯,就像我們所預期的,Perl透過熒幕印出了兩行一模一樣的結果,也就是印了兩行“標準輸出”。原因非常簡單,因為當我們使用print的指令時,Perl會使用STDOUT當作預設的檔案代號,所以一般狀況下,如果我們沒有指定檔案代號時,Perl就會自動輸出到STDOUT。所以事實上,我們早就開始使用檔案代號了,衹是我們自己並沒有發覺。或說,Perl原來的期望就是希望使用者都可以在最沒有負擔的狀況下任意輸出到熒幕,或從鍵盤輸入,畢竟Perl程式設計師那麽的怕麻煩,一般的鍵盤輸入,熒幕輸出又是使用的那麽頻繁,當然要讓程式設計師以最簡單的方式達成。而且非常顯然,這個目的也算達到了。
STDERR:標準的錯誤串流,也就是程式錯誤的標準輸出。正常而言,當程式發生錯誤時,程式可以發出錯誤訊息來通知使用者,這時候這些錯誤訊息也能透過檔案代號處理,把這些訊息丟進錯誤訊息串流。不過這樣說實在不太容易理解,那我們來玩個遊戲吧:
my $output = "標準輸出";
print "$outputn";
print STDERR "$outputn";
我們一開始定義了一個字串$output,一開始我們先直接從標準輸出印出這個字串,接下來我們便要求Perl把這個字串送出到錯誤串流中。這樣會發生甚麽有趣的事呢?讓我們來看看:
[hcchien@Apple]% perl stderr.pl
標準輸出
標準輸出
[hcchien@Apple]% perl stderr.pl > error.txt
標準輸出
第一次,我們直接執行了stderr.pl這支程式,而結果顯然有點平淡無奇。於是我們第二次執行時,就在後面加上了">error.txt",對於熟悉Unix操作的人大概知道,這樣的方式其實是把程式執行時的錯誤訊息導嚮檔案"error.txt"了。所以STDOUT衹輸出了第一行的print結果,而係統也産生了另外的error.txt的檔案,因為我們把標準錯誤串流送到了這個檔案裏,所以我們可以發現檔案裏正好有我們輸出到標準錯誤串流的字串。這樣的作法對於可能把Perl拿來進行係統管理的腳本程式時,就可以發揮很大的功能。因為我們也許希望某個程式可以幫我們進行一些日常的瑣事,而在處理這些瑣事的同時,如果發生甚麽異常狀況,可以把錯誤訊息存在某個檔案中,這樣一來我們就可以衹檢查這個日志檔案。
ARGV:我們可以直接利用參數來讀取某些檔案的內容,使用者衹需要在執行程式時,在程式後加上檔案名稱作為參數,然後在程式中我們就可以直接讀到檔案的內容了。還是用個例子比較容易理解:
my $input = <ARGV>;
print "$inputn";
於是我們試着執行它,並且加上參數"error.txt"
[hcchien@Apple]% perl argv.pl > error.txt
標準輸出
沒錯,當我們用了剛剛得到的error.txt當參數時,程式裏面直接使用預設檔案代號ARGV來讀取檔案內容,所以當我們印出來時,就可以看到剛剛寫入檔案的內容了。不過由於Perl讀檔案的性質,其實我們衹印出了檔案內的第一行,不過這部份我們稍後會再提到,這裏暫且略過不談。
不過Perl的ARGV其實非常好用,讓我們來看看使用陣列形式的@ARGV。也就是程式的參數,跟我們曾經提過的副常式參數有幾分相似。它也是把取得的參數放入陣列中,然後在程式裏,就可以直接叫用陣列,取出參數,就像這樣:
my $input = shift @ARGV;
print "$inputn";
我們用同樣的方式執行,可以看到這樣的結果:
[hcchien@Apple]% perl argv.pl error.txt
error.txt
另外,我們也可以對ARGV進行一般檔案代號的操作方式,不過這些將在稍後提到檔案操作時再來討論。
10.3 檔案的基本操作
我們剛剛提到了一些Perl預設的檔案代號,這些檔案代號都是由Perl自動産生的。因此當我們開始執行Perl的程式時,就可以直接使用這些檔案代號。可是除此之外,當我們希望自己來對某些檔案進行存取時,就必須手動控製某些程序。所以現在應該來關心一下,當我們要手動進行這些檔案的控管時,應該怎麽做呢?
10.3.1 開檔/關檔
最基本的,我們要先開啓一個檔案,也就是我們必須將檔案代號和我們想要存取的檔案接上綫。首先,我們可以使用open這個指令來開啓檔案代號,並且指定這個檔案代號所對應的檔案名稱,所以我們使用的指令應該會會這樣:
open FILE, "file.txt";
open OUTPUT, "<output.txt"; # 從檔案輸出
open INPUT, ">input.txt"; # 輸入到檔案
open append, ">>append.txt"; # 附加在現有檔案結尾
其實要開起一個檔案代號非常的容易,至少從上面的例子來看,應該還算是非常的平易近人。那麽我們衹需要稍微的解釋一些特殊的部份,大部份的人應該就可以輕鬆的開始使用檔案代號了。
首先,最基本的語法也就是利用open這個指令來結合檔案代號跟係統上實際的檔案。所以我們看到了所有的敘述都是以open接下檔案代號,接着是檔案的名稱。這樣一來,我們就把檔案代號跟檔案名稱連接起來,當然,前提是沒有錯誤發生。不過不管如何,這看起來應該非常容易了。接下來,看看在檔案名稱前面有一些大,小於符號,這些又是甚麽意思呢?這些符號主要在於對於檔案操作需求不同而産生不同的形式。首先我們看到的是一個小於(<)符號,這個符號代表我們會從這個檔案輸出資料,其實如果你對Unix係統有一點熟悉,你會發現這些表示方式跟在一般使用轉嚮的方式接近。所以當你使用小於符號時,就像把檔案的資料轉嚮到檔案代號中。如果你可以想像小於符號的方向性,那麽大於符號也就是同樣道理了。大於符號也就是把資料從檔案代號中轉入實際的檔案係統裏,也就是寫入到某個檔案中。而如果係統中沒有這個檔案,Perl會細心的幫你建立這個檔案,然後你透過檔案代號送出的資料就會由Perl幫你寫入檔案中。不過有一個部份必須要特別註意的地方,也就是如果你透過大於符號建立的檔案係結,Perl會把你指定的檔案視為全新的檔案,就如我們所說的,如果你的係統中沒有這個檔案,Perl會先幫你建立一個新的檔案。不過如果你的係統本來就已經存在同樣的檔名,那麽Perl會把原來的檔名清空,然後再把資料寫入。 當然,這樣就遇到問題了,因為如果你的程式正在監視網站伺服器,而你希望衹要伺服器有狀況發生就把發生的狀況寫入日志檔。這時候你大多會希望保留舊的日志,那麽如果Perl每次都清空舊的日志內容就會讓我們造成睏擾。這時候我們總會希望Perl能把新的狀況附加在原來的檔案最後面的位置,那麽我們就應該使用兩個大於(>>)的符號,這也就是">>"跟">"的不同之處。
既然你開啓了一個檔案代號,最好的方式就是在你使用完後要歸回原處(從小媽媽就這麽告誡我們)。因此如果你不再使用某個檔案代號時,你最好養成關閉這些檔案代號的習慣,對了,應該還要提醒的是“適時”關閉不需要的檔案代號。雖然Perl會在程式結束時自動幫你關閉所有還開着的檔案代號,不過有些時候,你如果沒有在檔案處理完之後就盡快處理的話,恐怕會有讓係統資源的負擔增加。
至於關閉檔案代號的方式也是非常簡單,你衹要使用close這個關鍵字,然後告訴Perl你所要關閉的檔案代號,這樣就沒問題了。因此你如果需要關閉檔案代號,你衹需要這麽做:
close FILE;
沒錯,就是這麽容易。不過卻也相當重要,至少你應該考慮好你自己的係統資源管理。否則等到等到持續拖纍係統資源時纔要怪罪Perl時可就有失公允了。另外,Perl也會在你關閉檔案代號時檢查緩衝區是否還存有資料,如果有的話,Perl也會先把資料寫入檔案,然後關閉檔案。另外,檔案也可能因為你的開啓而導致其他人無法對它正常的操作,因此盡可能在完成檔案操作後馬上關閉檔案代號是重要的習慣。
10.3.2 意外處理
有些時候,當我們想要開啓檔案時卻會發現一些狀況。例如我們想要從某個已經存在的檔案中讀入某些資料,可是卻發生檔案不存在,或是權限不足,而無法讀入的狀況。我們先看看以下的例子:
#!/usr/local/bin/perl
use strict;
open FILE, "<foo.txt";
while (<FILE>) {
print $_;
}
在這裏,我們希望開啓一個檔案"foo.txt",並且從檔案中讀取資料,接着再把檔案內容逐行印出。不過非常可惜,我們的係統中並沒有這個檔案。不過Perl預設並不會提醒你這樣的狀況,而且如果你沒有使用任何的警告或中斷,Perl也能安穩的執行完這個程式,當然結果是“沒有結果”。可是當我們在寫程式,或是使用者在跟程式進行互動時,實在難保這些時候都不會甚麽錯誤會發生,也許衹要把檔案名稱打錯,可是Perl卻不會自動的警告你。於是我們應該考慮發出一些警告,讓發生錯誤的人可以即時修正錯誤。當然,你可以使用warnings來讓Perl對於人為的錯誤發生一些警告,不過我們還有另外一種方法可以讓你更輕易的掌握錯誤發生的狀況,也就是讓程式“死去(die)”。
die函式就像他的字面意思,他可以讓程式停止執行,也就是讓程式“死去”。因此當我們希望程式在某些狀況下應該停止執行時,我們就可以使用die函式來達成。而檔案發生問題的狀況則是die函式經常被使用的地方。因為很多時候我們一旦開啓了某個檔案,大多就會把操作內容圍繞着這個被開啓的檔案,可是如果檔案其實沒有被正確的開啓,就很容易産生一些難以預料的問題,因此我們可以在檔案開啓失敗時就讓程式停止執行。以剛剛的程式作為例子,我們就可以把開啓檔案的部份寫成:
open File, "foo.txt" or die "開啓檔案失敗: $!";
在這裏,有幾個地方需要解釋的,首先自然就是die的用法。我們先嘗試開啓foo.txt這個檔案,接着用了一個邏輯運算元'or',後面接着使用die這個敘述。根據我們對or運算符的瞭解,程式會先嘗試開啓檔案"foo.txt",如果成功開啓,就會傳回1,因此or後面的敘述就會被省略。相反的,如果開啓檔案失敗,open敘述會傳回0。如此一來,Perl就會去執行or後面的敘述,因此他就會die了,也就是衹執行到這裏為止。
利用die結束程式的執行時,我們會希望知道程式為甚麽進入die的狀況,因此我們便利用die印出目前的情況。這聽起來就像程式說完遺言之後就不動了。而die的列印就跟我們一般使用print沒甚麽不同,因此我們可以加上可以提醒程式寫作者或使用者的字串。不過在剛剛的例子,我們看到了一個不尋常的變數:"$!"。這是Perl預設的一個變數,他會儲存係統産生出來的錯誤訊息。因為當我們透過Perl要進行檔案的存取時,其實衹是透過Perl和作業係統進行溝通,因此一但Perl對作業係統的要求産生失敗的狀況,他便會從作業係統得到相關的錯誤訊息,而這個訊息也會被存入$!這個變數中。
所以如果我們執行剛剛改過的那個程式,就可以得到像這樣的結果:
[hcchien@Apple]% perl ch3.pl
開啓檔案失敗: No such file or directory at ch3.pl line 5.
因為檔案不存在的原因,導致這一支Perl程式無法繼續執行而在執行完die之後就停止了。而且die這個指令也在我們的要求下,傳達了係統的錯誤訊息給我們,問題發生在你要開啓檔案時卻沒有發現這個檔案或資料夾。所以利用die這個指令,你就可以在程式無法正確開啓檔案時,就馬上中斷程式,以避免不可預知的問題産生。
既然提到die,我們就順便來談一下die的親戚,"warn"吧!當你發生一些狀況,可能導致程式發生無法正常運作時,你會希望使用die來強製中斷程式的執行。可是有些時候,錯誤也許並沒有這麽嚴重,那麽你就衹需要發出一些警告,讓執行者知道程式出了一點問題,讓他們决定是否應該中斷程式吧!我門把剛剛的程式改成這樣:
#!/usr/local/bin/perl
use strict;
open FILE, "<foo.txt" or warn "open failed: $!";
while (<FILE>) {
print $_;
}
print "程式在這裏結束了n";
你應該發現了,我們把die改成了warn,然後最後加了一行列印的指令,告訴我們程式的結尾在那裏。接下來我們來試着執行這支修改過的程式,你會看到這樣的結果:
[hcchien@Apple]% perl ch3.pl
open failed: No such file or directory at ch3.pl line 5.
the end of the script
10.3.3 讀出與寫入
在我們可以正確的開啓檔案代號之後,接下來我們就可以開始存取檔案中的資料,當然最主要的就是讀取,以及寫入檔案。
透過檔案代號來讀取檔案內容倒是不太有甚麽睏難。我們大多使用鑽石符號(<>)來進行檔案內容的讀取。所以我們可以像這樣進行檔案操作:
#!/usr/local/bin/perl -w
use strict;
open LOG, "/var/log/messages"; # 打開這個日志檔
while (<LOG>) { # 利用鑽石符號讀入資料
print if (/sudo/); # 符合比對的資料就列印出來
}
看起來非常容易,不是嗎?
我們先用剛剛瞭解的方式開啓了一個檔案代號,並且利用這個檔案代號聯繫到檔案"/var/log/messages"。在一些Unix係統中也許會看到這個檔案,它會紀錄一些使用者登入或是使用root權限的消息。而在這個檔案中,如果有使用者利用sudo這個指令進行某些操作時也會被記錄下來。因此我們就可以透過這個檔案知道伺服器上有些甚麽狀況正在發生。
接下來我們透過鑽石符號開始逐行讀取日志檔案中的資料,透過回圈while讀取檔案中的資料時,while會把所讀到的資料內容放進Perl的預設變數$_中,一直到檔案結束,傳回EOF時,回圈便會結束。因此我們就將所讀取的資料進行比對,以sudo這個關鍵字作為比對樣式,把符合的結果印出來。
這樣一來,衹要係統中有人使用sudo進行係統操作時,我們就可以檢查出來,而且印出來的結果會像是這樣:
TTY=ttyp0 ; PWD=/var/log ; USER=root ; COMMAND=/bin/rm -rf httpd-error.log
TTY=ttyp0 ; PWD=/var/log ; USER=root ; COMMAND=/bin/rm -rf httpd-access.log
TTY=ttyp0 ; PWD=/var/log ; USER=root ; COMMAND=/bin/rm -rf 192.168.1.1_access_log
192.168.1.1_error_log
TTY=ttyp0 ; PWD=/usr/home ; USER=root ; COMMAND=/bin/rm -rf interchange/
TTY=ttyp0 ; PWD=/usr/home ; USER=root ; COMMAND=/bin/rm -rf gugod/
TTY=ttyp0 ; PWD=/usr/home ; USER=root ; COMMAND=/bin/rm -rf mysql/
TTY=ttyp0 ; PWD=/ ; USER=root ; COMMAND=/bin/rm kernel.old
TTY=ttyp0 ; PWD=/ ; USER=root ; COMMAND=/bin/rm -rf modules.old/
TTY=ttyp0 ; PWD=/ ; USER=root ; COMMAND=/bin/rm -rf opt/
如果你是負責管理一些Unix的伺服器,利用這樣簡單的方式,確實可以幫忙你完成不少工作。很顯然,利用檔案的操作,你還可以進行更多對日志檔案的分析。例如你可以分析網站伺服器的各項資料,雖然其實已經有很多人用Perl幫你完成這樣的工作了。(註二)
基本上,從檔案內讀取內容的方式就是這麽容易,因此你可以簡單的運用檔案的內容進行所需要的工作。還記得我們在介紹open時的說明嗎?我們有幾個開啓檔案的方式包括了幾種描述子,例如大於(>),小於(<),以及兩個大於(>>)。而且我們也都簡單的描述過他們的差異,現在也許就是測試這些描述子的好時機,我們先來看看小於符號用於開檔的時候,會有甚麽影響。
我們之前也提過小於符號用在開檔作為描述的話,是用來表示從檔案內讀取資料。那我們是不是就衹能允許使用者讀取資料呢?先來看看這個小小的程式吧:
open LOG, "<log.txt" or die $!;
while (<LOG>) {
print $_;
}
print LOG "write to log" or die $!;
假設我們已經有了"log.txt"這個檔案,否則程式就會挂在中間,沒辦法繼續執行。那麽我們來看看執行結果吧:
file for log
Bad file descriptor at ch3.pl line 9, <LOG> line 1.
第一行就是原來log.txt裏面的內容,我們可以很輕鬆的讀出其中的資料,並且印出來,可是當我們要將資料寫入時,卻出現了錯誤訊息。沒錯,當初我們在開啓這個檔案時,衹要求Perl給我們一個可以讀出資料的檔案,如今要求寫入,果然就遭到拒絶。
看來一但我們使用了小於符號作為開啓檔案代號的描述子,那麽我們就不能輕易的把資料寫入所開啓的檔案中。想當然爾,Perl應該也不會讓我們在開啓一個利用大於符號指定為寫入的檔案中把資料讀出吧?要想測試這樣的結論,我們衹需要把剛剛的程式修改一個字元,也就是把小於符號改成大於,那麽就讓我們來看看執行後的結果吧:
我們嘗試着執行被我們修改了一個字元的程式,結果發生了甚麽事呢?檔案沒有輸出任何結果。好像很出乎意料?其實一點也不,而且正如Perl所要求我們的,我們使用了大於符號表明我們想要把資料寫入檔案log.txt,因此當我們想要從檔案讀取資料並且逐行印出結果時就無法成真。不過我們接下來去看看log.txt的內容。正如我們所預料的,程式已經正確的把字串"write to log"寫到檔案log.txt裏面了。
既然使用大於符號跟小於符號都符合我們的期待,那麽如果我們甚麽描述子都沒有使用,會是甚麽樣的情況呢?我們衹需要使用剛剛的測試程式,並且把描述子全部取消,再來試試結果如何吧!
結果我們發現,Perl還是可以讀出檔案的內容,可是卻無法寫入。也就是跟我們使用小於符號時是一樣的狀況,這點其實對於經常必須使用檔案的人來說其實是非常重要的。所以如果你有機會使用檔案的存取時,可別忘了這一點。
另外,大於符號與兩個大於的差別我們也曾經提過,這部份對於可能使用Perl來進行日常管理工作的人更是必須牢記。我們之前提過,一樣是開啓一個可以寫入的檔案,使用一個大於符號(>)的時候,Perl會判斷你是否已經有存在這個檔名的檔案,如果檔案已經存在,那麽Perl將會清空檔案內容,把他視作一個新的檔案來進行操作。如果在係統中檔案並不存在,那麽Perl就會跟係統要求開啓一個新的檔案。當然,在你使用兩個大於符號的時候,Perl會把你要寫入檔案的內容以附加的方式存入。當然,如果你的係統中並沒有這個檔案,那麽Perl也會先開啓一個新檔,並且把你所要求的內容寫入檔案中。這對於想要建立類似日志檔的需求有着絶對的幫助,例如你可能會需要Perl來作為監控網路的狀況,這時候你會需要每次有新狀況時就把它記錄下來,而且需要保留原來的紀錄。那麽如果你還是使用大於符號的話,你可就要小心原來的資料內容遺失了。
當然,我們知道開啓檔案時可以利用三種描述子去指定所要開啓檔案代號的狀態,不過如果你甚麽都沒加的狀況下,Perl又會作怎麽樣的處理呢?我們繼續用剛剛的例子來進行實驗吧。我們把開啓檔案的描述子拿掉,其他的部份一切照舊。所以你的程式就像這樣:
open LOG, "log.txt" or die $!;
print LOG "write to logn" or die $!;
接着我們發現,這樣的結果就跟我們使用小於符號的效果是相同的,也就是Perl衹會從檔案中讀出資料,卻無法寫入。
有了基本讀寫檔案的能力之後,我們還必須瞭解該怎麽樣透過Perl去控製係統的檔案以及資料夾。這樣才能確實掌握係統的檔案管理,尤其當你希望使用Perl來進行係統管理時,也就會更需要這樣的能力,所以我們接下來就要討論利用Perl對檔案係統的操作。
註一:不過當你打算這麽作的時候,也許要考慮這支程式未來衹有你在維護,否則你這樣的動作很可能會因為接下來維護的人需要花更多的時間來看懂程式而提高不少維護成本。
註二:其實跟這章主題不太有關,不過例如awstats就是這類型的工具。 | | 使用權限 : 所有使用者
使用方式 : chmod [-cfvR] [--help] [--version] mode file...
說明 : Linux/Unix 的檔案存取權限分為三級 : 檔案擁有者、群組、其他。利用 chmod 可以藉以控製檔案如何被他人所存取。
把計 :
mode : 權限設定字串,格式如下 : [ugoa...][[+-=][rwxX]...][,...],其中u 表示該檔案的擁有者,g 表示與該檔案的擁有者屬於同一個群體(group)者,o 表示其他以外的人,a 表示這三者皆是。
+ 表示增加權限、- 表示取消權限、= 表示唯一設定權限。
r 表示可讀取,w 表示可寫入,x 表示可執行,X 表示衹有當該檔案是個子目錄或者該檔案已經被設定過為可執行。
-c : 若該檔案權限確實已經更改,纔顯示其更改動作
-f : 若該檔案權限無法被更改也不要顯示錯誤訊息
-v : 顯示權限變更的詳細資料
-R : 對目前目錄下的所有檔案與子目錄進行相同的權限變更(即以遞回的方式逐個變更)
--help : 顯示輔助說明
--version : 顯示版本
範例 :將檔案 file1.txt 設為所有人皆可讀取 :
chmod ugo+r file1.txt
將檔案 file1.txt 設為所有人皆可讀取 :
chmod a+r file1.txt
將檔案 file1.txt 與 file2.txt 設為該檔案擁有者,與其所屬同一個群體者可寫入,但其他以外的人則不可寫入 :
chmod ug+w,o-w file1.txt file2.txt
將 ex1.py 設定為衹有該檔案擁有者可以執行 :
chmod u+x ex1.py
將目前目錄下的所有檔案與子目錄皆設為任何人可讀取 :
chmod -R a+r *
此外chmod也可以用數字來表示權限如 chmod 777 file
語法為:chmod abc file
其中a,b,c各為一個數字,分別表示User、Group、及Other的權限。
r=4,w=2,x=1
若要rwx屬性則4+2+1=7;
若要rw-屬性則4+2=6;
若要r-x屬性則4+1=7。
範例:
chmod a=rwx file
和
chmod 777 file
效果相同
chmod ug=rwx,o=x file
和
chmod 771 file
效果相同
若用chmod 4755 filename可使此程式具有root的權限
指令名稱 : chown
使用權限 : root
使用方式 : chmod [-cfhvR] [--help] [--version] user[:group] file...
說明 : Linux/Unix 是多人多工作業係統,所有的檔案皆有擁有者。利用 chown 可以將檔案的擁有者加以改變。一般來說,這個指令衹有是由係統管理者(root)所使用,一般使用者沒有權限可以改變別人的檔案擁有者,也沒有權限可以自己的檔案擁有者改設為別人。衹有係統管理者(root)纔有這樣的權限。
把計 :
user : 新的檔案擁有者的使用者 IDgroup : 新的檔案擁有者的使用者群體(group)-c : 若該檔案擁有者確實已經更改,纔顯示其更改動作-f : 若該檔案擁有者無法被更改也不要顯示錯誤訊息-h : 衹對於連結(link)進行變更,而非該 link 真正指嚮的檔案-v : 顯示擁有者變更的詳細資料-R : 對目前目錄下的所有檔案與子目錄進行相同的擁有者變更(即以遞回的方式逐個變更)--help : 顯示輔助說明--version : 顯示版本
範例 :
將檔案 file1.txt 的擁有者設為 users 群體的使用者 jessie :
chown jessie:users file1.txt
將目前目錄下的所有檔案與子目錄的擁有者皆設為 users 群體的使用者 lamport :
chmod -R lamport:users *
-rw------- (600) -- 衹有屬主有讀寫權限。
-rw-r--r-- (644) -- 衹有屬主有讀寫權限;而屬組用戶和其他用戶衹有讀權限。
-rwx------ (700) -- 衹有屬主有讀、寫、執行權限。
-rwxr-xr-x (755) -- 屬主有讀、寫、執行權限;而屬組用戶和其他用戶衹有讀、執行權限。
-rwx--x--x (711) -- 屬主有讀、寫、執行權限;而屬組用戶和其他用戶衹有執行權限。
-rw-rw-rw- (666) -- 所有用戶都有文件讀、寫權限。這種做法不可取。
-rwxrwxrwx (777) -- 所有用戶都有讀、寫、執行權限。更不可取的做法。
以下是對目錄的兩個普通設定:
drwx------ (700) - 衹有屬主可在目錄中讀、寫。
drwxr-xr-x (755) - 所有用戶可讀該目錄,但衹有屬主才能改變目錄中的內容
suid的代表數字是4,比如4755的結果是-rwsr-xr-x
sgid的代表數字是2,比如6755的結果是-rwsr-sr-x
sticky位代表數字是1,比如7755的結果是-rwsr-sr-t |
|
|