Utilizo mucho grep awk sort en mi shell de Unix para trabajar con archivos de texto de columnas separadas por tabuladores de tamaño mediano (alrededor de 10M-100M líneas). En este sentido, el shell de Unix es mi hoja de cálculo.
Pero tengo un gran problema, que es seleccionar registros dada una lista de ID.
Tener table.csv
archivo con formato idtfootbar...
y ids.csv
archivo con una lista de ID, solo seleccione registros de table.csv
con id presente en ids.csv
.
algo así como https://stackoverflow.com/questions/13732295/extract-all-lines-from-text-file-based-on-a-given-list-of-ids pero con shell, no perl.
grep -F
obviamente produce falsos positivos si los ID son de ancho variable.join
es una utilidad que nunca pude descifrar. En primer lugar, requiere una ordenación alfabética (mis archivos suelen estar ordenados numéricamente), pero aun así no puedo hacer que funcione sin quejarme del orden incorrecto y saltear algunos registros. Así que no me gusta.
grep -f contra archivo con ^idt
-s es muy lento cuando el número de ID es grande.awk
es engorroso.
¿Hay alguna buena solución para esto? ¿Alguna herramienta específica para archivos separados por tabulaciones? La funcionalidad adicional también será bienvenida.
UPD:sort
corregido -> join
Respuesta aceptada:
Supongo que quisiste decir grep -f
no grep -F
pero en realidad necesitas una combinación de ambos y -w
:
grep -Fwf ids.csv table.csv
La razón por la que estaba obteniendo falsos positivos es (supongo que no lo explicó) porque si una identificación puede estar contenida en otra, ambas se imprimirán. -w
elimina este problema y -F
se asegura de que sus patrones se traten como cadenas, no como expresiones regulares. De man grep
:
-F, --fixed-strings
Interpret PATTERN as a list of fixed strings, separated by
newlines, any of which is to be matched. (-F is specified by
POSIX.)
-w, --word-regexp
Select only those lines containing matches that form whole
words. The test is that the matching substring must either be
at the beginning of the line, or preceded by a non-word
constituent character. Similarly, it must be either at the end
of the line or followed by a non-word constituent character.
Word-constituent characters are letters, digits, and the
underscore.
-f FILE, --file=FILE
Obtain patterns from FILE, one per line. The empty file
contains zero patterns, and therefore matches nothing. (-f is
specified by POSIX.)
Si sus falsos positivos se deben a que una identificación puede estar presente en un campo que no es de identificación, recorra su archivo en su lugar:
while read pat; do grep -w "^$pat" table.csv; done < ids.csv
o, más rápido:
xargs -I {} grep "^{}" table.csv < ids.csv
Personalmente, haría esto en perl
aunque:
perl -lane 'BEGIN{open(A,"ids.csv"); while(<A>){chomp; $k{$_}++}}
print $_ if defined($k{$F[0]}); ' table.csv