Tengo un archivo csv. Sus números de línea son máximo 25.
Encabezamientosson hora (UTC) (primer campo), latitud (segundo campo), longitud (tercer campo), profundidad (cuarto campo), magnitud (quinto campo), lugar (decimocuarto campo), etc.
Data de muestra
2019-12-10T21:58:28.816Z 35.488 26.4157 57.32 5.4 35km NNE of Palaikastron, Greece
2019-12-11T11:54:27.670Z 18.6158 -67.2838 85 2.85 23km NW of San Antonio, Puerto Rico
Primero, quiero insertar un encabezado, incluida la variable incorporada fieldwith. Segundo, quiero convertirhora (utc)aUTC+03:00y dividir en fecha y hora de los encabezados y cambiar su formato de fecha. En tercer lugar, quiero extraer coincidencias entre 'de'palabra ycomaantes del nombre del país para el campo 14.
Salida deseada como títulos:
Date Time Latitude Longitude Depth Mag Place
Salida deseada:
11.12.2019 00:58:28 35.488 26.4157 57.32 5.4 Palaikastron
11.12.2019 14:54:27 18.6158 -67.2838 85 2.85 San Antonio
time,latitude,longitude,depth,mag,magType,nst,gap,dmin,rms,net,id,updated,place,type,horizontalError,depthError,magError,magNst,status,locationSource,magSource
2019-12-06T13:04:46.931Z,-15.2838,-175.1193,10,6,mww,,50,3.512,0.81,us,us60006n19,2019-12-07T13:11:48.228Z,"164km WNW of Hihifo, Tonga",earthquake,8.4,1.9,0.08,15,reviewed,us,us
2019-12-04T20:10:03.614Z,-19.0515,169.5628,266,6,mww,,21,2.812,0.82,us,us60006m2j,2019-12-05T23:44:01.300Z,"63km NNE of Isangel, Vanuatu",earthquake,7.6,1.9,0.037,71,reviewed,us,us
2019-12-03T08:46:36.374Z,-18.5597,-70.6504,32.44,6,mww,,112,0.31,1.4,us,us70006fh7,2019-12-05T08:07:29.617Z,"37km WSW of Arica, Chile",earthquake,6.2,7.8,0.069,20,reviewed,us,us
2019-12-02T05:01:54.693Z,51.3218,-178.2425,27.33,6,mww,,104,0.862,0.97,us,us70006f6d,2019-12-07T02:09:55.119Z,"60km E of Amatignak Island, Alaska",earthquake,6.7,4.2,0.066,22,reviewed,us,us
2019-11-27T07:23:42.552Z,35.7272,23.2673,71.76,6,mww,,23,1.394,1.16,us,us70006dlt,2019-12-03T23:18:27.456Z,"41km NW of Platanos, Greece",earthquake,5.8,5.4,0.046,46,reviewed,us,us
2019-11-26T02:54:12.594Z,41.5112,19.5151,20,6.4,mww,,17,0.937,0.58,us,us70006d0m,2019-12-09T15:46:11.689Z,"16km WSW of Mamurras, Albania",earthquake,3.5,1.8,0.037,72,reviewed,us,us
2019-11-24T00:54:01.052Z,51.3809,-175.5108,20,6.3,mww,,22,0.658,0.95,us,us70006cb6,2019-12-10T01:04:03.731Z,"96km SE of Adak, Alaska",earthquake,3.9,1.8,0.05,38,reviewed,us,us
2019-11-23T12:11:16.261Z,1.6286,132.7854,10,6.1,mww,,38,4.549,1.1,us,us70006c6w,2019-11-25T21:00:33.040Z,"Papua region, Indonesia",earthquake,7.8,1.8,0.061,26,reviewed,us,us
2019-11-20T23:50:43.955Z,19.4533,101.3558,10,6.2,mww,,15,2.366,0.62,us,us70006ara,2019-12-04T05:52:37.313Z,"32km ESE of Chaloem Phra Kiat, Thailand",earthquake,6.4,1.7,0.049,40,reviewed,us,us
Si puedo lograr una cosa, no hago otras.es un reto para mi. Guíame, por favor. Por un lado, tienen dificultades para entender cómo utilizarlo awk
. Por otro lado, awk
las funciones de tiempo son muy útiles. Estoy tan confundido ahora. Lo que sea que he intentado, no lo hago bien.
Respuesta1
Aunque aprender awk es un objetivo admirable, no tiene ningún mecanismo incorporado para analizar archivos CSV verdaderos (en particular, campos que pueden contener delimitadores entre comillas o escapes), y las funciones de tiempo son específicas de GNU y no portátiles.
Por estas razones es posible que desees considerar el uso de Perl (con suTexto::CSVmódulo), Python - o mi favorito actual para este tipo de cosas,Molinero. Además de proporcionar un verdadero análisis de CSV, estos también proporcionan una strptime
función adecuada, mientras que incluso con GNU awk mktime
es necesario analizar y ensamblar manualmente el datespec
argumento.
En Miller, por ejemplo, podrías hacer lo siguiente:
mlr --csv \
put -S '
s = strptime($time,"%Y-%m-%dT%H:%M:%SZ") + 3*3600;
$date = strftime(s,"%d.%m.%Y");
$time = strftime(s,"%H:%M:%S");
$place =~ "(.* of |)([^,]*),(.*)$" { $place = "\2" }
' then cut -o -f date,time,latitude,longitude,depth,mag,place input.csv
Si desea columnas de salida separadas por espacios en blanco, cambie --csv
a --icsv --opprint
(salida tabular "bastante impresa", con encabezados) o --icsv --onidx
(salida simple separada por espacios).
Ex.
$ mlr --icsv --opprint put -S '
s = strptime($time,"%Y-%m-%dT%H:%M:%SZ") + 3*3600;
$date = strftime(s,"%d.%m.%Y");
$time = strftime(s,"%H:%M:%S");
$place =~ "(.* of |)([^,]*),(.*)$" { $place = "\2" }
' then cut -o -f date,time,latitude,longitude,depth,mag,place input.csv
date time latitude longitude depth mag place
06.12.2019 16:04:46 -15.2838 -175.1193 10 6 Hihifo
04.12.2019 23:10:03 -19.0515 169.5628 266 6 Isangel
03.12.2019 11:46:36 -18.5597 -70.6504 32.44 6 Arica
02.12.2019 08:01:54 51.3218 -178.2425 27.33 6 Amatignak Island
27.11.2019 10:23:42 35.7272 23.2673 71.76 6 Platanos
26.11.2019 05:54:12 41.5112 19.5151 20 6.4 Mamurras
24.11.2019 03:54:01 51.3809 -175.5108 20 6.3 Adak
23.11.2019 15:11:16 1.6286 132.7854 10 6.1 Papua region
21.11.2019 02:50:43 19.4533 101.3558 10 6.2 Chaloem Phra Kiat
Miller está disponible en el universe
repositorio de Ubuntu.
Respuesta2
Primero, necesitarás preprocesar la entrada CSV para manejar mejor la coma incrustada. Luego divida el AWK en partes funcionales.
$ cat preprocess.sed
#!/bin/sed -f
:start # loop back to here
/"/{ # for any line that has a double quote
h # copy to the hold buffer
s/[^"]*"\([^"]*\).*/\1/ # what is between the first pair of dquotes
s/,/@@/g # replace comma with '@@'
G # append the hold buffer to the pattern buffer
# so we get what was in dqoutes followed by a newline followed by the
# original line
s/\(.*\)\n\([^"]*\)"\([^"]*\)"\(.*\)/\2\1\4/
# replace the unquoted part with what was there
t start # go back to 'start'
}
Esto reemplazará el ".*,.*"
con .*@@.*
, lo que facilitará las cosas para AWK.
Para cambiar solo la fecha a una nueva zona horaria, reemplace la primera línea:
$ cat change_date.sh
#!/bin/sh
userTZ="${1:-UTC+3}"
sed 's/,/ /' |
while read datestr rest; do
if [ "${datestr}" = time ]; then
newdate="${datestr}"
else
newdate=$(TZ=${userTZ} date -d "${datestr}" "+%d %m %Y %H:%M:%S")
fi
echo "${newdate}:${rest}"
done
El script AWK se vería así:
$ cat reformat.awk
#!/bin/awk -f
BEGIN {IFS=","} # comma separated fields
NR==1 {print; next;} # print the header and do nothing more with it
{ # get just the "town" from the place field
sub(/.* of /,"",$14) # strip up to the " of "
sub(/@@ .*/,"",$14) # strip after the embedded comma (now '@@')
}
{
printf("%s %8.3f %8.3f %8.3fs %8.3f %s\n", $1, $2, $3, $4, $5, $14)
}
Asegúrese de que ambos sean ejecutables y se ejecutenpreprocess.sed sample.csv | change_date.sh | reformat.awk
O en una línea:
sed ':start;/"/{;h;s/[^"]*"\([^"]*\).*/\1/;s/,/@@/g;G;s/\(.*\)\n\([^"]*\)"\([^"]*\)"\(.*\)/\2\1\4/;t start;};s/,/ /' test.csv | while read datestr rest; do if [ "$datestr" = "time" ]; then newdate="${datestr}"; else newdate=$(TZ=UTC+3 date -d "$datestr" "+%d %m %Y %H:%M:%S"); fi; echo "${newdate},${rest}"; done | awk -F, 'NR==1 {print;next} {sub(/.* of /,"",$14);sub(/@@ .*/,"",$14)} {printf("%s %8.3f %8.3f %8.3fs %8.3f %s\n", $1, $2, $3, $4, $5, $14)}'