2009-10-20 29 views
5

我有這樣的文件中的行文件:移動線(S)遵循另一條線在一個文件

check=('78905905f5a4ed82160c327f3fd34cba') 

我想能夠移動這條線跟隨線看起來像這樣:

files=('somefile.txt') 

陣列雖然在能夠跨越多行,例如倍:

files=('somefile.txt' 
     'file2.png' 
     'another.txt' 
     'andanother...') 

text 
in between 

check=('78905905f5a4ed82160c327f3fd34cba' 
     '5277a9164001a4276837b59dade26af2' 
     '3f8b60b6fbb993c18442b62ea661aa6b') 

陣列/線送花兒給人s結束於a),並且之間的任何文本都不會包含閉括號。

我得到了一些建議了awk可以這樣做:

awk '/files/{ 
    f=0 
    print $0 
    for(i=1;i<=d;i++){ print a[i] } 
    g=0 
    delete a # remove array after found 
    next 
} 
/check/{ f=1; g=1 } 
f{ a[++d]=$0 } 
!g' file 

這將只跨越一個行雖然。我被告知要擴大搜索範圍:

awk '/source/ && /\)$/{ 
    f=0 
    print $0 
    for(i=1;i<=d;i++){ print a[i] } 
    g=0 
    delete a # remove array after found 
    next 
} 
/md5sum/ && /\)$/{ f=1; g=1 } 
f{ a[++d]=$0 } 
!g' 

只是學習awk,所以我會很感激這個幫助。或者如果有另一種工具可以做到這一點,我想聽聽它。有人告訴我,'編輯'這些類型的功能。

+0

啊哈,需要上下移動線條,對嗎?我已經修改了下面的答案... – DigitalRoss 2009-10-24 19:56:38

回答

2

先回答你的最後一個問題,是的,awk是這種情況的典型的Unix工具,其他候選人是令人難以置信的強大PerlPython,或..我喜歡.. Rubyawk的一個優點是它總是在那裏;它是基本系統的一部分。解決這類問題的另一種方法是使用編輯腳本來控制ed(1)ex(1)。好的,修改後的問題的新程序。該程序將根據需要向上或向下移動「檢查」行,以便它們遵循「文件」行。

BEGIN { 
    checkAt = 0 
    filesAt = 0 
    scanning = 0 
} 

