即時餵資料給程式吃 - 朝陽科技大學
文章推薦指數: 80 %
Perl 會把使用者敲在命令列上的參數放在@ARGV 陣列裡。
(熟悉C 語言的讀者請注意: 在perl 當中, $ARGV[0] 是第一個參數, 不是命令名稱) 程式執行方式(以count_arg 為例):
Perl語言
新手上路
基本要素
餵資料
常用句型
regexp
詳談變數
一語中的
副程式
模組
外界對話
附錄
參考資料
scripting
Windows
圖形介面
big-5碼
light
dark
我的部落格:
人權
玩具
快速跳到:
社群活動
本層目錄
上層目錄
此頁@朝陽
此頁@資管
English
即時餵資料給程式吃
範例程式
以下有三個範例程式,每個程式各有兩個版本。
兩版本功能完全相同,
只是讀取輸入資料的方式不一樣--「命令列參數版」
從命令列參數讀取資料;「癡癡地等版」則是在使用者下了命令,按了
enter之後,癡癡地等著使用者逐列輸入資料。
----------------------------------------------------------------------
左半是「命令列參數版」中間是註解右半是「癡癡地等版」
----------------------------------------------------------------------
#!/usr/bin/perl-w#!/usr/bin/perl-w
#名稱:length_arg#名稱:length_stdin
#功用:數每個輸入字串的長度#功用:數每個輸入字串的長度
usestrict;
my(
$str,#每個字串
);
foreach$str(@ARGV){#對每個字串..while(
兩種常用的資料輸入方式
為了讓我們寫的程式用起來更有彈性,
我們不喜歡把運算要用到的的所有輸入資料(例如要把那些數字拿來加總?)
寫死在程式裡,而是留給使用者在執行程式時再臨時決定。
這類「要執行程式時才決定的資料」,有兩種簡單的方法傳給程式。
其一是直接讀取命令列上,命令名稱後面的參數commandline
argument(如圖左半部,想像資料從方框的上面進來)。
Perl
會把使用者敲在命令列上的參數放在@ARGV陣列裡。
(熟悉C
語言的讀者請注意:在perl當中,$ARGV[0]是第一個參數,
不是命令名稱)程式執行方式(以count_arg為例):
./count_argapplebananaorange...pineapplepeach
若使用者下這個命令來執行我們的程式,我們在count_arg
程式內會發現$ARGV[0]裡面存著"apple",$ARGV[1]裡面存著"banana",
...Q:如何知道使用者在命令列上究竟敲入多少個參數?又,
請印出最後一個參數。
第二種方法是從standardinput標準輸入裝置讀入資料:
在使用者打完命令,按了enter之後,
我們的程式才癡癡地等著他從鍵盤上敲入資料,每列一筆。
(如圖右半部,
想像資料從方框的左邊進來)程式語法是while(
注意每列最後面有一個換列字元,
習慣上以chomp把它刪除。
程式執行方式(以count_stdin為例):
./count_stdin
(提示符號未出現,但其實並未當掉.使用者開始輸入資料)
apple
banana
orange
...
pineapple
peach
^d(使用者按著Ctrl鍵不放,再按一下d鍵,表示資料輸入完畢)
(在Windows下則是按^z,不按^d)
第二種做法看起來有點無厘頭("連個提示符號都沒有,
害我以為程式掛掉了!")但其實在某些場合比第一種方法方便--
因為有一些方法可以欺騙程式,讓它把其他東西當做是
「使用者從鍵盤上輸入的資料」,而所謂的「其他東西」,
未必需要真的辛苦地人工敲入!Shell
提供四種特殊符號讓我們改變資料的流向,方便我們欺騙程式。
首先,程式原本想要印到螢幕上的東西,
我們可以將它轉而存到一個檔案裡面,像這樣:length_argapple
bananaorange...pineapplepeach>len.txt這叫做
outputredirection輸出重新導向。
也可以說它的
standardoutput標準輸出裝置被重新導向了。
看到
>符號時,
你可以在心中想像右邊出去的管線被改灌入地下。
其次,程式原本想要從鍵盤上讀入的東西,
我們可以轉而從一個既存的檔案裡面抓出來餵它吃,像這樣:
sum_stdin
(一種方式是改用length_stdin;另一種方式是仍舊使用
length_arg...)
注意:
Q:與perl無關的題外話:為什麼以下執行方式,
前三者得到相同的結果;後二者得到相同的結果?提示:這些引號不是給
perl看的,而是給另外一個程式看的。
在你的perl程式接手之前,
它就已經視需要將引號剝掉了。
length_arggoodmorning
length_arg"good""morning"
length_arg'good''morning'
length_arg"goodmorning"
length_arg'goodmorning'
Q:length_arga.txt
所謂符合搜尋條件,
就是這一列上包含指定的字串。
(用命令列參數指定)例如下
./pgrep'200'就會將STDIN輸入的資料當中,含有'
200'子字串的那幾列印出來。
#!/usr/bin/perl-w
die"usage:pgreppattern"unless$#ARGV>=0;
while(
它甚至可以拿來搜尋複雜的字串,例如./pgrep
's9214[01].[13579]'印出所有包含"四技二A同學學號"
的那幾列。
這些表達複雜字串規則的特殊符號叫做RegularExpressions。
取得每列第k個欄位
下面這個程式get_field假設標準輸入裝置輸入的每列資料,
都以冒號分隔所有欄位,像這樣:
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/bin/sh
...
ckhung:x:1006:100:洪朝貴,T2.907,x4271:/home/ckhung:/bin/bash
(順便一提:這是/etc/passwd檔的內容,別人finger你的時候,
系統就是在這裡找到你的個人資料。
如果你希望別人finger你的時候,
秀出比較酷的資訊,可以下chfn指令。
又,題外話:
系統其實已經有一個類似的指令,請見cut(1))
get_field會抓出第1個欄位的資料。
(注意欄位號碼從第0
個欄位數起。
)又,如果你想抓其他欄位的話,
可以在命令列上放一個數字當做參數,像這樣:./get_field
4,則它會抓出第4個欄位,也就是"root","bin",...
"洪朝貴,T2.907,x4271"等等。
#!/usr/bin/perl-w
usestrict;
my($which,$i,$n,$c);
$which=($#ARGV>=0)?$ARGV[0]:1;
while(
例如./get_field
4可以用perl-ne'print((split/:/)[4],"\n")'
/etc/passwd來取代。
常用運算子
邏輯運算子andornot&&||!:Perl
的邏輯運算規則與C相同--都是採取short-circuit
evaluation,如果一長串andor的前半部算完時,
已經可以知道答案,它就會偷懶地省略計算後半部的工作。
例如if
($candies/$children<5and$children>2){...}有
bug(萬一要是$children等於零怎麼辦?);如果改成if
($children>2and$candies/$children<5){...}
就沒有問題了。
處理字串的運算子:
.可以連接字串,例如"concate"."nation"
的結果是"concatenation"
x可以複製字串,例如"Great!"x3的結果是
"Great!Great!Great!"
比較字串用lt(lessthan),le(lessequal),gt(greater
than),ge(greaterequal),eq(equal),ne(notequal).
搜尋子字串$x=~/.../
更詳細的討論,請見perlop(1)(<==這個的意思是下
man1perlop)
簡單流程控制
與一般語言一樣,perl提供以下幾個一看就懂的流程控制敘述:
if(EXPR){...}
if(EXPR){...}else{...}
if(EXPR){...}elsif(EXPR){...}elsif(EXPR){
...}...else{...}
while(EXPR){...}
比較特別的是unless(EXPR){...}"除非"。
如果頭昏,可以將它翻譯成if(not(EXPR)){...
}。
其中的EXPR是判斷條件,例如$i$min等等。
熟悉C語言的讀者請注意:
即使大括弧內只有一句話,大括弧還是不能省略。
上述所有句形都一樣。
另外還有先前學過的for,其實可以用while來模擬;foreach可以用
for來模擬.
有時需要打斷迴圈正常流程:
next這個迴圈的這一次剩下的部分不做了,
直接進入迴圈的下一次.(類似C語言中的continue)
last完全跳出這個迴圈,
不但這一次剩下的部分不做了,不論剩下多少次都不做了.(類似C
語言中的break)
這兩個命令還可以跳出外層的迴圈,不像C的continue與break,
只限於跳出最內層的迴圈.詳見perlsyn(1)中談論迴圈的label
的部分.
Perl裡面比較特別的是"英文式"寫法:在英文裡,
條件子句可以寫在主要子句前面,而意思其實沒有變。
例如:"Takethe
lefttrailifyouhearadogbarks."在perl裡面,
如果主要子句只有短短一句話,那麼也可以這樣寫.例如:
print$iif$i>0;#$i大於零才要印
print$iunless$i>0;#$i大於零就不印;其他情況都印
更詳細的討論,請見perlsyn(1)(<==這個的意思是下
man1perlsyn)
其他常識
遇到沒有看過的函數,可查手冊perlfunc(1)或perlop(1)
前面那篇是perl函數手冊;後面這篇是perl運算子手冊。
因為在
perl裡面,有些看起來像函數的東西其實是運算子,例如eq,x,cmp,
and,...等等。
比方說要查perl內的printf怎麼用,可以:下man
1perlfunc命令,然後打:斜線"/",乘方"^",七個空格,"printf",
然後按Enter。
見regularexpression
範例)
一個變數,如果未曾設定初始值,那麼它的初始值就是undef.
undef值出現在數學運算式當中時,perl把它當做0來看待;
出現在字串運算式當中,perl把它當做空字串來看待.
三元運算子(測試)?(成功值):(失敗值)先判斷
(測試)是否成立,若成立,則傳回(成功值),不然就傳回
(失敗值)
substr函數可以取出字串的一小段。
(指定從第幾個字元開始取,
總共要取幾個字元)注意:字元從第0個開始數起。
以後學split
函數或regularexpression程式可以簡潔許多,
你會發覺幾乎不太需要用到substr。
這個單元裡面的兩個小程式合起來,其實就已經可以做到這當中的"分析流量"一例的前半部:
./get_field
延伸文章資訊
- 1Why is $#ARGV 0? - perl - Stack Overflow
$#ARGV is the count of the array elements so the count of @ARGV here. It is 0 as arrays start at ...
- 2即時餵資料給程式吃 - 朝陽科技大學
Perl 會把使用者敲在命令列上的參數放在@ARGV 陣列裡。 (熟悉C 語言的讀者請注意: 在perl 當中, $ARGV[0] 是第一個參數, 不是命令名稱) 程式執行方式(以count_a...
- 3Processing command line arguments - @ARGV in Perl
Perl automatically provides an array called @ARGV, that holds all the values from the command lin...
- 4[Perl 筆記] 預設變數@ARGV - 叮咚- 痞客邦
學習記錄﹞- Perl – 預設變數預設變數: $_ , @_, @ARGV @ARGV: 存放命令列引數的陣列$#ARGV: 陣列最後一個索引值執行程式時後面.
- 5perl中$#ARGV是什么意思_bruce0532的博客
作为一个变量表示打印数字时默认的数字输出格式,后面加上ARGV又表示什么意思呢?遇到perl的问题首先查perldoc,在perlvar里查到关于@ARGV的一条: ...