Tengo un archivo que contiene fechas de época que necesito convertir a legible para humanos. Ya sé cómo hacer la conversión de fecha, por ejemplo:
[server01 ~]$ date -d@1472200700
Fri 26 Aug 09:38:20 BST 2016
.. pero estoy luchando por descubrir cómo sed
recorrer el archivo y convertir todas las entradas. El formato del archivo se ve así:
#1472047795
ll /data/holding/email
#1472047906
cat /etc/rsyslog.conf
#1472048038
ll /data/holding/web
text-processing
sed
date
maquinista
fuente
fuente
HISTTIMEFORMAT
variable de shell para controlar el formato al momento de la escritura.date -d
no es portátil para decir Solaris ... ¿Asumo que esto está en un sistema con herramientas GNU en su mayoría? (GNU AWK / Perl tienden a ser los métodos más portátiles para manejar las conversiones de fechas).gawk '{ if ($0 ~ /^#[0-9]*$/) {print strftime("%c",substr($0,2)); } else {print} }' < file
(strftime
parece no portátil ...)Respuestas:
Asumiendo un formato de archivo consistente,
bash
puede leer el archivo línea por línea, probar si está en el formato dado y luego realizar la conversión:BASH_REMATCH
es una matriz cuyo primer elemento es el primer grupo capturado en la coincidencia de expresiones regulares=~
, en este caso, la época.Si desea mantener la estructura del archivo:
esto generará el contenido modificado en STDOUT, para guardarlo en un archivo, por ejemplo
out.txt
:Ahora, si lo desea, puede reemplazar el archivo original:
Ejemplo:
fuente
bash
,printf
puede hacer la conversión en sí:printf '#%(%F %H)T\n' "${BASH_REMATCH[1]}"
.Si bien es posible con GNU
sed
con cosas como:Eso sería terriblemente ineficiente (y es fácil introducir vulnerabilidades arbitrarias de inyección de comandos 1 ) ya que eso significaría ejecutar un shell y un
date
comando para cada#xxxx
línea, prácticamente tan malo como unwhile read
bucle de shell . Aquí, sería mejor usar cosas comoperl
ogawk
, es decir, utilidades de procesamiento de texto que tienen capacidades de conversión de fecha incorporadas:O:
1 Si hubiéramos escrito en
^#([0-9]).*
lugar de^#([0-9]).*$
(como hice en una versión anterior de esta respuesta), entonces en entornos locales de varios bytes como UTF-8 (la norma hoy en día), con una entrada como#1472047795<0x80>;reboot
, donde ese<0x80>
es el valor de byte 0x80 que no forma un carácter válido, eses
comando habría terminado ejecutándosedate -d@1472047795<0x80>; reboot
por ejemplo. Mientras que con el extra$
, esas líneas no serían sustituidas. Un enfoque alternativo sería:s/^#([0-9])/date -d @\1 #/e
dejar la parte después de la#xxx
fecha como un comentario de shellfuente
date -f
para hacer todas las conversiones de una manera inteligente?s
bandera hace que eso.*
también incluya la nueva línea en la entrada. También puedes usarstrftime "%c", localtime $1
.Todas las demás respuestas generan un nuevo
date
proceso para cada fecha de época que necesita convertirse. Potencialmente, esto podría agregar una sobrecarga de rendimiento si su entrada es grande.Sin embargo, la fecha GNU tiene una
-f
opción práctica que permite que una sola instancia de procesodate
lea continuamente las fechas de entrada sin la necesidad de una nueva bifurcación. Por lo tanto, podemos usarsed
,paste
ydate
de esta manera, que cada uno solo se genere una vez (2 vecessed
) independientemente de cuán grande sea la entrada:sed
comandos respectivamente eliminan básicamente las líneas pares e impares de la entrada; el primero también se reemplaza#
por@
para dar el formato de marca de tiempo de época correcto.sed
Luego se canaliza la primera salida a ladate -f
que se realiza la conversión de fecha requerida, para cada línea de entrada que recibe.paste
. Las<( )
construcciones son sustituciones de procesos bash que efectivamente engañan a pegar para que piense que está leyendo los nombres de archivo dados cuando de hecho está leyendo la salida canalizada desde el comando interno.-d '\n'
le dicepaste
que separe las líneas de salida pares e impares con una nueva línea. Puede cambiar (o eliminar) esto si, por ejemplo, desea la marca de tiempo en la misma línea que el otro texto.Tenga en cuenta que hay varios GNUisms y Bashisms en este comando. Esto no es compatible con Posix y no debe esperarse que sea portátil fuera del mundo GNU / Linux. Por ejemplo,
date -f
hace algo más en ladate
variante BSD de OSX .fuente
date -d
(de la pregunta) tampoco es portátil ... (En FreeBSD intentará meterse con la configuración DST, en Solaris dará un error ...) La pregunta no especifica un sistema operativo ...Suponiendo que el formato de fecha que tiene en su publicación es el que desea, la siguiente expresión regular debe ajustarse a sus necesidades.
Tenga en cuenta el hecho de que esto solo reemplazará una época por línea.
fuente
sed: -e expression #1, char 48: invalid reference \3 on 's' command's RHS
usando sed:
salida:
como mi idioma local es el árabe :)
fuente
Mi solución como hacer eso en una tubería
fuente