2013-04-02 62 views
0

給定一個測試文件settings.py,看起來像這樣:省略部分

# Django settings for x project. 
DEBUG = True 
TEMPLATE_DEBUG = DEBUG 
ADMINS = (
    # ('Your Name', '[email protected]'), 
) 
MANAGERS = ADMINS 
DATABASES = { 
    'default': { 
     'ENGINE': 'django.db.backends.', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'. 
     'NAME': '',      # Or path to database file if using sqlite3. 
     'USER': '',      # Not used with sqlite3. 
     'PASSWORD': '',     # Not used with sqlite3. 
     'HOST': '',      # Set to empty string for localhost. Not used with sqlite3. 
     'PORT': '',      # Set to empty string for default. Not used with sqlite3. 
    } 
} 
# Hosts/domain names that are valid for this site; required if DEBUG is False 
# See https://docs.djangoproject.com/en/1.3/ref/settings/#allowed-hosts 
ALLOWED_HOSTS = [] 

我想以編程方式(shell腳本)替換線之間的部分:

DATABASES = { 

和:

} 

包含在可變k一些文字:

declare -r k='foo bar baz' 

我是一個初學者perl,但我炮製的:

perl -ne 'if(!$f && /DATABASES/){$f=1} if(!$f){print} if($f && /^}$/){$f=0}' < settings.py 

這是我一貫的sed/awk小黑客出發:

# e.g. 
sed '/DATABASES/,/^}$/ d' < settings.py 

我想提高我的perl單線!

我該怎麼辦sed在全能的perl中做得如此精美?

什麼是絕對的最佳途徑:

  • 手錶標準輸入經過,重現它到stdout
  • 檢測哨兵「停止印刷」行並停止複製
  • 重新啓用的傳遞stdin->標準輸出當遇到第二個哨兵線

我省略了任務的更換部分,希望能得到一些幫助機智h也是如此。

+0

我想用sed的'/ DATABASES /,/ ^} $ /'是rougly日同['/ DATABASES/... /^}$/'](http://perldoc.perl.org/perlop.html#Range-Operators)。 –

回答

1

我以爲我會告訴你如何awk腳本轉換爲Perl的一個。

所以開始,我把Ed Morton'sawk version並通過a2p發送它。

$ a2p 
/DATABASES = {/ { skip=1 } 
skip && /^}/ { skip=0; $0=k } 
!skip 
^d 

注意^d表示按下Ctrl鍵+d

#!/opt/perl-5.14.1/bin/perl 
eval 'exec /opt/perl-5.14.1/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 

while (<>) { 
    chomp; # strip record separator 
    if (/DATABASES = {/) { 
    $skip = 1; 
    } 
    if ($skip && /^}/) { 
    $skip = 0; 
    $_ = $k; 
    } 
    print $_ if !$skip; 
} 

我們可以拋出eval 'exec ...線。我懷疑你會需要它。

由於我們只需要處理k="$k",所以也可以拋出eval '$'.$1.'$2;' ...。 我們只需要將$k設置爲$ENV{k}或者將後者替換爲前者。 (請注意,您必須調用export k這個工作,你也可以叫它通過env k="$k" perl test.pl

由於線變得chomped,我們要麼需要print $_, "\n" if !$skip;更換print $_ if !$skip;或設置$\"\n"。我想我們可以在不致電chomp的情況下離開。

同樣爲了防止難以發現的錯誤,我打算將use strict;use warnings;添加到開頭。

#!/usr/bin/env perl 
use strict; 
use warnings; 

my $skip; # prevents printing when true 
while (<>) { 
    if (/DATABASES = {/) { 
    $skip = 1; 
    } 
    if ($skip && /^}/) { 
    $skip = 0; 
    $_ = $ENV{k}."\n"; 
    } 
    print $_ if !$skip; 
} 

我認爲,我們可以在一個sed「主義混合在這裏。 (...

#!/usr/bin/env perl 
use strict; 
use warnings; 

while (<>) { 
    if(my $r = /DATABASES = {/ ... /^}/){ 

    if($r == 1){ # first time it matches 
     print $ENV{k}, "\n"; 
    } 

    next; # don't print 
    } 

    print; 
} 

唯一的一點是,我覺得OP就想換成DATABASES = {}之間的文本。所以我們必須添加代碼來允許打印這兩行。

#!/usr/bin/env perl 
use strict; 
use warnings; 

while (<>) { 
    if(my $r = /DATABASES = {/ ... /^}/){ 

    if($r == 1){ 
     # append the replacement to the first line 
     $_ .= $ENV{k}."\n"; 

    }elsif($r !~ /E/){ # rest of the matches, except the last one 
     next; 
    } 
    } 

    print; 
} 

你知道,我真的不喜歡其放置在一個環境變量替換文本。如何將它放入__DATA__部分。

use strict; 
use warnings; 

my $replacement = do{ local $/; <DATA> }; # slurp 
close DATA; 

while (<>) { 
    if(my $r = /DATABASES = {/ .. /^}/){ 
    if($r == 1){ 
     $_ .= $replacement; 
    }elsif($r !~ /E/){ 
     next 
    } 
    } 
    print; 
} 

__DATA__ 
<<<FOO>>> 
+0

Sh * t男人,我應**支付**您的學習,我在這裏得到**免費**!謝啦!你對自己的知識非常慷慨激勵!我會感激地洗你的腳! (儘管你可能不喜歡那樣,但它是象徵性的)。你是如何啓發自學的! – Robottinosino

1

要刪除數據庫之間的部分,},您可以使用此:

perl -ne 'print unless (/DATABASES/../^}$/)' settings.py 

需要更換,這樣的事情:

$ export VAR="foo bar baz" 
$ perl -ne 'print $ENV{VAR},"\n" if /DATABASES/; print unless /DATABASES/../^}$/' settings.py 
+0

謝謝..雖然你會怎麼做替換? – Robottinosino

+0

如果您看到要替換的內容的第一行,只需打印您想要的內容:'perl -ne'打印「$ ENV {VAR} \ n」if/DATABASES /;打印,除非/DATABASES/../^}$/'settings.py' – aragaer

+0

@aragaer:謝謝隊友,很好的解決方案,更新它...我的解決方案看起來很有趣,一旦我看到你:) – Guru

