GNU/Linux >> Tutoriales Linux >  >> Linux

¿Seleccionar líneas del archivo de texto que tienen identificadores enumerados en otro archivo?

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

Linux
  1. ¿Cómo eliminar líneas duplicadas dentro de un archivo de texto?

  2. ¿Reemplazar líneas que coinciden con un patrón con líneas de otro archivo en orden?

  3. ¿Cómo eliminar varias líneas aleatorias de un archivo de texto usando Sed?

  4. ¿Copiar las últimas líneas N de un archivo a otro?

  5. Awk de diferentes líneas?

Cómo crear directorios desde un archivo de texto en Linux

Cómo imprimir líneas duplicadas en un archivo de texto en Linux

Cómo eliminar archivos enumerados en otro archivo en Linux

¿Cómo selecciono todo el texto de un archivo con nano?

¿Cómo extraer texto de un archivo grande, comenzando en la primera aparición de una cadena?

¿Cómo mostrar ciertas líneas de un archivo de texto en Linux?