Se i file sono ordinati (sono nel tuo esempio):
comm -23 file1 file2
-23
sopprime le righe che si trovano in entrambi i file o solo nel file 2. Se i file non sono ordinati, reindirizzali attraverso sort
prima...
Vedi la pagina man qui
vieni in soccorso!
Questa soluzione non richiede input ordinati. Devi fornire prima il fileB.
awk 'NR==FNR{a[$0];next} !($0 in a)' fileB fileA
ritorna
A
C
Come funziona?
NR==FNR{a[$0];next}
idiom serve per memorizzare il primo file in un array associativo come chiavi per un successivo test "contiene".
NR==FNR
sta controllando se stiamo scansionando il primo file, dove il contatore di righe globale (NR) è uguale al contatore di righe del file corrente (FNR).
a[$0]
aggiunge la riga corrente all'array associativo come chiave, nota che questo si comporta come un set, dove non ci saranno valori duplicati (chiavi)
!($0 in a)
ora siamo nel prossimo file,in
è un test di contiene, qui controlla se la riga corrente è nel set che abbiamo popolato nel primo passaggio dal primo file,!
nega la condizione. Ciò che manca qui è l'azione, che per impostazione predefinita è{print}
e di solito non scritto esplicitamente.
Tieni presente che ora può essere utilizzato per rimuovere le parole dalla lista nera.
$ awk '...' badwords allwords > goodwords
con una leggera modifica può pulire più elenchi e creare versioni pulite.
$ awk 'NR==FNR{a[$0];next} !($0 in a){print > FILENAME".clean"}' bad file1 file2 file3 ...
Un altro modo per fare la stessa cosa (richiede anche un input ordinato):
join -v 1 fileA fileB
In Bash, se i file non sono preordinati:
join -v 1 <(sort fileA) <(sort fileB)
grep -Fvxf <lines-to-remove> <all-lines>
- funziona su file non ordinati (a differenza di
comm
) - mantiene l'ordine
- è POSIX
Esempio:
cat <<EOF > A
b
1
a
0
01
b
1
EOF
cat <<EOF > B
0
1
EOF
grep -Fvxf B A
Uscita:
b
a
01
b
Spiegazione:
-F
:usa stringhe letterali invece del BRE predefinito-x
:considera solo le corrispondenze che corrispondono all'intera riga-v
:stampa non corrispondente-f file
:prende i modelli dal file specificato
Questo metodo è più lento sui file preordinati rispetto ad altri metodi, poiché è più generale. Se anche la velocità è importante, vedi:Modo rapido per trovare righe in un file che non sono in un altro?
Ecco una rapida automazione bash per il funzionamento in linea:
remove-lines() (
remove_lines="$1"
all_lines="$2"
tmp_file="$(mktemp)"
grep -Fvxf "$remove_lines" "$all_lines" > "$tmp_file"
mv "$tmp_file" "$all_lines"
)
GitHub a monte.
utilizzo:
remove-lines lines-to-remove remove-from-this-file
Vedi anche:https://unix.stackexchange.com/questions/28158/is-there-a-tool-to-get-the-lines-in-one-file-that-are-not-in-other