2017-04-06 12 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が結果のキャッシュのいくつかの種類がないと思ったが、を4回(偽のために3×3の行+ 1条件ながら)生み出したことをstraceの主張:オン

# 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'; 
} 

どこに2つのスクリプトの違いはありますか?私は何が欠けていますか?

+3

これはいい質問です – Zaid

+4

straceなしで、このbashスクリプト 'mycat'を' for a i in aa bb cc;として使うことができます。 echo "$ {i} _ $ BASHPID"; done'(ofc 'chmod 755 mycat')です。ループごとに異なる '$ BASH_PID'を表示します。 :) – jm666

+1

おそらくバックティックは同じメモリバッファを再利用しており、/ 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 

これはマッチ演算子は、同じスカラに対してそれが評価された4つのすべての回にマッチした場合に観察された行動は、バッククォートの例では可能である唯一の方法があることを意味します!そんなことがあるものか?なぜなら、バックティックは、TARGを使用する演算子の1つです。

スカラーの作成は、3つまでのメモリー割り当てが必要なため、比較的高価です。パフォーマンスを向上させるために、TARGというスカラーがいくつかの演算子の各インスタンスに関連付けられています。 TARGを持つオペレータが評価されると、TARGに値を代入して(新しいものを割り当てて返すのではなく)TARGを返して返すことがあります。

「だから何?」と聞くかもしれません。結局のところ、既にスカラーに代入すると、そのスカラーに関連付けられたマッチ位置がリセットされることが実証されています。それは起こると思われることですが、バックティックではありません。

マジックは、情報を変数に添付できるだけでなく、特定の条件のもとで呼び出す関数もアタッチします。 //gによって追加された魔法には、スカラーが修正された後に呼び出されるべき関数が添付されています(上のダンプのSMGフラグによって示されています)。この関数は、値がスカラーに割り当てられたときに位置をクリアするものです。

割り当てオペレータは、マジックを正しく処理しますが、バックティックオペレータは正しく処理しません。マジックがTARGに追加されているとは思わないので、マジックがあるかどうかはチェックされないので、マッチ位置をクリアする関数は呼び出されません。

+0

私にはバグのように聞こえます。 –

+0

@Oleg V. Volkov、それはバグですが、私はそれを修正することの利点を理解することはできません。私はそれが害を及ぼす状況を理解することができず、それは事実上OP事件で手助けをした。 – ikegami

+0

@ikegami助けたが、それはまた混乱している。無限のループが未来の期待のようです。 –

関連する問題