1. 輸入與輸出
1.1 從標準輸入設備輸入
由於,行輸入操作在到達文件的結尾時將返回undef,這對於從循環退出時非常方便的:
while (defined($line = <STDIN>)) {
print “I saw $line”;
}
可以這樣簡寫:
while(<STDIN>){
print “I saw $_”;
}
下面這個東西和上面表面上沒有區別,實際上它是先得到列表的所有元素再打印的,這樣如果是文件很大,就很浪費資源,而上面的就很好,動態利用內存,一個元素一個元素的處理。
foreach(<STDIN>){
print “I saw $_”;
}
1.2 從<>輸入
$ ./my_program fred barney betty
上述命令的含義是,運行my_program(在當前目錄下),它將處理文件fred,再處理文件barney,最後是文件betty。
如果沒有命令行參數,程序將處理標準輸入流(standard input stream)。作爲一個特例,如果將連接號(-)作爲一個參數,其
含義也是標準輸入◆。如果調用參數爲fred –betty,其含義是程序將首先處理文件fred,其次是標準輸入流,最後是文件betty。
while (defined($line = <>)){
chomp($line);
print “It was &line that I saw!/n”;
}
應該想得到,<STDIN>代表標準輸入,那麼<>就應該代表所有有可能的輸入,可以是文件,可以是標準輸入。
可以簡化的很牛逼:
while(<>){
chomp;
print “It was $_ that I saw!/n”;
}
1.3 調用參數
實際上,<>從數組@ARGV 中得到調用參數。這個數組是Perl 中的一個特殊數組,其包含調用參數的列表。那程序名存在哪裏了呢?和shell差不多,在$0裏面。
@argv = qw# larry mor curly #; #強制使用這三個文件
while(<>){
chomp;
print “It was $_ that I saw in some stooge-like file!/n”;
}
1.4 Print輸出到標準輸出
print @array; #打印出元素的列表
print “@array”; #打印一個字符串(包含一個內插的數組)
第一個語句打印出所有的元素,一個接着一個,其中沒有空格。第二個打印出一個元素,它爲@array 的所有元素,其被存在一個字符串中。也就是說,打印出@array 的所有元素,並由空格分開◆。如果@array 包含qw /fred barney betty /◆,則第一個例子輸出爲:fredbarneybetty,而第二個例子輸出爲fred barney betty(由空格分開)。
例子:
#!/usr/bin/perl
@array = <STDIN>;
print @array;
print "@array";
輸出:
legend@ubuntu:~/data/study/perl$ perl 5.4
legend1
legend2
legend3
legend1
legend2
legend3
legend1
legend2
legend3
其中前三項是我自己的輸入,之後是ctrl+d結束輸入。後面六個是程序輸出。由於他們是unchomp的,所以每個元素後面都有換行。注意最後兩個空格,是數組作爲字符串時系統自動添加的。
所以如果,字符串包含換行符,如果想輸出它們,通常:
print @array;
如果不包含換行符,通常想加上一個:
print “@array/n”;#注意之前說過的它與print @array.”/n”;的區別
由於print 需要一些輸出的字符串列表,則其參數是作爲列表context 來求值的。由於<>操作返回的是列表,則它們可很好
的一起工作:
print <>; # ‘cat’的源程序
print sort <>; #‘sort’的源程序
print 的括號在不影響語義的情況下是可選的
print (“Hello, world!/n”); #真實語義是將print作爲函數調用
pirnt “Hello, world!/n” #真實語義是將print後面的所有東西當作列表打印
所以:print (2+3)*4; #oops!結果是打印了5,丟了運行結果4,因爲此時print是系統調用,相當於(print (2+3)) * 4;
1.5 使用printf 格式化輸出
printf “Hello, %s; your password expires in %d days!/n”,
$user, $days_to_die;
print “in %d days!/n”,17.85; #in 17 days!
printf “%6f/n”, 42; #輸出爲○○○○42(○此處指代空格)
printf “%23/n”,2e3+1.95; #2001
printf “%10s/n”, “wilma”; #輸出爲:○○○○○wilma
print “%-15s/n”, “flintstone”; #輸出爲flintstone○○○○
%f 根據需要進行截尾,你可以設置需要幾位小數點後面的數字:
printf “%12f/n”, 6*7 + 2/3; #輸出爲: ○○○42.666667
printf “%12.3f/n”, 6*7 + 2/3; #輸出爲: ○○○○○○42.667
printf “%12.0f/n”, 6*7 + 2/3; #輸出爲: ○○○○○○○○○○43
下面一個例子好好理解printf和print的區別
#!/usr/bin/perl
printf "i want to see%%dlegend/n",23; #輸出%的正確方法
printf "i want to see/%dlegend/n",23;#別以爲和c語言一樣,此時應該特別注意
printf "i want to see %d and %s/n",23;#內容不夠,則省
printf "i want to see %d and %s/n",23,43,212;#格式符不夠則省
結果:
legend@ubuntu:~/data/study/perl$ perl 5.5
i want to see%dlegend
i want to see23legend
i want to see 23 and
i want to see 23 and 43
1.5.1.數組和printf
my @items = qw( wilma dino pebbles );
my $format = “The items are:/n”. (“%10s/n”x @items);
## print“the format is >>$format<</n”; #用於調試
printf $format, @items;
printf“The items are:/n”. (“%10s/n”x @items), @items;
1.6 句柄
Perl 自身有六個文件句柄:STDIN,STDOUT,STDERR,DATA,ARGV,ARGVOUT
$ ./your_program <dino >Wilma
上述命令告訴shell,從一個名叫dino 讀入,將結果輸出到叫做wilma 的文件之中。由於程序從STDIN 讀入,處理它(按照我們的要求),再輸出到STDOUT,上述代碼將能很好工作。
$ cat fred barney | sort | ./your_program | grep something | lpr
1.7 文件句柄的打開
open CONFIG, “dino”;
open CONFIG, “<dino”; #和上者一樣,因爲<是可以缺省的
open BEDROCK, “>fred”;#把文件fred當作標準輸出
open LOG,“>>logfile”;#不是新建一個文件或者清空這個文件,而是從後面追加
可以在文件名的地方使用任何的標量表達式,雖然通常你可能不想這樣做:
my $selected_output = “my_output”;
open LOG,“> $selected_output” #當$selected_output 爲“>passwd”,則它將
變成追加。
Perl 的新版本中(從Perl5.6 開始),open 支持“3 參數”類型:
open CONFIG, “<”, “dino”;
open BEDROCK, “>”, $file_name;
open LOG, “>>”, &logfile_name();
這種方法的優點是Perl 不會將模式(第二個參數)和文件的名字(第三個參數)混淆,這能增加安全性
1.7.1.Bad 文件句柄
如果從一個bad 文件句柄讀入(文件句柄沒有恰當的打開),會立刻到達文件結尾(end-of-file)。如果寫到一個bad 文件句柄,數據會被悄悄地丟掉。
如何判斷文件句柄是否被正確地打開?
-w可以給予警告
也可以用open調用的返回值判斷
my $success = open LOG, “>>logifle”; #將返回值保存在$success 中
if(!$success){
#打開失敗時
...
}
1.7.2.關閉文件句柄
close BEDROCK;
當關閉文件句柄時,Perl 將告訴操作系統已經結束了對此數據流的操作,因此應當將輸出的數據寫到磁盤中,如果程序重新打開它(也就是說,使用open 重新打開此文件句柄),或者退出程序,Perl 將自動關閉文件句柄。
如果希望程序更加整潔,則每一個open 都應當使用一個close。通常,最好在不使用一個文件句柄時就立刻將它關閉,無論程序是否立即結束
1.8 嚴重錯誤和die
die 函數將打印出你給它的消息(利用標準錯誤流),並確保程序退出時爲非零(nonzero)的退出狀態(exit status)
if(!open LOG, “>>logfile”){
die “Cannot create logfile:$!”;
}
如果open 失敗,則die 將結束程序,通常,當系統拒絕了我們的請求(如打開文件),$!將告訴你原因(可能是“權限不夠(permission denied)”或者“(文件不存在)file not found”,針對本例)
也可以不用打印系統輸出,因爲有時根本就沒有系統錯誤輸出
if(@ARGV < 2){
die “Not enough arguments/n”;
}
1.9 警告信息和warn
warn 函數像die 那樣工作,除了最後一步,它不會從程序中退出。
1.10 使用文件句柄
讀入:
if(! open PASSWD, “/etc/passwd”){
die “How did you get logged in?($!)”;
}
while(<PASSWD>){
chomp;
...
}
輸出:
寫出(>)或追加的(>>)的文件句柄,可以和print 或printf 結合使用,如:
print LOG “Captain’s log, stardate 3.14159/n”; #輸出到LOG 中
printf STDERR “%D percent complete./n”, $done/$total * 100;
printf (STDERR “%d percent complete./n”, $done/$total * 100);
printf STDERR (“%d percent complete./n”, $done/$total * 100);
都是正確的
1.10.1. 改變默認的輸出句柄
默認情況下,如果不指定文件句柄給print(或者printf,這裏的內容對兩者均適用),則默認會使用STDOUT。但這個默認屬性,可以通過select 操作進行更改。如下:
select BEDROCK;
print “I hope Mr. Slate doesn’t find out about this./n”;
print “Wilma!/n”
以後的print都受影響,因此要及時恢復回去,用select STDOUT;
$| = 1; #don’t keep LOG entries sitting in the buffer,設置它爲1可以讓print語句執行之後立即將文件句柄的內容寫入文件
select STDOUT;
#...time passes, babies learn to work, tectonic plates shift, and then … .
print LOG “This gets written to the LOG at once!/n”;
1.11 重新打開文件句柄
if(! Open STDERR, “>>/home/barney/.error_log”){
die “Can’t open error log for append: $!”;
}
因爲STDERR默認打開的,所以立即關閉了原有的STDERR,而用新的日誌文件替換了