2016-07-28 40 views
0

Angenommen, eine Textdatei enthält bestimmte Zeilen, deren Wortreihenfolge geändert werden sollte. Die Wörter (Teilstrings) sind durch einzelne Leerzeichen begrenzt. Die zu ändernden Zeilen können durch ihr erstes Zeichen (z. B. ">") identifiziert werden.Inline-Neuordnung von Teilstrings über Bash

# cat test.txt 
>3 test This is 
foo bar baz 
foo bar qux 
>2 test This is 
foo bar baz 
>1 test This is 
foo bar qux 

Welcher Befehl (wahrscheinlich in awk) würden Sie den gleichen Bestellprozess über alle Linien mit dem Schlüsselzeichen verwenden anwenden zu beginnen?

# cat test.txt | sought_command 
>This is test 3 
foo bar baz 
foo bar qux 
>This is test 2 
foo bar baz 
>This is test 1 
foo bar qux 
+0

nicht die Sortierregel verstehen .. .. – Kent

+0

Was hast du probiert? Und gibt es eine abstraktere Definition von Input und Output, die die Umordnungsregeln klarer machen kann? – l0b0

Antwort

2

Hier ist eine Art und Weise Sie es awk mit tun könnte:

awk 'sub(/^>/, "") { print ">"$3, $4, $2, $1; next } 1' file 

sub kehrt wahr (1), wenn es macht eine Substitution. Die 1 am Ende ist die kürzeste True Bedingung, um die Standardaktion { print } auszulösen.

+0

Wow !. Das gleiche Skript wie ich, aber optimiert! – AwkMan

1

Nach Ihrem Beispiel wie folgt aus:

awk '$1~"^>" {sub(">","",$1);print ">"$3,$4,$2,$1;next} {print}' test.txt 
+0

Danke. Schlicht und einfach! –

+1

Der Operator '~' ist für Regexp-Vergleiche, also ist die Sache auf der rechten Seite des Ausdrucks eine Regexp, keine Zeichenkette, und sollte daher in Regexp-Trennzeichen eingeschlossen sein, '/.../', nicht String-Trennzeichen, ' "...". Wenn Sie Zeichenfolgenbegrenzer in einem Regexp-Kontext verwenden, muss awk die Zeichenfolge zweimal analysieren, um sie zuerst in eine Regexp umzuwandeln und sie dann erneut als Regexp zu verwenden, was Konsequenzen hat, einschließlich der Verdopplung aller Escape-Zeichen, z. '/ foo \ .bar /' vs '$ 0 ~" foo \\. bar "'. Also sollten Sie '$ 1 ~/^> /', nicht '$ 1 ~" ^> "' verwenden. –

+1

Danke für die Informationen @EdMorton !. Dank dir weiß ich, warum ich Probleme mit den Scape Charakteren hatte. Ich werde '/../' von nun an mit dem '~' Operator verwenden. – AwkMan

0

Das Werkzeug für die einfache Substitutionen an einzelnen Linien am besten geeignet ist, sed:

$ sed -E 's/>([^ ]+)([^ ]+)(.*)/>\3\2\1/' file 
>This is test 3 
foo bar baz 
foo bar qux 
>This is test 2 
foo bar baz 
>This is test 1 
foo bar qux 

Awk für etwas kompliziertere/interessant ist das richtige Werkzeug ist. Beachten Sie, dass im Gegensatz zu den awk-Lösungen, die Sie bisher erhalten haben, die oben genannten weiterhin funktionieren, wenn Sie mehr als 4 "Wörter" in einer Zeile haben, zB:

$ cat file 
>3 test Now is the Winter of our discontent 
foo bar baz 
foo bar qux 
>2 test This is 
foo bar baz 
>1 test This is 
foo bar qux 

$ sed -E 's/>([^ ]+)([^ ]+)(.*)/>\3\2\1/' file 
>Now is the Winter of our discontent test 3 
foo bar baz 
foo bar qux 
>This is test 2 
foo bar baz 
>This is test 1 
foo bar qux 

$ awk 'sub(/^>/, "") { print ">"$3, $4, $2, $1; next } 1' file 
>Now is test 3 
foo bar baz 
foo bar qux 
>This is test 2 
foo bar baz 
>This is test 1 
foo bar qux