/check=\(/ { 
    checkAt = NR 
    scanning = 1 
} 

/files=\(/ { 
    filesAt = NR 
    scanning = 1 
} 

/)$/ { 
    if (scanning) { 
    if (checkAt > filesAt) { 
     checkEnd = NR 
    } else { 
     filesEnd = NR 
    } 
    scanning = 0 
    } 
} 

{ 
    lines[NR] = $0 
} 

END { 
    for (i = 1; i <= NR; ++i) { 
    if (checkAt <= i && i <= checkEnd) { 
     continue 
    } 
    print lines[i] 
    if (i == filesEnd) { 
     for (j = checkAt; j <= checkEnd; ++j) { 
     print lines[j] 
     } 
    } 
    } 
} 
+0

嘿,這很棒,但是右括號正在被截斷。即check =(...。我對files數組嘗試的例子是在文件末尾,這是否有所作爲呢?另外,如果文件數組位於check數組之前,是否也可以工作: )。我發現它在一些文件中有所不同。 – 2009-10-21 01:04:51

+0

好吧,如果你在'mover.awk'結尾添加這行,它將處理文件中最後一行是check()行的情況:'END {for(v in save){print saved [ v]}}'*但是*我無法重現您的截斷錯誤報告。你能否把一個測試用例放到http://pastie.org上(使用文件類型「純文本」)? – DigitalRoss 2009-10-21 01:38:58

+0

我已經在http://pastie.org/662905中放置了腳本的更新版本。此版本通過在最後一次檢查時看到一個新的檢查,並在EOF上輸出任何剩餘的檢查來處理倒序排序。但我仍然需要一個測試用例,因爲我無法重現您的錯誤。 – DigitalRoss 2009-10-21 01:40:47

0

這裏是如何用做sed的:

 
sed -e /^check=(/,/)/{H;d} -e /)/{G;s/\n//} < filename 

這是假設沒有正確的括號的「文件= ...」如果有,那麼你就需要更多的精度:

 
sed -e /^check=(/,/)/{H;d} -e /^files=(/,/)/{/)/{G;s/\n//}} < filename 

編輯:
工作在bash?好吧,試試這個:

 
sed -e /^check=(/,/)/H -e /^check=(/,/)/d -e '/)/G;s/\n//' < filename 

這似乎工作,但它並不清楚爲什麼這個變種,而不是其他一些明顯的變種。這種特殊字符跳舞對於正則表達式來說總是一個問題。

+1

哇,試圖做sed,勇敢的人:P。是的,我用sed試過這個,但是理解寄存器我還沒有深入。從你的命令看來,bash正在試圖解釋括號。我嘗試轉義它們,但得到:sed:-e表達式#1,字符0:不匹配{{' bash:d}:找不到命令 bash:s/n //}}:沒有這樣的文件或目錄 – 2009-10-21 00:41:41

+0

Still沒有運氣。在這裏使用gnu-sed 4.2.1。 bash:意外標記附近的語法錯誤'( – 2009-10-24 07:17:32

+0

* sigh *如果你有興趣,我們可以做一些實驗並讓它工作,但是因爲你已經在awk中有了一個工作解決方案,所以它只是學習sed中的一個擴展 – Beta 2009-10-26 14:27:39

0

我着眼於使用Awk做這件事,但看起來你並沒有真正從中得到任何聰明的東西,它只是一個邏輯,但有一些Awk痛苦地去做,所以我做了它在Perl :)

#!/usr/bin/perl 

open(IN, $ARGV[0]) || die("Could not open file: " . $ARGV[0]); 

my $buffer=""; 

foreach $line (<IN>) { 
     if ($line =~ /^check=/) { 
       $flag = 1; 
       $buffer .= $line; 
     } elsif ($flag == 1 && $line =~/\)/) { 
       $flag = 0; 
       $buffer .= $line; 
     } elsif ($flag == 1) { 
       $buffer .= $line; 
     } elsif ($flag == 0 && $line =~ /^files=/) { 
       $flag = 2; 
       print $line; 
     } elsif ($flag == 2 && $line =~ /\)/) { 
       $flag = 0; 
       print $line; 
       if (length($buffer) > 0) { 
         print $buffer; 
         $buffer = ""; 
       } 
     } else { 
       print $line; 
     } 

} 

和輸出:)

Chill:~ rus$ cat test check=('78905905f5a4ed82160c327f3fd34cba' 
     '5277a9164001a4276837b59dade26af2' 
     '3f8b60b6fbb993c18442b62ea661aa6b') 

text in between 

files=('somefile.txt' 
     'file2.png' 
     'another.txt' 
     'andanother...') 

asdasdasd 

check=('78905905f5a4ed82160c327f3fd34cba' 
     '5277a9164001a4276837b59dade26af2' 
     '3f8b60b6fbb993c18442b62ea661aa6b') 

text in between 

files=('somefile.txt' 
     'file2.png' 
     'another.txt' 
     'andanother...') 

asdsd 

check=('78905905f5a4ed82160c327f3fd34cba' 
     '5277a9164001a4276837b59dade26af2' 
     '3f8b60b6fbb993c18442b62ea661aa6b') 

text in between 

files=('somefile.txt' 
     'file2.png' 
     'another.txt' 
     'andanother...') 

Chill:~ rus$ ./t.pl test 

text in between 

files=('somefile.txt' 
     'file2.png' 
     'another.txt' 
     'andanother...') check=('78905905f5a4ed82160c327f3fd34cba' 
     '5277a9164001a4276837b59dade26af2' 
     '3f8b60b6fbb993c18442b62ea661aa6b') 

asdasdasd 


text in between 

files=('somefile.txt' 
     'file2.png' 
     'another.txt' 
     'andanother...') check=('78905905f5a4ed82160c327f3fd34cba' 
     '5277a9164001a4276837b59dade26af2' 
     '3f8b60b6fbb993c18442b62ea661aa6b') 

asdsd 


text in between 

