2009-10-20 13 views
5

dostałem plik, który ma linię w pliku jak poniżej:Move podążać inną linię w pliku

check=('78905905f5a4ed82160c327f3fd34cba') 

Chciałbym móc przenieść tę linię, aby postępować zgodnie ze linia, która wygląda następująco:

files=('somefile.txt') 

tablica chociaż czasami, która może obejmować wiele przewodów, na przykład:

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

text 
in between 

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

tablica/linia sprecyzowane s kończy się na a) i żaden tekst nie będzie zawierał zamkniętego nawiasu.

mam kilka rad by awk może to zrobić:

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 

ten nie sięga tylko jedną linię chociaż. Powiedziano mi, aby rozwinąć wyszukiwanie:

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' 

ucze awk więc byłbym wdzięczny pomóc. Lub jeśli istnieje inne narzędzie, które może to zrobić, chciałbym o tym usłyszeć. Ktoś powiedział mi, że "ed" te typy zdolności.

+0

Aha, potrzeba poruszać liniami w górę iw dół, prawda? Skorygowałem odpowiedź poniżej ... – DigitalRoss

Odpowiedz

2

Aby odpowiedzieć na to ostatnie pytanie pierwsze, tak, awk jest typowym narzędziem Unix za to inni kandydaci są niezwykle wydajne Perl, Python lub .. mój ulubiony .. Ruby. Jedną z zalet awk jest to, że zawsze tam jest; to część systemu bazowego. Innym sposobem rozwiązania tego problemu jest skrypt edytora, który kontroluje ed(1) lub ex(1).

OK, nowy program do skorygowanego pytania. Ten program przesunie linie "sprawdź" w górę lub w dół, jeśli to konieczne, aby podążały za wierszami "plików".

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

Hej, to świetnie, ale nawias zamykający jest obcięty. tzn. check = (.... Przykład, który wypróbowałem w tablicy files, znajdował się na końcu pliku. Czy to miało znaczenie? Czy można to również zrobić, jeśli tablica plików znajduje się przed tablicą check:). W niektórych plikach jest inaczej. –

+0

OK, jeśli dodasz ten wiersz na końcu 'mover.awk', to zajmiesz się przypadkiem, w którym ostatnią rzeczą w pliku jest linia check():' END {dla (v w zapisanym) {print saved [ v]}} '* jednak * Nie mogę odtworzyć twojego raportu o błędzie skracania. Czy możesz przenieść testową sprawę na http://pastie.org (użyj typu pliku "zwykły tekst")? – DigitalRoss

+0

Umieściłem zaktualizowaną wersję skryptu w http://pastie.org/662905 Ta wersja zajmuje się odwróconą kolejnością poprzez wybranie ostatniego sprawdzenia, jeśli widzi nowy, i wyprowadzenie dowolnego z pozostałych w EOF. Ale nadal potrzebuję przypadku testowego, ponieważ nie mogę odtworzyć błędu. – DigitalRoss

0

Oto jak to zrobić z sed:

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

ta zakłada, że ​​nie ma dobrych nawiasy po że „pliki = ...” Jeśli istnieje wtedy będziesz potrzebować więcej precyzja:

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

EDIT:
Praca w bash? Wszystko w porządku, spróbuj tego:

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

To wydaje się działać, ale to nie jest dla mnie jasne, dlaczego ten wariant, a nie kilka innych oczywistych. Te taneczne postaci zawsze stanowią problem z wyrażeniami regularnymi.

+1

Wow próbuje zrobić z sed, odważny człowiek: P. Tak, próbowałem tego z sedem, ale ze zrozumieniem rejestrów, do których jeszcze nie dotarłem. Z Twojego polecenia wygląda na to, że bash próbuje zinterpretować nawias. Próbowałem ich uniknąć, ale otrzymuję: sed: -e expression # 1, char 0: unmatched '{' bash: d}: command not found bash: s/n //}}: Brak takiego pliku lub katalogu –

+0

Still brak szczęścia. Używając tu gnu-sed 4.2.1. bash: błąd składni w pobliżu nieoczekiwanego tokenu '( –

+0

* westchnienie * Jeśli jesteś zainteresowany, możemy zrobić kilka eksperymentów i sprawić, że będzie działał, ale ponieważ masz już działające rozwiązanie w awk, byłoby to po prostu ćwiczeniem w nauce sed. – Beta

0

Spojrzałem na to z Awkiem, ale wyglądało na to, że nie dostaniesz z tego nic sprytnego, to byłaby po prostu ta sama logika, ale z jakimś awk bólem, więc zrobiłem to to w 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; 
     } 

} 

a wyjście :)

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') 

ta da?: D

+0

urgh , pasta wyjściowa jest wkręcona, ale zaufaj mi, działa. im zazdrosny o rozwiązania awk i sed :) – RusHughes

+0

nah, to jest dobre. Dla mnie jednak nie działa. Tablica plików zostaje wymazana, a tablica plików nadal istnieje. Mam {i() znaki między dwiema tablicami, czy to ma znaczenie? –

+0

Dodałem mnóstwo {()} znaków do moich danych testowych i nadal działało dobrze! czy masz przykład danych testowych, na których mogę go wypróbować? – RusHughes

0

@todd, wydaje mi się, że zostawiłem cię na lodzie po dostarczeniu ci rozwiązania awk, nie mam. ? :). Oto kolejna metoda, tym razem bez użycia metody flag. jest kilka luźnych końcówek (podpowiedź: sprawdź wzory p, q i wyjście ponownie), które zostawię ci, abyś posprzątał.

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 jest specyficzna dla gawk, więc jeśli masz gawk, to jest to w porządku

wyjście

$ 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

Dzięki ghost. Wkuwałem się w awk przez ostatnie kilka dni i po prostu tego nie rozumiem. Wciąż się uczę sed. Zgadnij, że jestem typem, który lubi się uczyć i nauczyć go dobrze, zanim przejdzie dalej: D. Doceń pomoc, bardzo doceniona. –

0

To może pracować dla Ciebie:

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