Conversión de la columna de marca de tiempo de época de Unix en cada fila usando sed o awk

Conversión de la columna de marca de tiempo de época de Unix en cada fila usando sed o awk

Tengo un archivo con los siguientes datos de muestra de entrada:

1137921146.499 180900 61.153.158.197 1409 
1137921158.698 181622 61.153.158.197 1409
1137921758.163 180026 221.226.124.114 1374
1137921802.016 179485 121.13.128.132 1409

la primera columna es la marca de tiempo de la época de Unix que necesito convertir a un formato legible por humanos y además quiero que los datos se delimiten de la siguiente manera

Sun Jan 22 01:12:26 PST 2006|180900|61.153.158.197|1409   
Sun Jan 22 01:12:38 PST 2006|181622|61.153.158.19|1409

Intenté agregar delimitadores usando sed 's/ {1,}/|/g' y convirtiendo la fecha usando date -d @1137921146.499. Pero no puedo unir estos dos con un solo comando.

Respuesta1

Puedes usar un programa awk como este:

awk '{ print strftime("%c",$1)"|" $2"|"$3"|"$4 }' file

el núcleo es usar la función strftime para convertir la época al formato de fecha

Aquí está el resultado:

#awk '{ print strftime("%c",$1)"|" $2"|"$3"|"$4 }' file
Sun Jan 22 10:12:26 2006|180900|61.153.158.197|1409
Sun Jan 22 10:12:38 2006|181622|61.153.158.197|1409
Sun Jan 22 10:22:38 2006|180026|221.226.124.114|1374
Sun Jan 22 10:23:22 2006|179485|121.13.128.132|1409

PD: O puedes usar un delimitador de salida implícito:

awk  'BEGIN { OFS="|"} {$1= strftime("%c",$1) }1' file

Respuesta2

Usando lo que ya sabes:

  • GNU datepuede convertir una marca de tiempo en una fecha formateada dándole @timestamp.
  • Reemplazar espacios por |le dará el resultado que desea.

A eso le sumamos

  • GNU datepuede operar en un archivo, convirtiendo fechas en un solo lote.

Para convertir fechas por lotes con GNU, datetenemos que extraer las marcas de tiempo y anteponerlas con @:

$ sed 's/^\([^ ]*\).*$/@\1/' data.in
@1137921146.499
@1137921158.698
@1137921758.163
@1137921802.016

La sedexpresión sustituye cada línea con el primer campo delimitado por espacios con el prefijo @.

Con bash(y ksh93, o cualquier shell que comprenda las sustituciones de procesos):

$ date -f <( sed 's/^\([^ ]*\).*$/@\1/' data.in )
Sun Jan 22 10:12:26 CET 2006
Sun Jan 22 10:12:38 CET 2006
Sun Jan 22 10:22:38 CET 2006
Sun Jan 22 10:23:22 CET 2006

Luego necesitamos tomar los otros campos de los datos de entrada y reemplazar los delimitadores:

$ cut -d ' ' -f 2- data.in | tr ' ' '|'
180900|61.153.158.197|1409
181622|61.153.158.197|1409
180026|221.226.124.114|1374
179485|121.13.128.132|1409

Luego pegamos estas dos cosas junto con un |delimitador como:

$ paste -d '|' <( date -f <( sed 's/^\([^ ]*\).*$/@\1/' data.in ) ) <( cut -d ' ' -f 2- data.in | tr ' ' '|' )
Sun Jan 22 10:12:26 CET 2006|180900|61.153.158.197|1409
Sun Jan 22 10:12:38 CET 2006|181622|61.153.158.197|1409
Sun Jan 22 10:22:38 CET 2006|180026|221.226.124.114|1374
Sun Jan 22 10:23:22 CET 2006|179485|121.13.128.132|1409

Respuesta3

O con tu caparazón:

while read timestamp pid ip port; do
  echo "$(date -d @$timestamp)|$pid|$ip|$port"
done <yourfile

información relacionada