files=('somefile.txt' 
     'file2.png' 
     'another.txt' 
     'andanother...') check=('78905905f5a4ed82160c327f3fd34cba' 
     '5277a9164001a4276837b59dade26af2' 
     '3f8b60b6fbb993c18442b62ea661aa6b') 

ただ?!:D

+0

urgh ,輸出粘貼是搞砸了,但相信我,它確實有效。我嫉妒awk和sed解決方案:) – RusHughes 2009-10-20 23:57:30

+0

不,這很好。雖然不適合我。文件陣列正在被擦除,文件陣列仍然存在。我得到了兩個數組之間的{和()字符,這是否有所作爲? – 2009-10-21 00:35:32

+0

我在我的測試數據中加入了{()}個字符,它仍然正常工作!你有我可以試用的測試數據的例子嗎? – RusHughes 2009-10-21 08:39:32

0

@託德,我似乎已經給你提供了awk解決方案後,你沒有我。 ? :)。 這是另一種方法,這次不使用標誌方法。有一些鬆散的結束(提示:檢查模式p,q和再次輸出),我把它留給你整理。

gawk 'BEGIN{ 
    RS="check=[(]" 
    q="files=(.*\047)" # pattern to replace files= part 
    p=".*(files=(.*\047)).*" # to get the whole files= part to variable 
} 
NR>1{ 
    b=gensub(p, "\\1","g",$0) # get the files=part to var b 
    printf "%s\n\n",b  
    printf "check=(" 
    gsub(q,"",$0) 
    print $0 
}' file 

NB:gensub是針對呆子所以如果你有GAWK,那麼這是正常的

輸出

$ more file 
check=('5277a9164001a4276837b59dade26af2' 
     '5277a9164001a4276837b59dade26af2' 
     '3f8b60b6fbb993c18442b62ea661aa6b') 

text in between one 

files=('somefile1.txt' 
     'file1.png'  
     'another1.txt' 
     'andanother1...') 

asdasdasd blah blah 

check=('78905905f5a4ed82160c327f3fd34cba' 
     '5277a9164001a4276837b59dade26af2' 
     '3f8b60b6fbb993c18442b62ea661aa6b') 

text in between two 

files=('somefile2.txt' 
     'file2.png'  
     'another2.txt' 
     'andanother2...') 

asdsd blaasdf aslasdfaslj aslfjsldfsa 123e12 

check=('78905905fblah blah5a4ed82160c327f3fd34cba' 
     '5277a9164001a4276837b59dade26af2'   
     '3f8b60b6fbb993c18442b62ea661aa6b')   

text in between 

files=('somefile3.txt' 
     'file3.png'  
     'another3.txt' 
     'andanother3...') 

$ ./shell.sh 
files=('somefile1.txt'    
     'file1.png'     
     'another1.txt'    
     'andanother1...'    

check=('5277a9164001a4276837b59dade26af2' 
     '5277a9164001a4276837b59dade26af2' 
     '3f8b60b6fbb993c18442b62ea661aa6b') 

text in between one 

) 

asdasdasd blah blah 


files=('somefile2.txt' 
     'file2.png' 
     'another2.txt' 
     'andanother2...' 

check=('78905905f5a4ed82160c327f3fd34cba' 
     '5277a9164001a4276837b59dade26af2' 
     '3f8b60b6fbb993c18442b62ea661aa6b') 

text in between two 

) 

asdsd blaasdf aslasdfaslj aslfjsldfsa 123e12 


files=('somefile3.txt' 
     'file3.png' 
     'another3.txt' 
     'andanother3...' 

check=('78905905fblah blah5a4ed82160c327f3fd34cba' 
     '5277a9164001a4276837b59dade26af2' 
     '3f8b60b6fbb993c18442b62ea661aa6b') 

text in between 

) 
+0

謝謝鬼。在過去的幾天裏,我們一直在使用awk,只是還沒搞明白。仍在學習sed。猜猜我喜歡在繼續學習之前學習它的類型:D。欣賞幫助,但非常感謝。 – 2009-10-26 04:38:10

0

這可能會爲你工作:

sed ':a;$!N;/^files=.*\ncheck=/{/.*)$/!ba;s/\([^)]*)\)\(.*\)\(\ncheck=.*\)/\1\3\2/p;d};/^files=.*/ba;P;D' file 
相關問題