Quiero ordenar un archivo delimitado por tabulaciones por un campo específico conservando el encabezado. Estoy usando awk
como se describe aquí.ordenar y uniq en awk, pero no sé a quién decirle sort
que el separador de campo es una pestaña.
Datos del juguete:
$ echo -e "head_1\thead_2\thead_3" > file.tsv
$ echo -e "aaa zzz\tc\t300" >> file.tsv
$ echo -e "bbb yyy ooo\ta\t100" >> file.tsv
$ echo -e "ccc xxx nnn\tb\t200" >> file.tsv
$ column -ts $'\t' file.tsv
head_1 head_2 head_3
aaa zzz c 300
bbb yyy ooo a 100
ccc xxx nnn b 200
$ awk -F'\t' 'NR==1; NR>1 { print | "sort -k2" }' file.tsv | column -ts $'\t'
head_1 head_2 head_3
ccc xxx nnn b 200 ## note these data are sorted
bbb yyy ooo a 100 ## based on the xxx/yyy/zzz
aaa zzz c 300 ## not the a/b/c
Cuando intento indicar explícitamente sort
que el separador de campo es una pestaña, aparece este error, que creo que está relacionado con problemas de citas:
$ awk -F'\t' 'NR==1; NR>1 { print | "sort -k2 -t $'\t'" }' file.tsv | column -ts $'\t'
sort: option requires an argument -- 't'
Try 'sort --help' for more information.
head_1 head_2 head_3
¿Cómo especifico el separador de columnas sort
dentro de `awk? Gracias
La interfaz web de SE hace un mejor trabajo de resaltado de sintaxis que Notepad++; Aquí hay un par de cosas que he probado:
$ awk -F'\t' 'NR==1; NR>1 { print | "sort -k2 -t $'$'\t''" }' file.tsv | column -ts $'\t'
head_1 head_2 head_3
aaa zzz c 300
bbb yyy ooo a 100
ccc xxx nnn b 200
$ awk -F'\t' 'NR==1; NR>1 { print | "sort -k2 -t $'\t'" }' file.tsv | column -ts $'\t'
sort: option requires an argument -- 't'
Try 'sort --help' for more information.
head_1 head_2 head_3
$ awk -F'\t' 'NR==1; NR>1 { print | "sort -k2 -t "'$'\t''"" }' file.tsv | column -ts $'\t'
sort: option requires an argument -- 't'
Try 'sort --help' for more information.
head_1 head_2 head_3
$ awk -F'\t' 'NR==1; NR>1 { print | "sort -k2 -t "'$'\t'' }' file.tsv | column -ts $'\t'
sort: option requires an argument -- 't'
Try 'sort --help' for more information.
head_1 head_2 head_3
Respuesta1
elige una de estas opciones:
... | "sort -k2 -t \\\t "
... | "sort -k2 -t \"\t\" "
... | "sort -k2 -t'\''\t'\'' "
... | "sort -k2 -t \047\011\047" ## preferred
\011
es el código ASCII del octeto paraPestañacarácter/ \047
para comillas simples '
awk -v q="'" ... { print | "sort -k2 -t " q "\t" q }'
awk -v tb="'\t'" ... { print | "sort -k2 -t " tb }'
awk -v tb=$'\t' ... { print | "sort -k2 -t \"" tb "\"" }'
awk -v tb=$'\t' -v q="'" ... { print | "sort -k2 -t " q tb q }'
y muchos más …; leerProblemas de cotización de Shell en awk; ver tambiénSecuencias de escape en awk
Respuesta2
Puede que esta no sea una forma adecuada de una sola línea, pero es simple y no es necesario jugar con el carácter de tabulación... :D
var=$(head -1 file.tsv);perl -ne '{ print $_ if $. > 1; }' file.csv| sort -k2 | sed "1 i $var" | column -ts "\t"
Respuesta3
FWIW, así es como resolvería su problema real de ordenar los datos pero conservando el encabezado en la parte superior:
awk -v OFS='\t' '{print (NR>1), $0}' file.tsv | sort -t$'\t' -k1,1n -k3 | cut -f2-
Lo anterior funciona anteponiendo un 0 o 1 a los datos de entrada (0 para la primera línea, 1 para todas las demás líneas) para que pueda ordenar ese indicador primero y luego la clave real que le interesa y luego simplemente eliminar ese campo agregado nuevamente. .
Aquí está funcionando por etapas:
$ awk -v OFS='\t' '{print (NR>1), $0}' file.tsv
0 head_1 head_2 head_3
1 aaa zzz c 300
1 bbb yyy ooo a 100
1 ccc xxx nnn b 200
$ awk -v OFS='\t' '{print (NR>1), $0}' file.tsv | sort -t$'\t' -k1,1n -k3
0 head_1 head_2 head_3
1 bbb yyy ooo a 100
1 ccc xxx nnn b 200
1 aaa zzz c 300
$ awk -v OFS='\t' '{print (NR>1), $0}' file.tsv | sort -t$'\t' -k1,1n -k3 | cut -f2-
head_1 head_2 head_3
bbb yyy ooo a 100
ccc xxx nnn b 200
aaa zzz c 300