Perl 6 - 解析命令行輸出

哦, 列, 你在哪里?

當(dāng) ramiroencinas 給 Perl 6 的生態(tài)系統(tǒng)增加 FileSystem::Capacity::VolumesInfo模塊的時(shí)候, 我說(shuō)他沒(méi)有添加 macOS 支持递胧。而當(dāng)我嘗試為這個(gè)模塊貢獻(xiàn)源代碼時(shí)我才發(fā)現(xiàn)知道一丟丟 Perl 6 的特性就能節(jié)省很多時(shí)間馍管。 FileSystem::Capacity::VolumesInfo 這個(gè)模塊所做的就是解析 df 命令的輸出, 它看起來(lái)長(zhǎng)這樣:

$ df -k -P
Filesystem                                  1024-blocks       Used Available Capacity  Mounted on
/dev/disk3                                   1219749248  341555644 877937604    29%    /
devfs                                               343        343         0   100%    /dev
/dev/disk1s4                                  133638140  101950628  31687512    77%    /Volumes/Untitled
map -hosts                                            0          0         0   100%    /net
map auto_home                                         0          0         0   100%    /home
map -fstab                                            0          0         0   100%    /Network/Servers
//Pawel%20Pabian@biala-skrzynka.local./Data  1951417392 1837064992 114352400    95%    /Volumes/Data
/dev/disk5s2                                 1951081480 1836761848 114319632    95%    /Volumes/Time Machine Backups
bbkr@localhost:/Users/bbkr/foo 123           1219749248  341555644 877937604    29%    /Volumes/osxfuse

(如果你看到了折行的或者截?cái)嗟妮敵稣?qǐng)?jiān)谶@兒核對(duì)一下原始數(shù)據(jù))

雖然這對(duì)人類(lèi)來(lái)說(shuō)看起來(lái)不錯(cuò), 但是對(duì)于解析器來(lái)說(shuō)十一個(gè)棘手的任務(wù)。

  • 列的寬度是動(dòng)態(tài)的 - 所以每列的值不能使用帶有硬編碼位置的子字符串來(lái)提取椅贱。
  • 列和列之間是通過(guò)空白分割的, 空白被填充到列與列之間, 并且它們的值也能包含空白 - 所以不能通過(guò)空白使用 split 函數(shù)來(lái)提取值恨狈。
  • 文件系統(tǒng)的名字擁有不同的轉(zhuǎn)義模式妆棒。
  • 有些列是左對(duì)齊的, 有些列是右對(duì)齊的, 有一列是居中對(duì)齊的幻锁。

所以讓我們來(lái)使用 Perl 6 中的特性來(lái)處理這混雜的東西。

捕獲命令行輸出

my ($header, @volumes) = run('df', '-k', '-P', :out).out.lines;

方法 run 執(zhí)行 shell 命令并返回 Proc對(duì)象辐真。方法 out 創(chuàng)建一個(gè) 管道對(duì)象以接收 shell 命令的輸出须尚。方法 lines 把該輸出按行分割, 第一行保存到 $header 變量中, 剩下的行保存到 @volumes 數(shù)組中。

解析 header

my $parsed_header = $header ~~ /^
    ('Filesystem')
    \s+
    ('1024-blocks')
    \s+
    ('Used')
    \s+
    ('Available')
    \s+
    ('Capacity')
    \s+
    ('Mounted on')
$/;

我們這樣做是因?yàn)槠ヅ鋵?duì)象保存了每個(gè)捕獲, 并且每個(gè)捕獲都知道它所匹配的開(kāi)始位置和結(jié)束位置, 舉個(gè)例子:

say $parsed_header[1].Str;
say $parsed_header[1].from;
say $parsed_header[1].to;

會(huì)返回:

1024-blocks
44
55

那會(huì)在動(dòng)態(tài)列寬問(wèn)題上幫助我們很多!

提取每行的值

首先我們必須要查看 FileSystem 和 1024-blocks 這兩列之間的邊界侍咱。因?yàn)?FileSystem 是左對(duì)齊的而 1024-blocks 是右對(duì)齊的, 所以?xún)闪兄械臄?shù)據(jù)都占據(jù)那些 headers 之間的空白, 舉個(gè)例子:

Filesystem                      1024-blocks
/dev/someverybigdisk        111111111111111
me@host:/some directory 123    222222222222
         |                      |
         |<----- possible ----->|
         |<--- border space --->|

