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
date
puede 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
date
puede operar en un archivo, convirtiendo fechas en un solo lote.
Para convertir fechas por lotes con GNU, date
tenemos que extraer las marcas de tiempo y anteponerlas con @
:
$ sed 's/^\([^ ]*\).*$/@\1/' data.in
@1137921146.499
@1137921158.698
@1137921758.163
@1137921802.016
La sed
expresió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