Tengo un conjunto de datos de vuelos en un archivo CSV y quiero obtener un porcentaje de vuelos retrasados (columna 6) ordenados por día. 0 es para no retrasado y 1 es para retraso de 15 minutos o más.
Aporte:
DAY_OF_MONTH,"DAY_OF_WEEK","ORIGIN","DEST","DEP_TIME","DEP_DEL15","CANCELLED","DIVERTED","DISTANCE"
1,Tuesday,ORD,GRB,1003,0.00,0.00,0.00,322.248
1,Tuesday,TUL,ORD,1027,0.00,0.00,0.00,1083.42
1,Tuesday,EWR,TYS,1848,0.00,0.00,0.00,1168.61
Producción:
Weekday, % delayed, delayed, total flights
Tuesday,0.00,0,3
En realidad, el conjunto de datos tiene muchas filas y tiene todos los días de un mes y todos sus vuelos, por lo que ese no sería el resultado real.
Alguien me ayudó a pensar:
#!/bin/awk
BEGIN { FS = OFS = "," }
FNR > 1 { total[$2]++; if ($6) delay[$2]++ }
END {
print "\"weekday\"", "\"percentage_delayed\"", "\"delayed\"", "\"total_flights\""
for ( day in total ) { print day, delay[day] / total[day] * 100, delay[day], total[day]}
}
Pero cuando guardo esto en un archivo awk e intento ejecutarlo con:
Respuesta1
Cuando #!/bin/awk
le estás diciendo a awk que se ejecute usando elnombredel archivo que contiene el script como el script en lugar delcontenidodel archivo que contiene el script. Es como escribir:
awk './delayed_by_day_jan20.awk'
en lugar de:
awk -f './delayed_by_day_jan20.awk'
Al igual que especificar un archivo que contiene un script awk en la línea de comando, también debe usarlo -f
en un shebang para decirle a awk que abra el nombre del archivo que pasó (es decir, el nombre del archivo de script actual) y use su contenido como el script awk. interpretar.
Una vez dicho esto....
Considere cada comando que escriba en Unix como solo un comando. No importa si ese comando está escrito en awk, perl, shell o cualquier otra cosa; debe nombrarse según su nombre.hace, no cómo se implementa. Dado eso, nunca debes tener comandos que terminen en .awk
o .sh
o .perl
cualquier otra cosa que indique el idioma en el que están escritos para que, entre otras cosas, puedas volver a implementar cualquier comando que escribiste en awk en perl o viceversa sin tener que revisar todos los demás comandos que llaman a ese comando para cambiarlos. Entonces el nombre de tu comando debería ser delayed_by_day_jan20
, no delayed_by_day_jan20.awk
.
Además, otros no están de acuerdo con esto porque les gusta usar un editor que entienda la sintaxis de awk, pero en mi opinión, nunca debes usar un shebang para llamar a awk, solo usa el shebang para llamar a cualquier shell que uses y luego simplemente llama a awk dentro de tu script de shell. como lo llamarías desde la línea de comando. Eso reducirá en gran medida la complejidad de sus scripts para aquellos casos extremadamente comunes en los que es útil hacer la mayor parte del trabajo en awk pero también partes del mismo en shell, por ejemplo, validar la existencia de archivos de entrada, crear archivos temporales, establecer trampas, separar argumentos de comandos en Asignaciones de variables awk versus argumentos awk, etc., etc. Consultehttps://stackoverflow.com/a/61002754/1745001ygoogle "awk shebang"para obtener más información sobre los problemas.
Aquí se explica cómo escribir su script de shell:
$ cat delayed_by_day_jan20
#!/usr/bin/env bash
awk '
BEGIN { FS = OFS = "," }
FNR > 1 { total[$2]++; if ($6) delay[$2]++ }
END {
print "\"weekday\"", "\"percentage_delayed\"", "\"delayed\"", "\"total_flights\""
for ( day in total ) {
printf "%s,%0.2f,%d,%d\n", day, delay[day] / total[day] * 100, delay[day], total[day]
}
}
' "${@:--}"
$ ./delayed_by_day_jan20 file
"weekday","percentage_delayed","delayed","total_flights"
Tuesday,0.00,0,3
Ahora simplemente arregle su script awk para que haga lo que quiera que haga si no es así y haga una nueva pregunta si tiene problemas para hacerlo.