2

無法想象爲什麼你要來使用perl進行簡單的文本處理,因爲它是awk的設計目的,就像所有優秀的UNIX工具一樣,awk可以完成一件事情並且做得很好。

隨着GNU AWK:

$ k="<<<<foo>>>>" 
$ gawk -v k="$k" -v RS='\0' '{sub(/DATABASES = {.*\n}/,k)}1' file 
# Django settings for x project. 
DEBUG = True 
TEMPLATE_DEBUG = DEBUG 
ADMINS = (
    # ('Your Name', '[email protected]'), 
) 
MANAGERS = ADMINS 
<<<<foo>>>> 
# Hosts/domain names that are valid for this site; required if DEBUG is False 
# See https://docs.djangoproject.com/en/1.3/ref/settings/#allowed-hosts 
ALLOWED_HOSTS = [] 

說明:

gawk 
-v k="$k"  = set the awk variable k to the value of the shell variable k 
-v RS='\0' = set the Record Separator to the NULL string so gawk reads the whole file 
' 
{sub(/DATABASES = {.*\n}/,k)}  = replace the text between "DATABASES = {" and "}" at the start of a line inclusive with the contents of the awk variable k. 
1  = set a true condition which invokes the default action of printing the current record (the whole file in this case) 
' file 

如果你不能一次讀取整個文件,由於存儲器限制,或者如果你只是喜歡這種風格還是不要沒有GNU awk,將腳本修改爲(未經測試):

$ awk -v k="$k" ' 
    /DATABASES = {/ { skip=1 } 
    skip && /^}/ { skip=0; $0=k } 
    !skip 
    ' file 

希望它的功能很明顯。請注意,刪除RS ='\ 0'的設置意味着腳本不再是特定於gawk的。

如果你需要保持劃界線,這只是一個調整過:

$ awk -v k="$k" ' 
    skip && /^}/ { skip=0; print k } 
    !skip 
    /DATABASES = {/ { skip=1 } 
    ' file 
# Django settings for x project. 
DEBUG = True 
TEMPLATE_DEBUG = DEBUG 
ADMINS = (
    # ('Your Name', '[email protected]'), 
) 
MANAGERS = ADMINS 
DATABASES = { 
<<<<foo>>>> 
} 
# Hosts/domain names that are valid for this site; required if DEBUG is False 
# See https://docs.djangoproject.com/en/1.3/ref/settings/#allowed-hosts 
ALLOWED_HOSTS = [] 
+0

事實上,我喜歡'sed'和'awk'!非常感謝你回答!答:僅僅因爲我是_learning_'perl',我仍然更喜歡'sed' /'awk'這些東西! – Robottinosino

+0

您能否「解釋」/「擴大」您的單線?習慣上,當提供一個好的和緊湊的解決方案時,給它添加一個「閱讀指南」,對於那些不熟悉的人或者那些(比如我)不太熟練的人。 – Robottinosino

+0

關鍵是,如果你想學習Perl,你應該先學習它的優點(我不知道那是什麼,但我確定有什麼)。只是「學習perl」聽起來像是通過提供各種複雜的腳本,包含標點符號和單個字符的神祕組合來做sed但是根本不應該做的事情。 –