2017-04-06 63 views
16

這個腳本搜索文字的線條和打印他們,而(),而重讀源文件中的每個迭代全球正則表達式匹配在反引號結果

# cat mm.pl 
#!/usr/bin/perl 
use strict; 
use warnings; 

while(`cat aa` =~ /(\w+)/g) { 
    print "$1\n"; 
} 

輸入文件:

# cat aa 
aa 
bb 
cc 

結果:

# ./mm.pl 
aa 
bb 
cc 

請解釋爲什麼運行腳本t不是無窮無盡

在每迭代正則表達式引擎偏移,因爲表達的變化,否則重置(新分叉)。

我想perl做一些類型的緩存爲的結果,但使用strace聲稱被催生4次(3爲3條線+ 1爲假,而條件):

# strace -f ./mm.pl 2>&1 | grep cat | grep -v ENOENT 
[pid 22604] execve("/bin/cat", ["cat", "aa"], [/* 24 vars */] <unfinished ...> 
[pid 22605] execve("/bin/cat", ["cat", "aa"], [/* 24 vars */] <unfinished ...> 
[pid 22606] execve("/bin/cat", ["cat", "aa"], [/* 24 vars */] <unfinished ...> 
[pid 22607] execve("/bin/cat", ["cat", "aa"], [/* 24 vars */] <unfinished ...> 

在另一方面,下面的例子一直運行

# cat kk.pl 
#!/usr/bin/perl 
use strict; 
use warnings; 

my $d = 'aaa'; 
while($d =~ /(\w+)/g) { 
    print "$1\n"; 
    $d = 'aaa'; 
} 

哪裏是兩個腳本之間的差異?我錯過了什麼?

+3

這是個不錯的問題 – Zaid

+4

對於那些沒有strace的人,你可以使用這個bash腳本'mycat'作爲'for i in aa bb cc;做回聲「$ {i} _ $ BASHPID」; (''chmod 755 mycat')。它會爲每個循環顯示不同的'$ BASH_PID'。 :) – jm666

+1

也許backtick重用相同的內存緩衝區,並愚弄/ g認爲它是相同的字符串。 – BOC

回答

7

//g中止的位置以添加到執行匹配的標量的魔力形式存儲。

$ perl -MDevel::Peek -e'$_ = "abc"; Dump($_); /./g; Dump($_);' 
SV = PV(0x32169a0) at 0x3253ee0 
    REFCNT = 1 
    FLAGS = (POK,IsCOW,pPOK) 
    PV = 0x323bae0 "abc"\0 
    CUR = 3 
    LEN = 10 
    COW_REFCNT = 1 
SV = PVMG(0x326c040) at 0x3253ee0 
    REFCNT = 1 
    FLAGS = (SMG,POK,IsCOW,pPOK) 
    IV = 0 
    NV = 0 
    PV = 0x323bae0 "abc"\0 
    CUR = 3 
    LEN = 10 
    COW_REFCNT = 2 
    MAGIC = 0x323d050 
    MG_VIRTUAL = &PL_vtbl_mglob 
    MG_TYPE = PERL_MAGIC_regex_global(g) 
    MG_FLAGS = 0x40 
     BYTES 
    MG_LEN = 1 

這意味着行爲觀察到的唯一途徑是有可能在反引號例子是,如果對同一標相匹配的匹配運算符的所有四次有人評價過!這怎麼可能?這是因爲反引號是使用TARG的運營商之一。

創建一個標量是相對昂貴的,因爲它需要多達三個內存分配!爲了提高性能,稱爲TARG的標量與某些運營商的每個實例相關聯。對具有TARG的操作員進行評估時,可以使用要返回的值填充TARG並返回TARG(而不是分配和返回新的)。

「那麼是什麼?」,你可能會問。畢竟,您已經證明,分配給標量會重置與該標量關聯的匹配位置。這就是想要發生的事情,但它不適用於反引號。

魔法不僅可以將信息附加到一個變量,它還附加在某些條件下被調用的函數。 //g添加的魔法附加了一個函數,該函數在標量被修改後(在上面的轉儲中由SMG標誌指示)將被調用。這個函數是當一個值被分配給標量時清除位置的東西。

賦值運算符正確處理魔法,但不是由反引號操作符處理。它不希望魔法被添加到它的TARG中,所以它不檢查是否有魔法,所以清除匹配位置的函數不會被調用。

+0

聽起來像bug報告給我。 –

+0

@ Oleg V. Volkov,這是一個bug,但我無法弄清楚修復它的好處。我無法弄清楚它會造成傷害的情況,它實際上有助於OP的案例 – ikegami

+0

@ikegami雖然它有幫助,但它也令人困惑。無盡的循環似乎是天真的期望。 –