2011-12-29 84 views
2

我有一個Perl腳本,它可以在HPUX 11i v3上的Perl 5.005下正常運行,並且在我的Ubuntu 11.04盒子的Perl 5.10下會導致一個小問題。爲什麼Perl在這裏抱怨一個未終止的字符串?

它歸結爲這樣一行:

open (CMD, "do something | grep -E 'sometext$' |"); 

(它實際上捕捉ps -ef輸出,看是否有進程在運行,但我不認爲這很重要(一))。

現在這個運行在HP-UX環境很好,但是,當我嘗試一下在Ubuntu下,我得到:

sh: Syntax error: Unterminated quoted string 

通過插入豐富的調試語句,我跟蹤它到該問題的行,然後開始刪除字符一個接一個,直到它停止抱怨。幸運的是,$曾是我的第一個,它停止了給我的錯誤,所以後來我改了行到:

open (CMD, "do something | grep -E 'sometext\$' |"); 

它工作得很好(Linux下反正 - 我沒有測試過,關於HPUX自我今天無法訪問那臺機器 - 如果它工作正常,我會用這種方法,但我仍然想知道爲什麼它是一個問題)。

所以看起來很明顯,$是「吞嚥」在我的Linux環境下的結束單引號,但顯然不是在HPUX上。

我的問題很簡單,爲什麼?當然在5.005和5.10之間沒有任何大的變化。或者是否有某種我缺少的配置項?


(一)但是,如果你知道一個更好的方式來做到這一點沒有外部CPAN模塊(即,只有基線的Perl 5.005安裝),我很樂意去了解它。

+1

「當然有不5.005和5.10之間的巨大變化,」這十一點滄桑。這兩個版本之間有一些變化。看看各種perldelta手冊頁。 – 2011-12-29 08:49:36

回答

7

$'是一個特殊的變量(見perldoc perlvar)。 5.005之前是很多版本的,所以有可能在正則表達式引擎中改變了一些東西,使這個變量不同(儘管看起來也是5.005)

至於更好的方法,至少只能運行' ps -ef'並在perl中執行'grep'。

+0

實際上,(Perl中的grep位)可能會更好,因爲它會調用更少的外部進程,並且PCRE將在不同的UNIX中通用。我假設Perl中的RE是PC :-) – paxdiablo 2011-12-29 01:36:35

3

因爲$'是最近版本的Perl中的一個特殊變量。

從官方文檔(perlvar):

$': 以下任何由上次成功 模式匹配(不包括隱藏在塊或 的eval(在任何比賽)的封閉匹配的字符串目前的BLOCK)。

如果沒有成功的模式匹配,$'是空的,你的發言基本上是插值到

open (CMD, "do something | grep -E 'sometext |"); 

逃離美元符號(即你可以在Linux的解決方案)應該在HPUX工作了。

我不確定這個變量何時添加,但我可以確認它存在於Perl 5.8.5中。 What's New for Perl 5.005提到$'(不是一個新功能),所以我認爲它已經在那之前。

+2

是的,但'$''是舊版和新版Perl中的一個特殊變量(甚至可能是Perl 4.x);從5.005到5.10的變化有點令人費解。 OTOH,5.005非常古老。 – 2011-12-29 01:18:29

2

你或許應該使用單引號,而不是雙引號括起來的周圍,因爲沒有任何字符串中應該進行插值:

open (CMD, q{do something | grep -E 'sometext$' |}); 
更好

是使用的open 3個參數的形式詞法文件句柄:

open my $cmd, '-|', q{do something | grep -E 'sometext$'} or die 'a horrible death'; 

我沒有爲什麼$'被確認爲5.10特殊變量一個很好的解釋,但它是不是在5.005。這是意想不到的。

是否有一個很好的理由,你不能升級到5.14.1?即使您不更改系統提供的Perl,也沒有明顯的原因,您不能在其他位置安裝最新版本,並將其用於所有腳本工作。

+0

你可能是對的。它看起來像HPUX 11.0是第一個發佈Perl和5.6。 11.3看起來像5.8版本,我可以用它作爲我的基準。我正在開發的構建機器可能是一箇舊版本,其中操作系統已更新,但不是Perl。由於我們必須分發和安裝任意版本,所以安裝任意版本......對公司來說是不大可能的,因爲我們不得不分發和安裝它,而不是讓客戶自己獲取和安裝。儘管如此,我仍然會進行調查,並且很可能會提供我們可以使用的最新Perl版本,這些版本在最新版本的Solaris/AIX/HPUX/RHEL/SLES中很常見。乾杯。 – paxdiablo 2011-12-29 01:29:19

1

$'是一個特殊變量。

如果你想避免變量擴展,只需要使用q()

open (CMD, q(do something | grep -E 'sometext$' |)); 
4

無論是否爲defined,任何標點符號(在標準鍵盤上)後面的印記都是Perl中的變量。因此,在雙引號字符串[[email protected]][symbol]將始終被讀作一個標記並插入,除非該標記被轉義。

我有一種感覺,你所看到的差異與不同的系統shell而不是不同版本的perl有關。

考慮您的線路:

open (CMD, "do something | grep -E 'sometext$' |"); 

當perl的看到,它會插空$'變量輸入到雙引號字符串,因此字符串變成:

open (CMD, "do something | grep -E 'sometext |"); 

在這一點上,你的殼得到處理如下的線:

do something | grep -E 'sometext 

而且如果它的成功或失敗將取決於shell關於未終止字符串的規則(一些shell會大聲抱怨,其他的會在eof自動終止字符串)。

如果您在腳本中使用warnings編譯指示,您可能會收到有關插入未定義變量的警告。


更短和更清潔的方式在ps輸出讀會:

my @lines = grep /sometext\$/, `ps -ef`; 

或者使用一個明確的開放:

my @lines = grep /sometext\$/, do { 
    open my $fh, '|-', 'ps -ef' or die $!; 
    <$fh> 
}; 
+0

其實,這是一個很好的可能性。 HPUX使用ksh,而我的Ubuntu使用bash。 – paxdiablo 2011-12-29 04:13:56

+0

@paxdiablo:嚴格地說,默認的HP-UX shell是一個類似於ksh的Posix shell,作爲動態鏈接的可執行文件提供 -/usr/bin/sh和靜態鏈接的 -/sbin/sh。 HP將Korn88 ksh shell作爲/ usr/bin/ksh和Korn93 shell作爲/ usr/dt/bin/dtksh運送。 – JRFerguson 2011-12-31 23:28:32

6

使用以下!

use strict; 
use warnings; 

你會得到

Use of uninitialized value $' in concatenation (.) or string