2012-10-02 48 views
1

我試圖匹配以下格式記錄:多平臺的perl腳本awk或

(-,username,domain1.co.uk)\ 
(-,username,domain2.co.uk) 

無論是AWK或Perl必須使用。我使用Cygwin和寫了下面這工作和同時匹配以上項目代碼:

awk 'BEGIN {musr="(-,username,[^)]+.co.uk)"} {if ($0~musr) print $0}' netgroup 

但是,如果我嘗試修改這個正則表達式更具體的輸出是什麼:

1:匹配記錄,則最後反斜線然後匹配換行符:

"(-,username,[^)]+.co.uk)\\$" 

第二:賽會紀錄後immediatelly新行沒有反斜線:

"(-,username,[^)]+.co.uk)$" 

所以我決定將腳本重寫爲perl,希望perl可以處理反斜槓和行尾符號。爲此我使用A2P這樣:

echo 'BEGIN {musr="(-,username,[^)]+.co.uk)"} {if ($0~musr) print $0}' | a2p.exe 
#!/usr/bin/perl 
eval 'exec /usr/bin/perl -S $0 ${1+"[email protected]"}' 
    if $running_under_some_shell; 
         # this emulates #! processing on NIH machines. 
         # (remove #! line above if indigestible) 

eval '$'.$1.'$2;' while $ARGV[0] =~ /^([A-Za-z_0-9]+=)(.*)/ && shift; 
         # process any FOO=bar switches 

$, = ' ';    # set output field separator 
$\ = "\n";    # set output record separator 

$musr = '(-,username,[^)]+.co.uk)'; 

while (<>) { 
    chomp;  # strip record separator 
    if ($_ =~ $musr) { 
     print $_; 
    } 
} 

這個生成的perl腳本也都條目相匹配,但是如果我試圖修改此腳本,以更具體的我收到以下錯誤:

1:

$musr = "(-,username,[^)]+.co.uk)\\"; 
Trailing \ in regex m/(-,username,[^)]+.co.uk)\/ at perlmatch.pl line 18, <> line 1. 

第二:

$musr = "(-,username,[^)]+.co.uk)$"; 
Final $ should be \$ or $name at perlmatch.pl line 14, within string 
syntax error at perlmatch.pl line 14, near "= "(-,username,[^)]+.co.uk)$"" 
Execution of perlmatch.pl aborted due to compilation errors. 

3:

$musr = "(-,username,[^)]+.co.uk)\$"; 
[the output is nothing] 

我在做什麼錯了?我的問題也指出,如果有人需要在多個平臺(aix,solaris,linux)上使用腳本,而不是使用perl,應該是處理(非)GNU utils和各種(g | n)awk版本等更好的方法。問候

回答

1

你的問題來自Perl中的字符串引用。

$musr = "(-,username,[^)]+.co.uk)\\";在創建字符串時用單個反斜槓代替\\。但是你需要將兩個反斜槓傳遞給正則表達式。所以當你創建字符串的時候,你將不得不放入四個。

$musr = "(-,username,[^)]+.co.uk)$";試圖在字符串內執行變量插值。正如John Kugelman指出的那樣,圓括號應該逃脫。

解決方案是使用Perl內置的定界符作爲正則表達式,而不是普通的帶引號的字符串。最簡單的方法是把它直接進入你的循環:

while (<>) { 
    chomp;  # strip record separator 
    if ($_ =~ /\(-,username,[^)]+.co.uk\)$/) { 
     print $_; 
    } 
} 

如果你需要把模式到一個變量第一,使用特殊qr// 運營商。

my $musr = qr/\(-,username,[^)]+.co.uk\)$/; 
while (<>) { 
    chomp;  # strip record separator 
    if ($_ =~ $musr) { 
     print $_; 
    } 
} 
+0

謝謝qr操作員是我一直在尋找的東西。 –

+0

當然也逃避了括號。還有一個問題,爲什麼應該有qr並且簡單地引用正則表達式還不夠? Regards –

+0

@Wakan Tanka,正則表達式使用特殊的語法,其中某些字符和某些轉義碼具有特殊含義。因此,Perl爲您提供了特殊的'qr //'運算符來處理這個問題。如果你不得不把它放在一個普通的字符串中,你需要有兩層轉義:一個用於字符串,另一個用於正則表達式。這造成了一個難以理解的混亂。 – dan1111

1
(-,username,[^)]+.co.uk)\\$ 

這裏的問題是與反斜線在行尾,它是括號。圓括號用於分組。你需要轉義它們以匹配文字()個字符。你也應該避開這些點,以便它們匹配文字點而不是「任何字符」。

$ awk '/\(-,username,[^)]+\.co\.uk\)$/ {print}' netgroup 
(-,username,domain2.co.uk) 
$ awk '/\(-,username,[^)]+\.co\.uk\)\\$/ {print}' netgroup 
(-,username,domain1.co.uk)\ 

如果你堅持用普通的awk,不要使用[GN] AWK-特定功能AWK是非常便攜。我會想,比Perl更便攜。

+0

Awk和Perl都可以在任何主要平臺上使用。我不認爲一般人比其他人「更便攜」。這取決於你想要做什麼。 – dan1111

+0

你的意思是堅持簡單的awk嗎?有時我需要在多個平臺(AIX,Solaris,HP-UX,Linux,Cygwin)中編寫腳本,我的經驗是所有* UNIX中「經典」Linux命令(awk,sed)的行爲略有不同。例如。 sed在Solaris中不能簡單地用newline像linux那樣替換任何字符。 (sed's/char/\ n /')等。我只是perl新手,但到目前爲止,當我編寫perl代碼時,它在所有平臺上都運行,沒有像[gn] awk sed等問題。Regards –

0

括號必須轉義。否則,他們將表情分組更具體地說,匹配行末尾的可選反斜槓(反斜槓加倍,因爲字符串也必須被轉義)。

awk 'BEGIN {musr="\\(-,username,[^)]+.co.uk\\)\\\\?$"} {if ($0~musr) print $0}' netgroup 
+0

Thanks for reply ,那些逃跑已經逃脫了我的瘋狂,你能發佈一些好的資源嗎? –