2013-08-26 33 views
9

Ich versuche, ein HTML, das eine Tabelle enthält, in eine CSV-Datei mit einem bash Skript zu konvertieren.Verwenden Sie sed oder awk, um das Datumsformat zu beheben

Bisher habe ich acomplished die folgenden Schritte:

  1. auf Unix-Format konvertieren (mit dos2unix)
  2. alle Leerzeichen entfernen und Registerkarten (mit sed 's/[ \t]//g')
  3. Entfernen Sie alle leeren Zeilen (mit sed ':a;N;$!ba;s/\n//g') (Dies ist notwendig, weil die HTML-Datei eine Leerzeile für jede Zelle der Tabelle hat ... das ist nicht meine Schuld)
  4. Entfernen Sie die unnötigen <td> und <tr> Tags (mit sed 's/<t.>//g')
  5. ersetzen </td> mit '' (mit sed 's/<\/td/,/g')
  6. ersetzen </tr> mit End-of-line (\n) Zeichen (mit sed 's/<\/tr/\n/g')

Natürlich Ich setze dies alles in eine Pipeline. Bis jetzt funktioniert es großartig. Es gibt einen letzten Schritt, bei dem ich feststecke: Die Tabelle hat eine Spalte mit Daten, die das Format dd/mm/yyyy hat, und ich möchte sie in yyyy-mm-dd konvertieren.

Gibt es einen (einfachen) Weg (mit sed oder awk)?

Datenabtastblock (nach dem ganzen sed Rohr):

500,2,13/09/2007,30000.00,12,B-1 
501,2,15/09/2007,14000.00,8,B-2 

Erwartetes Ergebnis:

500,2,2007-09-13,30000.00,12,B-1 
501,2,2007-09-15,14000.00,8,B-2 

Der Grund, warum ich muss das tun, weil ich diese Daten importieren müssen zu MySQL. Ich könnte die Datei in Excel öffnen und das Format von Hand ändern, aber ich möchte das überspringen.

Antwort

7

Awk können diese Aufgabe tun ziemlich leicht:

awk ' 
    BEGIN { FS = OFS = "," } 
    { split($3, date, /\//) 
     $3 = date[3] "-" date[2] "-" date[1] 
     print $0 
    } 
' infile 

Es ergibt:

500,2,2007-09-13,30000.00,12,B-1 
501,2,2007-09-15,14000.00,8,B-2 
4
sed "s:,\([0-9]\+\)/\([0-9]\+\)/\([0-9]\+\),:,\3-\2-\1,:" 
4

awk würde für diese Arbeit:

echo 08/26/2013 | awk -F/ '{printf "%s-%s-%s\n",$3,$2,$1}' 

als würde einer von ihnen bash -nur Optionen:

IFS=/ read m d y < <(echo 08/26/2013); echo "${y}-${m}-${d}" 
IFS=/ read m d y <<< "08/26/2013"; echo "${y}-${m}-${d}" 

Wenn Sie verwenden ksh geschehen, wo eine Subshell nicht für die letzte Komponente einer Pipeline verwendet wird, sollte dies auch funktionieren:

echo 08/26/2013 | IFS=/ read m d y; echo "${y}-${m}-${d}" 

In den letzten bash, Sie können auch shopt -s lastpipe in einem Skript verwenden, um den obigen Aufruf zu ermöglichen, aber es funktioniert nicht auf der Kommandozeile (Danke an @ mklement0 in den Kommentaren unten).

Ich werde es Ihnen überlassen, um herauszufinden, wie es mit dem Rest ...

+0

Schön, aber der 'lesen'-basierte Befehl wird nicht funktionieren, weil' read' in diesem Fall in _subshell_ läuft; Verwende 'echo '08/26/2013' | {IFS =/lesen m d y; echo "$ {y} - $ {m} - $ {d}"; } 'oder ' IFS =/lesen m d y <<< '26.08.2013'; echo "$ {y} - $ {m} - $ {d}" ' – mklement0

+1

@ mklement0 Ah, ja .... vergaß dieses kleine Detail. Es würde jedoch in 'ksh' funktionieren. Eine andere Alternative wäre "IFS =/read m dy <<(26.08.2013)", um die Unterschale zu vermeiden (obwohl das "Echo" in einer Unterschale wäre). – twalberg

+0

Gute Punkte, obwohl '<<<' hier wahrscheinlich am effizientesten ist. In Bash v4.2 + können Sie auch 'shopt -s lastpipe' verwenden (aber nur in Skripten). Kann ich vorschlagen, dass Sie Ihre Antwort mit einer der Arbeitslösungen aktualisieren? – mklement0

7
sed -E 's,([0-9]{2})/([0-9]{2})/([0-9]{4}),\3-\2-\1,g' 
+0

Dies wurde als erstes Beispiel eingefügt, um die Dinge in Gang zu bringen und es funktionierte wörtlich! Danke @ash! – Matthew

1

Korrektur awk zu integrieren annehmen, dass Sie yyyy-mm-dd suchen (nicht yyyy-mm-dd)

echo 26/08/2013 | awk -F/'{printf "% s-% s-% s \ n", $ 3, $ 1, $ 2}'

2

Bisher sind alle Antworten sehr fallspezifisch für das Problem von OP. Hier ist ein allgemeiner Ansatz, Laufen (GNU, für -d Option) date durch awk:

awk 'BEGIN{FS=","} 
    { 
     "date -d\"" $3 "\" +%Y-%m-%d" | getline mydate; 
     print $1 "," $2 "," mydate "," $4 "," $5 "," $6 
    }' 

Natürlich ist dieser Ansatz funktioniert wie nur dann, wenn das Eingangsdatum Format von date gehandhabt wird. AFAICS ist dies bei dd/mm/yyyy leider nicht der Fall. Man kann versuchen other commands als date (nicht getestet).

Bearbeiten: Implementiert mklement0's Kommentar.

Edit2: Eigentlich funktioniert das nicht mit mawk, die Debians Standard awk Implementierung ist. Offensichtliche Lösung ist, gawk wenn möglich zu installieren.

+1

++, aber Sie sollten erwähnen, dass _GNU_ 'date' aufgrund von' -d' erforderlich ist; ähnlich ist '| &' eine GNU Awk Extension, die hier aber nicht benötigt wird: '|' macht das, was es mit allen Awks funktioniert. Schließlich schlage ich vor, Sie Leerzeichen zwischen den Zeichenfolgen zu verketten, sowohl für die visuelle Klarheit und um zu zeigen, dass String-Verkettung in Awk arbeitet anders als in der Shell ; z. B. "date -d" "$ 3" +% Y-% m-% d "' (Ich habe auch einfache Anführungszeichen hinzugefügt, um das Feld mit eingebetteten Leerzeichen zu schützen). – mklement0

+1

@ mklement0: Danke für deine Vorschläge, ich habe die Antwort bearbeitet. Einfache Anführungszeichen reichen nicht aus, ich habe sie durch doppelte Anführungszeichen ersetzt. –

+1

Danke für die Aktualisierung der Antwort, und danke für das Abfangen meiner Single-Anführungszeichen Fehler (nur um es explizit zu sagen: einfache Anführungszeichen können nicht innerhalb des Awk-Skript verwendet werden, weil das Skript als Ganzes zitiert wird). – mklement0

Verwandte Themen