J'ai un fichier qui contient des dates d'époque que j'ai besoin de convertir en lisibles par l'homme. Je sais déjà comment faire la conversion de date, par exemple:
[server01 ~]$ date -d@1472200700
Fri 26 Aug 09:38:20 BST 2016
..mais j'ai du mal à comprendre comment sed
parcourir le fichier et convertir toutes les entrées. Le format de fichier ressemble à ceci:
#1472047795
ll /data/holding/email
#1472047906
cat /etc/rsyslog.conf
#1472048038
ll /data/holding/web
text-processing
sed
date
machinist
la source
la source
HISTTIMEFORMAT
variable shell pour contrôler le format au moment de l'écriture.date -d
n'est pas portable pour dire Solaris ... Je suppose que c'est sur un système avec principalement des outils GNU? (GNU AWK / Perl ont tendance à être les méthodes les plus portables pour gérer les conversions de dates).gawk '{ if ($0 ~ /^#[0-9]*$/) {print strftime("%c",substr($0,2)); } else {print} }' < file
(strftime
semble non portable ...)Réponses:
En supposant un format de fichier cohérent,
bash
vous pouvez lire le fichier ligne par ligne, tester s'il est dans un format donné, puis effectuer la conversion:BASH_REMATCH
est un tableau dont le premier élément est le premier groupe capturé dans la correspondance Regex,,=~
dans ce cas, l'époque.Si vous souhaitez conserver la structure du fichier:
cela affichera le contenu modifié dans STDOUT, pour l'enregistrer dans un fichier, par exemple
out.txt
:Maintenant, si vous le souhaitez, vous pouvez remplacer le fichier d'origine:
Exemple:
la source
bash
,printf
peut faire la conversion elle - même:printf '#%(%F %H)T\n' "${BASH_REMATCH[1]}"
.Bien que cela soit possible avec GNU
sed
avec des choses comme:Ce serait terriblement inefficace (et il est facile d'introduire des vulnérabilités arbitraires d'injection de commandes 1 ) car cela signifierait exécuter un shell et une
date
commande pour chaque#xxxx
ligne, pratiquement aussi mauvais qu'unewhile read
boucle shell . Ici, il serait préférable d'utiliser des choses commeperl
ougawk
, c'est-à-dire des utilitaires de traitement de texte qui ont des capacités de conversion de date intégrées:Ou:
1 Si nous avions écrit à la
^#([0-9]).*
place de^#([0-9]).*$
(comme je l'ai fait dans une version antérieure de cette réponse), alors dans des paramètres régionaux à plusieurs octets comme ceux en UTF-8 (la norme de nos jours), avec une entrée comme#1472047795<0x80>;reboot
, où c'est<0x80>
la valeur d'octet 0x80 qui ne forme pas un caractère valide, cettes
commande aurait fini par s'exécuterdate -d@1472047795<0x80>; reboot
par exemple. Avec le supplément$
, ces lignes ne seraient pas remplacées. Une approche alternative serait:s/^#([0-9])/date -d @\1 #/e
laisser la partie après la#xxx
date sous forme de commentaire shellla source
date -f
pour effectuer toutes les conversions de manière rationnelle?s
drapeau fait en sorte que.*
la nouvelle ligne soit également entrée. Vous pouvez également utiliserstrftime "%c", localtime $1
.Toutes les autres réponses engendrent un nouveau
date
processus pour chaque date d'époque qui doit être convertie. Cela pourrait potentiellement ajouter des frais généraux de performances si votre entrée est volumineuse.Cependant, GNU date a une
-f
option pratique qui permet à une seule instance de processus dedate
lire en continu les dates d'entrée sans avoir besoin d'un nouveau fork. Nous pouvons donc utilisersed
,paste
etdate
de cette manière, que chacun ne soit généré qu'une seule fois (2x poursed
), quelle que soit la taille de l'entrée:sed
commandes suppriment respectivement les lignes paires et impaires de l'entrée; le premier remplace également#
par@
pour donner le format d'horodatage correct.sed
sortie est ensuite dirigée versdate -f
laquelle effectue la conversion de date requise, pour chaque ligne d'entrée qu'elle reçoit.paste
. Les<( )
constructions sont des substitutions de processus bash qui incitent efficacement le collage à penser qu'il lit à partir de noms de fichiers donnés alors qu'il lit en fait la sortie canalisée depuis la commande à l'intérieur.-d '\n'
indiquepaste
de séparer les lignes de sortie impaires et paires avec une nouvelle ligne. Vous pouvez modifier (ou supprimer) cela si, par exemple, vous voulez que l'horodatage soit sur la même ligne que l'autre texte.Notez qu'il y a plusieurs GNUisms et Bashisms dans cette commande. Ce n'est pas compatible Posix et ne devrait pas être portable en dehors du monde GNU / Linux. Par exemple,
date -f
fait autre chose sur ladate
variante OSXes BSD .la source
date -d
(à partir de la question) est également non portable ... (Sur FreeBSD, il essaiera de jouer avec les paramètres DST, sur Solaris, il donnera une erreur ...) La question ne spécifie cependant pas de système d'exploitation ...En supposant que le format de date que vous avez dans votre message soit ce que vous voulez, l'expression régulière suivante devrait répondre à vos besoins.
Gardez à l'esprit que cela ne remplacera qu'une seule époque par ligne.
la source
sed: -e expression #1, char 48: invalid reference \3 on 's' command's RHS
en utilisant sed:
production :
comme ma langue locale est l'arabe :)
la source
Ma solution comment faire cela dans un pipeline
la source