我們不能簡(jiǎn)單地按空白分割耐床。但是我們知道 1024-blocks 這一列在哪里結(jié)束, 所以結(jié)束在和 1024-blocks 同一位置的那個(gè)數(shù)字就是我們的容量大小(volume size)。要提取它, 我們可以使用另外一個(gè)有用的 Perl 6 特性 - 正則表達(dá)式位置錨點(diǎn)(regexp position anchor)楔脯。

for @volumes -> $volume {
    $volume ~~ / (\d+) <.at($parsed_header[1].to)> /;
    say 'Volume size is ' ~ $/[0] ~ 'KB';
}

它查找對(duì)齊于 header 末端位置的數(shù)字序列撩轰。每個(gè)其它的列都能使用這個(gè)花招來(lái)提取, 如果我們知道那個(gè)數(shù)據(jù)準(zhǔn)線的話。

$volume ~~ /
    # first column is not used by module, skip it
    \s+

    # 1024-blocks, 右對(duì)齊
    (\d+) <.at($parsed_header[1].to)>

    \s+

    # Used, 右對(duì)齊
    (\d+) <.at($parsed_header[2].to)>

    \s+

    # Available, 右對(duì)齊
    (\d+) <.at($parsed_header[3].to)>

    \s+

    # Capacity, 居中對(duì)齊, 不會(huì)比 header 還長(zhǎng)
    <.at($parsed_header[4].from)>
        \s* (\d+ '%') \s*
    <.at($parsed_header[4].to)> 

    \s+

    # Mounted on, 左對(duì)齊
    <.at($parsed_header[5].from)>(.*)
$/;

益處!

通過(guò)在正則表達(dá)式中使用 header 名字的位置和位置錨點(diǎn)我們?cè)?macOS 上得到了防炸的 df 解析器, 它能工作在普通的磁盤(pán), 隨身存儲(chǔ)器, NFS / AFS / FUSE 共享, 古怪的目錄名和不同的轉(zhuǎn)義模式中。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末堪嫂,一起剝皮案震驚了整個(gè)濱河市偎箫,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌皆串,老刑警劉巖淹办,帶你破解...
    沈念sama閱讀 212,816評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異恶复,居然都是意外死亡怜森,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,729評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén)寂玲,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人梗摇,你說(shuō)我怎么就攤上這事拓哟。” “怎么了伶授?”我有些...
    開(kāi)封第一講書(shū)人閱讀 158,300評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵断序,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我糜烹,道長(zhǎng)违诗,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,780評(píng)論 1 285
  • 正文 為了忘掉前任疮蹦,我火速辦了婚禮诸迟,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘愕乎。我一直安慰自己阵苇,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,890評(píng)論 6 385
  • 文/花漫 我一把揭開(kāi)白布感论。 她就那樣靜靜地躺著绅项,像睡著了一般。 火紅的嫁衣襯著肌膚如雪比肄。 梳的紋絲不亂的頭發(fā)上快耿,一...
    開(kāi)封第一講書(shū)人閱讀 50,084評(píng)論 1 291
  • 那天,我揣著相機(jī)與錄音芳绩,去河邊找鬼掀亥。 笑死,一個(gè)胖子當(dāng)著我的面吹牛妥色,可吹牛的內(nèi)容都是我干的铺浇。 我是一名探鬼主播,決...
    沈念sama閱讀 39,151評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼鳍侣!你這毒婦竟也來(lái)了丁稀?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,912評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤倚聚,失蹤者是張志新(化名)和其女友劉穎线衫,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體惑折,經(jīng)...
    沈念sama閱讀 44,355評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡授账,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,666評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了惨驶。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片白热。...
    茶點(diǎn)故事閱讀 38,809評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖粗卜,靈堂內(nèi)的尸體忽然破棺而出屋确,到底是詐尸還是另有隱情,我是刑警寧澤续扔,帶...
    沈念sama閱讀 34,504評(píng)論 4 334
  • 正文 年R本政府宣布攻臀,位于F島的核電站,受9級(jí)特大地震影響纱昧,放射性物質(zhì)發(fā)生泄漏刨啸。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,150評(píng)論 3 317
  • 文/蒙蒙 一识脆、第九天 我趴在偏房一處隱蔽的房頂上張望设联。 院中可真熱鬧,春花似錦灼捂、人聲如沸仑荐。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,882評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)粘招。三九已至,卻和暖如春偎球,著一層夾襖步出監(jiān)牢的瞬間洒扎,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,121評(píng)論 1 267
  • 我被黑心中介騙來(lái)泰國(guó)打工衰絮, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留袍冷,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,628評(píng)論 2 362
  • 正文 我出身青樓猫牡,卻偏偏與公主長(zhǎng)得像胡诗,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,724評(píng)論 2 351

推薦閱讀更多精彩內(nèi)容