Pokud jsou soubory seřazeny (jsou ve vašem příkladu):
comm -23 file1 file2
-23
potlačí řádky, které jsou v obou souborech, nebo pouze v souboru 2. Pokud soubory nejsou seřazeny, propojte je přes sort
první...
Viz manuálovou stránku zde
awk na záchranu!
Toto řešení nevyžaduje tříděné vstupy. Nejprve musíte poskytnout soubor B.
awk 'NR==FNR{a[$0];next} !($0 in a)' fileB fileA
vrací
A
C
Jak to funguje?
NR==FNR{a[$0];next}
idiom je pro uložení prvního souboru v asociativním poli jako klíče pro pozdější test "obsahuje".
NR==FNR
kontroluje, zda skenujeme první soubor, kde se globální počítadlo řádků (NR) rovná aktuálnímu počítadlu řádků souboru (FNR).
a[$0]
přidá aktuální řádek do asociativního pole jako klíč, všimněte si, že se to chová jako sada, kde nebudou žádné duplicitní hodnoty (klíče)
!($0 in a)
nyní jsme v dalším souboru (souborech),in
je test obsahuje, zde se kontroluje, zda je aktuální řádek v sadě, kterou jsme naplnili v prvním kroku z prvního souboru,!
neguje podmínku. Co zde chybí, je akce, která je ve výchozím nastavení{print}
a obvykle nejsou psány explicitně.
Všimněte si, že toto lze nyní použít k odstranění slov z černé listiny.
$ awk '...' badwords allwords > goodwords
s malou změnou může vyčistit více seznamů a vytvořit vyčištěné verze.
$ awk 'NR==FNR{a[$0];next} !($0 in a){print > FILENAME".clean"}' bad file1 file2 file3 ...
Další způsob, jak udělat totéž (také vyžaduje seřazený vstup):
join -v 1 fileA fileB
V Bash, pokud soubory nejsou předtříděné:
join -v 1 <(sort fileA) <(sort fileB)
grep -Fvxf <lines-to-remove> <all-lines>
- funguje na netříděných souborech (na rozdíl od
comm
) - udržuje objednávku
- je POSIX
Příklad:
cat <<EOF > A
b
1
a
0
01
b
1
EOF
cat <<EOF > B
0
1
EOF
grep -Fvxf B A
Výstup:
b
a
01
b
Vysvětlení:
-F
:místo výchozího BRE
použijte doslovné řetězce -x
:zohledňují pouze shody, které odpovídají celému řádku-v
:tisk neodpovídající-f file
:převzít vzory z daného souboru
Tato metoda je pomalejší u předem setříděných souborů než jiné metody, protože je obecnější. Pokud záleží také na rychlosti, viz:Rychlý způsob hledání řádků v jednom souboru, které nejsou v jiném?
Zde je rychlá automatizace bash pro in-line provoz:
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 upstream.
použití:
remove-lines lines-to-remove remove-from-this-file
Viz také:https://unix.stackexchange.com/questions/28158/is-there-a-tool-to-get-the-lines-in-one-file-that-are-not-in-another