2012-03-24 20 views
1

ich eine Datei mit Struktur wie diese:awk - Konvertieren von negativen Zahlen positiv und umgekehrt

[05:58:10 08.12.1990] 125.441 
[05:58:21 08.12.1990] -2.4158 
... 

Wo alles, aber das letzten colummn ist eine Art von Timecode (unterschiedlich für jede Datei) und ich muß konvertieren die letzte Nummer in ihr Gegenteil, wie folgt aus:

[05:58:10 08.12.1990] -125.441 
[05:58:21 08.12.1990] 2.4158 
... 

ich versuchte es mit awk, aber da mein Wissen über awk ist ziemlich schlecht habe ich nicht ganz erreichen es. Ich versuchte zunächst negative Zahlen mit diesem hinzuzufügen:

awk '{$NF=" "; NF--; printf $0; NF++; if ($NF ~ /^[0-9].*/){printf "-"; print $NF}}' 

aber da ich die letzte Spalte weg mit NF-- werfen, kann ich es nicht mit NF zurück ++.

Jede Hilfe mit diesem würde geschätzt werden. Vielen Dank.

+0

gute Antworten unten, sondern folgt auf Ihrem ‚Ich kann es nicht mit NF wieder ++‘, auch dann, warum nicht Speichern Sie es in eine spezielle Variable, dh. 'myNF = NF; $ NF = ""; NF--; .... drucken $ (myNF) ... '. Viel Glück. – shellter

Antwort

2

was:

awk ' { if($NF ~ /^-/){sub(/-/, "", $NF); print $0;} 
     else {sub(/^[1-9]*.[1-9]*/,"-"$NF,$NF); print $0} } ' 


$ cat data 
[05:58:10 08.12.1990] 125.441 
[05:58:21 08.12.1990] -2.4158 
$ cat data | awk ' { if($NF ~ /^-/){sub(/-/, "", $NF); print $0;} else {sub(/^[1-9]*.[1-9]*/,"-"$NF,$NF); print $0} }' 
[05:58:10 08.12.1990] -125.441 
[05:58:21 08.12.1990] 2.4158 

edit: als William Purssell vorgeschlagen, eine verbesserte Version dieses Skripts:

cat data | awk ' { if($NF ~ /^-/){sub(/-/, "", $NF); print $0;} 
     else { $NF="-"$NF; print $0}} ' 
[05:58:10 08.12.1990] -125.441 
[05:58:21 08.12.1990] 2.4158 
[05:59:30 08.13.2000] -0.94630008768741448848 
+0

Danke für eine andere Version, aber es gibt auch einen Fehler .. Wenn ich die Zahl zwischen 0 und 1 umwandeln möchte, bekomme ich die falsche Nummer: Ich habe: "[05: 58:21 08.12.1990] 0.4158 "und ich bekomme [05:58:21 08.12.1990] -0.4158.4158 und ich sehe warum, Sie verwenden 1-9 statt 0-9. Jetzt funktioniert es ok, danke! – user1290065

+1

In der Else-Klausel, gibt es keine Notwendigkeit für sub. Tun Sie einfach $ NF = "-" $ NF –

5

Versuchen:

awk '{$NF *= -1; print}' 
+0

Das scheint zu funktionieren, aber es hat meine Nummer gerundet. Ich hatte 0.94630008768741448848 und awk gerundet es zu -0.9463 – user1290065

+0

Es ist möglich, Zeichenfolge <-> Nummer Konvertierung mit CONVFMT Variable anzupassen. Aber ich würde vorschlagen, bei einer anderen Lösung zu bleiben von @wisent –

0

sed Verwendung:

Inhalt des script.sed:

## Try to remove the negative sign. 
s/\(\] \+\)-\(.*\)$/\1\2/ 

## If last substitution succeed, goto label 'a'. 
ta 

## If last substitution failed, there was not negative sign, so 
## it is a positive number, I will have to add the sign just 
## before it. 
s/\] \+/&-/ 

## Label 'a' at end of script. Here print line and read next one. 
:a 

Inhalt des infile:

[05:58:10 08.12.1990] 125.441 
[05:58:21 08.12.1990] -2.4158 

Run es mögen:

sed -f script.sed infile 

und Ergebnis:

[05:58:10 08.12.1990] -125.441                                                    
[05:58:21 08.12.1990] 2.4158 
+0

Danke für die Lösung mit sed, aber das Problem hier ist, kann ich nicht sicher sein, dass der Timecode in Klammern ist. Wenn der Timecode zum Beispiel in zusammengesetzten Klammern wäre, würde dies nicht funktionieren. Aber trotzdem danke für die Idee! – user1290065

1

Dies könnte für Sie arbeiten:

sed 's/ \([0-9.]*\)$/ -\1/;t;s/\(.*\)-/\1/' file 
[05:58:10 08.12.1990] -125.441 
[05:58:21 08.12.1990] 2.4158 

Im Wesentlichen:

  • Wenn das letzte Feld durch ein Leerzeichen getrennt wird prepend eine -
  • Andernfalls die letzte minus entfernen.
+0

Ich muss sagen, dass Sed ist immer noch ein kleines Rätsel für mich, aber das funktioniert tatsächlich und es ist auch unabhängig von dem Format eines Timecode als awk. Ich dachte wirklich, das wäre mit sed unmöglich. Danke, dass du mich falsch bewiesen hast, ich muss noch viel lernen! – user1290065

0

http://www.nongnu.org/txr

$ txr -c '@(collect) 
[@date] @{sign /-?/}@num 
@(output)               
[@date] @(if (equal sign "") "-" "")@num 
@(end) 
@(end)' < data.txt 
[05:58:10 08.12.1990] 125.441 
[05:58:21 08.12.1990] -2.4158 
[05:59:30 08.13.2000] 0.94630008768741448848 

Dies ist robuster als die Hacky-Lösungen, die blindlings ein Minuszeichen durch Spalte Flip, weil wir einige Musterabgleich auf das tun, was die Daten aussehen (und wir können die Steigerung Menge an Details, falls erforderlich).

Aber die @(collect) überspringt Sachen, die nicht übereinstimmen.Eine Sache, die wir tun können, ist eine Ausnahme auslösen, wenn es etwas seltsam geformten Reihe ist:

$ txr -c '@(collect) 
@(cases) 
[@date] @{sign /-?/}@num 
@(or)          
@(throw error "invalid data") 
@(end) 
@(output) 
[@date] @(if (equal sign "") "-" "")@num 
@(end) 
@(end)' < data.txt 
+0

txr sieht wirklich interessant aus, noch nie davon gehört. Ich werde versuchen, mehr darüber zu lesen, danke! – user1290065

Verwandte Themen