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