Perl命令行 -a參數(shù) -F參數(shù)
【上集回顧】
上次說到了-p與-n參數(shù),其實再加上之前學(xué)的-e參數(shù)已經(jīng)可以做很多事情了,但是為了方便,Perl還有這樣一對搭檔組合的參數(shù),就是-a和-F
【參數(shù)解釋】
-a : 將讀入的
$_進行分割,保存到@F列表之中,類似于split /分隔符/ , $_;而這個分隔符是由-F參數(shù)指定的,其實這個功能與awk工具相似
-F : 在添加
-a參數(shù)時候,指定分隔符(可以是正則表達式),如果不加好像是由空格作為分隔符,一般對其進行設(shè)置
實例說明
為了更加清晰的說明,還是舉例子吧,打開終端或者git for windows
輸入
# 例如我需要把來自管道的數(shù)據(jù)按照空格分隔成一個一個單元,存到列表里面
echo "qwe asd zxc" | perl -n -a -F"\s+"-e '
$" = "\n";
foreach my $item (@F){
print "$item\n";
}
'
--------------------------------------
# 輸出
qwe
asd
zxc
這次的例子要比之前的例子復(fù)雜一點,我來一一說明
-
echo在屏幕上打印出qwe asd zxc這個字符串,這字符串中間由空格分成三個部分,分別是qwe、asd、zxc -
echo的輸出進入管道 | - 被
perl逐行讀?。ㄒ驗橹挥幸恍?,所以直接讀完了) - 讀取的字符串賦值給
$_ -
$_被分割為三份(應(yīng)-a的要求,根據(jù)-F(注意雙引號是貼著-F參數(shù)的,中間沒有空格隔開)的指定的\s+(意思是按照一個或者多個空格或者制表符分隔,這里也可以改為" +"),將$_分割為三份)
qwe asd zxc
^ ^
| |
空格
# 根據(jù)空格來劃分 \s+ 表示如果有多個空格相連也一并視為一個整體
# 切割之后,空格都消失
/ /
qwe/asd/zxc 成為 @F中的元素 ('qwe','asd','zxc')
/ /
- 分隔的三份按照順序存在
@F列表中 - 遍歷
@F列表,將其中的內(nèi)容打印出來
其實你可能會說,用之前之前學(xué)的參數(shù)就夠了??!比如
echo "qwe asd zxc" | perl -n -e '
my @F = split /\s+/,$_;
$" = "\n";
print "@F\n";
'
那為什么要這樣做呢?其實在平常的文本中比沒有感覺到,在linux或者mac系統(tǒng)下面,有很多信息就是以文本的形式給出來的,而且中間一般都是用空格或者制表符分隔的,就比如使用df命令查看磁盤使用情況
df
------------------------------------------
# 輸出
Filesystem 1K-blocks Used Available Use% Mounted on
C:/Program Files/Git 104857596 63822260 41035336 61% /
D: 318168060 313664144 125465657 40% /d
E: 41942012 21699268 20242744 52% /e
可以看到很鮮明的由空格或者制表符分隔的信息形式。
問題來了,利用這兩個參數(shù),我們可以試著做一下事情
問題1:我需要將所有的盤符提取并打印出來?
來試一下
df | perl -n -a -F"\s+" -e '
print $F[0],"\n";
'
------------------------------------------
# 輸出
Filesystem
C:/Program
D:
E:
可是標(biāo)題行不是我想要的,怎么除去呢?
有多種方法
- 使用特殊變量
$.
$.意為當(dāng)前讀取的行數(shù)
df | perl -n -a -F"\s+" -e '
# 第一行就是標(biāo)題行了,直接跳過它
if($. == 1){
next;
}else{
print $F[0],"\n";
}
'
------------------------------------------
# 輸出
C:/Program
D:
E:
- 借助Linux命令
# awk中NR為內(nèi)置變量,與上面的perl中的 $. 變量意義相同,就是當(dāng)前讀取的行數(shù)
df | perl -n -a -F"\s+" -e '
print $F[0],"\n";
' | awk 'NR>1{print $0}'
------------------------------------------
# 輸出
C:/Program
D:
E:
注意:你發(fā)現(xiàn)在現(xiàn)實盤符的時候C:/Program Files/Git顯示的是不完整的,只顯示了C:/Program,也就是它被分隔了??!這里要說明一下,文件夾是可以使用空格的(特別是像windows下面的系統(tǒng)文件夾C:/Program Files,的確是很煩人),這個時候使用空格分隔則要小心,一般在linux和mac下面碰不到這種情況。這里為了演示更加方便,然后便于初次的講解,我把C盤排除掉。但是要是的確有需要加入C盤來進行處理也是可以進行的,只是有點復(fù)雜,這里我不敘述,在文章末尾我進行一下探討。
問題2:我要計算D盤和E盤總共已經(jīng)使用的磁盤的內(nèi)存(排除了C盤,原因見上述說明)
# 與上面一樣,還是將df命令的結(jié)果讀取進來,然后分隔成各個元素存到@F中去
df | perl -n -a -F"\s+" -e '
BEGIN{
$total = 0;
}
chomp;
# 排除C盤
if(m/^C:/){
next;
}
if($. == 1){
next;
}else{
$total = $total + $F[2];
}
END{
print "total use : $total\n";
}
'
----------------------------------------------------
# 輸出
total use : 335363412
上面用到了兩個特殊的代碼塊BEGIN{}和END{}
這兩個代碼塊在perl的單行程序中會經(jīng)常用到
說明一下它們兩個的作用
# 單行程序中的結(jié)構(gòu) # 流程解釋
_________________________________________________________
BEGIN{ | +++++++++ 讀取文件之前
代碼1; | + 代碼1 + 就運行代碼1
} | +++++++++ 只運行一次
|
| ---> ++++
| ---> +代+ 然后每次讀取一行
代碼2; | ---> +碼+ 運行一下代碼2
| ---> +2 +
| .... ++++
|
END{ | +++++++++ 最后文件讀取完畢
代碼3; | + 代碼3 + 運行代碼3
} | +++++++++ 只運行一次
_________________________________________________________
其實BEGIN{}與END{}塊放的順序和位置并不重要,也就是說可以這樣
# 形式1
BEGIN{
代碼1;
}
END{
代碼3;
}
代碼2;
------------------
# 形式2
END{
代碼3;
}
代碼2;
BEGIN{
代碼1;
}
------------------
# 形式3
代碼2;
BEGIN{
代碼1;
}
END{
代碼3;
}
其實除了這些由空格分隔的,我們平常使用的excel中的兩個格式也是由特定的字符分隔的
- CSV文件 : 由逗號分隔的文本文件
- TSV文件 : 由制表符分割的文本文件
對于這種文件,使用這兩個參數(shù)進行搭配,就省了很多事兒,是吧
# 例如一個文件 123.csv
# 新建一個txt文本文件,將后綴名改成csv就可以
# 內(nèi)容為
name,apple,banana,orange,grape,strawberry
color,red,yellow,orange,purple,red
- 示例1
目標(biāo):打印出第一列,也就是標(biāo)題
cat 123.csv | perl -n -a -F"," -e '
print "$F[0]\n";
'
# 輸出
name
color
- 示例2
目標(biāo):計算出現(xiàn)了多少種顏色
cat 123.csv | perl -n -a -F"," -e '
# 如果第一列是color就執(zhí)行代碼
if($F[0] eq 'color'){
# 將第一個元素給扔掉
shift @F;
for my $color (@F){
# 利用哈希對重復(fù)的顏色的合并
# 而不是簡單的記錄這個列表中有多少元素
# 因為存在重復(fù)的顏色
# 紅色是兩份,它的值為2
$hash{$color}++;
}
}
END{
# 使用scalar方法得到哈西鍵的個數(shù)
print "Total number of color type : ",scalar(keys %hash),"\n";
}
'
---------------------------------------------
# 輸出
Total number of color type : 4
- 示例3
目標(biāo):按照下面那樣的方式打印出來(之間是逗號相隔開),這個其實就是列表的翻轉(zhuǎn),這個例子稍微有點復(fù)雜,這個例子意義其實不大。但是結(jié)合了多個perl單行程序
name,color
apple,red
banana,yellow
orange,orange
grape,purple
strawberry,red
# 代碼開始
cat 123.csv | perl -n -a -F"," -e '
# 因為沒有去處換行符,所以每一個元素后面均會帶有回車符和換行符
# 這里將其除去
$F[-1] =~ s/\r*\n//;
my $title = shift @F;
my @items = @F;
my $item_num = scalar(@items) unless defined $item_num;
$title_num++;
# 列表里面的原始是有序的
# 用它來記錄有順序的title
push @title_list,$title;
# 哈希里面的元素是無序的
# 用它來記錄每個title對應(yīng)的該行的元素
$hash{$title} = \@items;
END{
$" = ",";
# 先輸出標(biāo)題行
print "@title_list\n";
# 然后打印出各個元素
for my $row (0..$item_num-1){
for my $key (@title_list){
print $hash{$key}->[$row];
print ",";
}
print "\n";
}
}
' | perl -p -e 's/,$//'
-----------------------------------------------------
# 結(jié)果
name,color
apple,red
banana,yellow
orange,orange
grape,purple
strawberry,red
補充說明
- -a與-F參數(shù)的順序不重要,但是一定要放在-e參數(shù)之前
- -F指定分隔符的時候后面的分隔符要貼著-F參數(shù),中間不要有空格之類,否則會報錯
探討
上面說到有時候文件夾會出現(xiàn)空格的情況,像上面出現(xiàn)的C:/Program Files/Git被分隔的情況
那這樣難道就沒有辦法來處理嗎?
再來看一下df的輸出結(jié)果
df
------------------------------------------
# 輸出
Filesystem 1K-blocks Used Available Use% Mounted on
C:/Program Files/Git 104857596 63822260 41035336 61% /
D: 318168060 313664144 125465657 40% /d
E: 41942012 21699268 20242744 52% /e
雖然按照空格來分隔可能有些行不通了,但是能不能轉(zhuǎn)換一下思維,按照字符串的數(shù)量來劃分
|-------------------|---------|---------|---------|----|----------|
Filesystem 1K-blocks Used Available Use% Mounted on
C:/Program Files/Git 104857596 63822260 41035336 61% /
D: 318168060 313664144 125465657 40% /d
E: 41942012 21699268 20242744 52% /e
可以看到每一列對應(yīng)的字符串長度(空格也會被計算)是一致的
來!試一試
# 這個時候不能直接用空格分隔了,得采用一些特殊的方法
# 設(shè)置行數(shù)
export col=1
df | perl -n -e '
BEGIN{
# 設(shè)置想要打印的列數(shù)
# 傳入環(huán)境中變量
$col = $ENV{'col'};
}
if($. == 1){
@title_slice = (22,11,11,11,5,11);
next;
}
my $offset = 0;
map {$offset+= $_} @F[0..$col-2] if $col-2 > 0;
print substr($_,$offset,$title_slice[$col-1]-1) =~ s/\s*(.+?)\s*/$1/r,"\n";
'
# 但是這樣需要人工去數(shù),也不是個好辦法
版權(quán)聲明:本文采用 知識共享署名-非商業(yè)性使用-禁止演繹 4.0 國際許可協(xié)議 (CC BY-NC-ND 4.0) 進行許可。