GNU/Linux >> Linux Esercitazione >  >> Linux

Seleziona le righe dal file di testo che hanno gli ID elencati in un altro file?

Uso molto grep awk sort nella mia shell unix per lavorare con file di testo di colonne separate da tabulazioni di medie dimensioni (circa 10M-100M linee). A questo proposito, la shell unix è il mio foglio di calcolo.

Ma ho un grosso problema, ovvero selezionare i record a cui è assegnato un elenco di ID.

Avere table.csv file con formato idtfootbar... e ids.csv file con elenco di ID, seleziona solo i record da table.csv con ID presente in ids.csv .

tipo di https://stackoverflow.com/questions/13732295/extract-all-lines-from-text-file-based-on-a-given-list-of-ids ma con shell, non perl.

grep -F ovviamente produce falsi positivi se gli ID sono di larghezza variabile.
join è un'utilità che non potrei mai capire. Prima di tutto, richiede l'ordinamento alfabetico (i miei file sono solitamente ordinati numericamente), ma anche in questo caso non riesco a farlo funzionare senza lamentarmi di un ordine errato e saltare alcuni record. Quindi non mi piace.
grep -f contro file con ^idt -s è molto lento quando il numero di ID è grande.
awk è ingombrante.

Ci sono buone soluzioni per questo? Qualche strumento specifico per i file separati da tabulazioni? Anche le funzionalità extra saranno molto gradite.

UPD:corretto sort -> join

Risposta accettata:

Immagino tu intendessi grep -f non grep -F ma in realtà hai bisogno di una combinazione di entrambi e -w :

grep -Fwf ids.csv table.csv

Il motivo per cui stavi ottenendo falsi positivi è (suppongo, non l'hai spiegato) perché se un ID può essere contenuto in un altro, verranno stampati entrambi. -w rimuove questo problema e -F assicura che i tuoi modelli siano trattati come stringhe, non come espressioni regolari. Da 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.)

Se i tuoi falsi positivi sono dovuti al fatto che un ID può essere presente in un campo non ID, esegui invece il ciclo del tuo file:

while read pat; do grep -w "^$pat" table.csv; done < ids.csv

o, più veloce:

xargs -I {} grep "^{}" table.csv < ids.csv

Personalmente, lo farei in perl però:

perl -lane 'BEGIN{open(A,"ids.csv"); while(<A>){chomp; $k{$_}++}} 
            print $_ if defined($k{$F[0]}); ' table.csv

Linux
  1. Sostituire le righe che corrispondono a un motivo con le righe di un altro file in ordine?

  2. Come eliminare più righe casuali da un file di testo utilizzando Sed?

  3. Creare dati di lettura di testo da un file?

  4. Come rimuovo le nuove righe da un file di testo?

  5. Rimuovi le righe pari o dispari da un file di testo

Come creare directory da un file di testo in Linux

Come stampare righe duplicate in un file di testo in Linux

Come eliminare i file elencati in un altro file in Linux

Awk da linee diverse?

Come rimuovere le linee che appaiono sul file B da un altro file A?

Rimuove le prime N righe da un file di registro attivo