2009-10-20 9 views
5

ich eine Datei bekam, die eine Zeile in der Datei wie folgt hat:Verschieben Linie (n) eine weitere Zeile in einer Datei folgen

check=('78905905f5a4ed82160c327f3fd34cba') 

ich in der Lage sein möchten, diese Linie zu bewegen, ein folgen Linie, die wie folgt aussieht:

files=('somefile.txt') 

Das Array zwar zu Zeiten, die mehrere Zeilen, zum Beispiel umfassen kann:

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

text 
in between 

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

Die Anordnung/Leitung alway s endet in a) und kein Text dazwischen enthält eine geschlossene Klammer.

Ich habe ein paar Ratschläge, die dies tun awk kann:

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 

Dies wird nur wenn eine Zeile erstrecken. Ich wurde aufgefordert, die Suche zu erweitern:

Nur lernen awk, so würde ich die Hilfe mit diesem schätzen. Oder wenn es ein anderes Werkzeug gibt, das das kann, würde ich gerne davon erfahren. Jemand hat mir gesagt, dass diese Arten von Fähigkeiten "ediert" werden.

+0

Aha, Notwendigkeit Linien auf und ab bewegen, oder? Ich habe die Antwort unten überarbeitet ... – DigitalRoss

Antwort

2

Ihre letzte Frage zuerst zu beantworten, ja, awk das typische Unix-Tool hierfür ist, sind auch andere Kandidaten der unglaublich leistungsstarke Perl, Python oder .. mein Favorit .. Ruby. Ein Vorteil von awk ist, dass es immer da ist; Es ist Teil des Basissystems. Eine andere Möglichkeit, diese Art von Problem zu lösen, ist ein Editor-Skript, das ed(1) oder ex(1) steuert.

Ok, neues Programm für die überarbeitete Frage. Dieses Programm verschiebt die "Check" -Zeilen entweder nach oben oder nach unten, so dass sie den Zeilen "Dateien" folgen.

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

Hey, das ist großartig, aber die schließende Klammer wird abgeschnitten. ie check = (.... Das Beispiel, das ich am Dateiarray ausprobiert habe, war am Ende der Datei. Hat das einen Unterschied gemacht? Könnte dies auch funktionieren, wenn das Dateiarray vor dem Checkarray ist:). Ich finde es in einigen Dateien anders. –

+0

Ok, wenn Sie diese Zeile am Ende von 'mover.awk' hinzufügen, wird es mit dem Fall umgehen, wo das Letzte in der Datei eine check() Zeile ist:' END {for (v in saved) {print saved [ v]}} '* aber * ich kann Ihren Abbruchberichtbericht nicht reproduzieren. Kannst du bitte einen Testfall auf http://pastie.org ablegen (Dateityp "Klartext" verwenden) ?? – DigitalRoss

+0

Ich habe eine aktualisierte Version des Skripts in http://pastie.org/662905 gestellt Diese Version befasst sich mit umgekehrter Reihenfolge durch die Ausgabe der letzten Prüfung, wenn es eine neue sieht, und die Ausgabe einer übrig gebliebenen bei EOF. Aber ich brauche immer noch einen Testfall, weil ich deinen Fehler nicht reproduzieren kann. – DigitalRoss

0

Hier ist, wie es zu tun mit sed:

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

Dies setzt voraus, dass es keine richtigen Klammern nach das „files = ...“ Wenn es dann werden Sie brauchen mehr Präzision:

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

EDIT:
in bash arbeiten? In Ordnung, versuchen Sie dies:

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

Dies scheint zu funktionieren, aber es ist mir nicht klar, warum diese Variante und nicht wenige andere offensichtlichen. Dieser Tanz der besonderen Charaktere ist immer ein Problem mit Regexs.

+1

Wow, mit sed zu versuchen, ein tapferer Mann: P. Ja, ich habe das mit sed versucht, aber ich verstehe Registern, zu denen ich noch nicht weit gekommen bin. Von Ihrem Befehl sieht es aus wie Bash versucht, die Klammern zu interpretieren. Ich habe versucht, sie zu entkommen, aber ich bekomme: sed: -e Ausdruck # 1, Char 0: unübertroffen '{' bash: d}: Befehl nicht gefunden bash: s/n //}}: Keine solche Datei oder Verzeichnis –

+0

Still kein Glück. Verwenden Sie gnu-sed 4.2.1 hier. Bash: Syntaxfehler in der Nähe von unerwartetem Token '( –

+0

* seufz * Wenn Sie interessiert sind, könnten wir einige Experimente machen und es zum Laufen bringen, aber da Sie bereits eine funktionierende Lösung in awk haben, wäre es einfach eine große Lernerfahrung. – Beta

0

Ich sah mich mit Awk an, aber es sah so aus, als würde man nichts wirklich schlaues daraus machen, es wäre nur die gleiche Logik, aber mit ein wenig Unbehagen, um damit zu gehen, also tat ich es es in 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; 
     } 

} 

Und die Ausgabe :)

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 die Ausgabe Paste ist vermasselt, aber vertrauen Sie mir, es funktioniert. Ich eifersüchtig auf die awk und sed Lösungen obwohl :) – RusHughes

+0

nah, das ist gut. Funktioniert aber nicht für mich. Das Dateiarray wird gelöscht und das Dateiarray ist noch vorhanden. Ich habe {und() Zeichen zwischen den beiden Arrays, macht das einen Unterschied? –

+0

Ich habe eine Menge {{}} Zeichen in meine Testdaten eingefügt und es funktionierte immer noch gut! Hast du ein Beispiel für die Testdaten, die ich ausprobieren kann? – RusHughes

0

@todd, ich scheinen Sie im Stich gelassen haben nach der Bereitstellung der awk Lösung habe ich nicht. ? :). hier ist eine andere Methode, diesmal nicht mit der Methode der Flags. es gibt ein paar losen Enden (Hinweis: Überprüfen Sie die Muster p, q und Ausgabe wieder), dass ich es Ihnen überlassen, aufzuräumen.

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 ist spezifisch so gaffen, wenn Sie gaffen haben, dann ist das in Ordnung

Ausgang

$ 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

Danke Geist. Ich habe die letzten paar Tage in Awk gequetscht und es einfach noch nicht verstanden. Ich lerne immer noch sed. Schätze, ich bin der Typ, der gerne etwas lernt und es lernt, bevor es weitergeht: D. Schätzen Sie die Hilfe jedoch, sehr geschätzt. –

0

Dies könnte für Sie arbeiten:

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