Ich habe eine Datei, die Epochendaten enthält, die ich in lesbare konvertieren muss. Ich weiß bereits, wie die Datumskonvertierung durchgeführt wird, z.
[server01 ~]$ date -d@1472200700
Fri 26 Aug 09:38:20 BST 2016
..aber ich habe Mühe herauszufinden, wie ich sed
durch die Datei gehen und alle Einträge konvertieren kann. Das Dateiformat sieht folgendermaßen aus:
#1472047795
ll /data/holding/email
#1472047906
cat /etc/rsyslog.conf
#1472048038
ll /data/holding/web
text-processing
sed
date
Maschinist
quelle
quelle
HISTTIMEFORMAT
Shell-Variable an, um das Format zum Zeitpunkt des Schreibens zu steuern.date -d
ist nicht portabel, um Solaris zu sagen ... Ich gehe davon aus, dass dies auf einem System mit hauptsächlich GNU-Tools ist? (GNU AWK / Perl sind in der Regel die tragbareren Methoden für Datumskonvertierungen.)gawk '{ if ($0 ~ /^#[0-9]*$/) {print strftime("%c",substr($0,2)); } else {print} }' < file
(strftime
scheint nicht tragbar ...)Antworten:
Unter der Annahme eines konsistenten Dateiformats
bash
können Sie die Datei zeilenweise lesen, testen, ob sie im angegebenen Format vorliegt, und dann die Konvertierung durchführen:BASH_REMATCH
ist ein Array, dessen erstes Element die erste erfasste Gruppe im Regex-Matching ist=~
, in diesem Fall die Epoche.Wenn Sie die Dateistruktur beibehalten möchten:
Dadurch wird der geänderte Inhalt an STDOUT ausgegeben, um ihn in einer Datei zu speichern, z
out.txt
.Wenn Sie möchten, können Sie jetzt die Originaldatei ersetzen:
Beispiel:
quelle
bash
,printf
können Sie die Konvertierung selbst durchführen :printf '#%(%F %H)T\n' "${BASH_REMATCH[1]}"
.Während es mit GNU
sed
mit Dingen wie möglich ist:Das wäre furchtbar ineffizient (und es ist einfach, willkürliche Sicherheitsanfälligkeiten bezüglich der Befehlsinjektion 1 einzuführen ), da dies bedeuten würde, eine Shell und einen
date
Befehl für jede#xxxx
Zeile auszuführen, praktisch so schlecht wie eine Shell-while read
Schleife . Hier ist es besser, Dinge wieperl
oder zu verwendengawk
, dh Textverarbeitungsprogramme mit integrierten Datumskonvertierungsfunktionen:Oder:
1 Wenn wir
^#([0-9]).*
statt^#([0-9]).*$
(wie in einer früheren Version dieser Antwort) geschrieben hätten, dann in Multi-Byte-Gebietsschemas wie UTF-8 (heutzutage die Norm) mit einer Eingabe wie#1472047795<0x80>;reboot
, wobei dies<0x80>
der Byte-Wert 0x80 ist bildet kein gültiges Zeichen, diesers
Befehl wäredate -d@1472047795<0x80>; reboot
beispielsweise ausgeführt worden. Mit dem Extra$
würden diese Zeilen nicht ersetzt. Ein alternativer Ansatz wäre:s/^#([0-9])/date -d @\1 #/e
Das heißt, das Teil nach dem#xxx
Datum als Shell-Kommentar belassenquelle
date -f
, um alle Konvertierungen in Stream-Form durchzuführen?s
Flags wird.*
auch die neue Zeile bei der Eingabe eingefügt. Sie können auch verwendenstrftime "%c", localtime $1
.Alle anderen Antworten führen zu einem neuen
date
Prozess für jedes Epochendatum, das konvertiert werden muss. Dies kann möglicherweise zu einem zusätzlichen Leistungsaufwand führen, wenn Ihre Eingabe groß ist.Das GNU-Datum verfügt jedoch über eine praktische
-f
Option, mit der eine einzelne Prozessinstanzdate
Eingabedaten kontinuierlich lesen kann, ohne dass eine neue Verzweigung erforderlich ist. Also wir nutzen könnensed
,paste
unddate
auf diese Weise , so dass jeder bekommt einmal (2x für nur gelaichtsed
) , unabhängig davon , wie groß die Eingabe:sed
Befehle löschen grundsätzlich gerade und ungerade Zeilen der Eingabe; die erste ersetzt auch#
mit@
dem richtigen Unix - Zeitstempel - Format zu geben.sed
Ausgabe wird dann weitergeleitet, andate -f
die für jede empfangene Eingabezeile die erforderliche Datumskonvertierung durchgeführt wird.paste
. Die<( )
Konstrukte sind Bash-Prozess-Ersetzungen , die das Einfügen effektiv dazu verleiten, zu glauben, dass es aus bestimmten Dateinamen liest, wenn es tatsächlich die Ausgabe liest, die vom Befehl im Inneren weitergeleitet wird.-d '\n'
erzähltpaste
mit einem Newline ungeraden und geraden Ausgangsleitungen zu trennen. Sie können dies ändern (oder entfernen), wenn Sie beispielsweise möchten, dass sich der Zeitstempel in derselben Zeile wie der andere Text befindet.Beachten Sie, dass dieser Befehl mehrere GNUisms und Bashisms enthält. Dies ist nicht Posix-konform und sollte außerhalb der GNU / Linux-Welt nicht portabel sein. Zum Beispiel
date -f
macht etwas anderes auf OSXes BSD-date
Variante.quelle
date -d
(aus der Frage) ist auch nicht portierbar ... (Unter FreeBSD wird versucht, mit den Sommerzeiteinstellungen herumzuspielen, unter Solaris wird ein Fehler ausgegeben ...) Die Frage gibt jedoch kein Betriebssystem an ...Angenommen, das Datumsformat, das Sie in Ihrem Beitrag haben, ist das, was Sie möchten, sollte der folgende reguläre Ausdruck Ihren Anforderungen entsprechen.
Beachten Sie, dass dies nur eine Epoche pro Zeile ersetzt.
quelle
sed: -e expression #1, char 48: invalid reference \3 on 's' command's RHS
mit sed:
Ausgabe :
da meine Landessprache Arabisch ist :)
quelle
Meine Lösung, wie man das in einer Pipeline macht
quelle