Používám Solaris 10, takže možnosti grep zahrnující -f nefungují.
Mám dva soubory oddělené svislou čarou:
soubor1:
abc|123|BNY|apple|
cab|234|cyx|orange|
def|kumar|pki|bird|
soubor 2:
abc|123|
kumar|pki|
cab|234
Chtěl bych porovnat první dva sloupce souboru2 se souborem1 (prohledejte celý obsah souboru1 v prvních dvou sloupcích), pokud se shodují s tiskem odpovídající řádky souboru1. Potom vyhledejte druhý řádek souboru 2 a tak dále.
Očekávaný výstup:
abc|123|BNY|apple|
cab|234|cyx|orange|
Soubory, které mám, jsou obrovské a obsahují asi 400 000 řádků, takže bych rád, aby bylo provádění rychlé.
Přijatá odpověď:
K tomu byl awk navržen:
$ awk -F'|' 'NR==FNR{c[$1$2]++;next};c[$1$2] > 0' file2 file1
abc|123|BNY|apple|
cab|234|cyx|orange|
Vysvětlení
-F'|'
:nastaví oddělovač polí na|
.NR==FNR
:NR je číslo aktuálního vstupního řádku a FNR číslo řádku aktuálního souboru. Tyto dva se budou rovnat pouze při čtení prvního souboru.-
c[$1$2]++; next
:pokud se jedná o 1. soubor, uložte 1. dvě pole doc
pole. Potom přeskočte na další řádek, aby se to použilo pouze na 1. soubor. -
c[$1$2]>0
:blok else bude proveden pouze v případě, že se jedná o druhý soubor, takže zkontrolujeme, zda pole 1 a 2 tohoto souboru již byla zobrazena (c[$1$2]>0
) a pokud byly, vytiskneme řádek. Vawk
, výchozí akcí je vytisknout řádek, takže pokudc[$1$2]>0
je true, řádek se vytiskne.
Případně, protože jste označili Perlem:
perl -e 'open(A, "file2"); while(<A>){/.+?|[^|]+/ && $k{$&}++};
while(<>){/.+?|[^|]+/ && do{print if defined($k{$&})}}' file1
Vysvětlení
První řádek otevře file2
, přečtěte si vše až do 2. |
(.+?|[^|]+
) a uložte jej ($&
je výsledkem operátoru poslední shody) v %k
hash.
Druhý řádek zpracovává soubor1, používá stejný regulární výraz k extrakci prvních dvou sloupců a vytiskne řádek, pokud jsou tyto sloupce definovány v %k
hash.
Oba výše uvedené přístupy budou muset držet 2 první sloupce souboru2 v paměti. To by neměl být problém, pokud máte jen několik set tisíc řádků, ale pokud ano, můžete udělat něco jako
cut -d'|' -f 1,2 file2 | while read pat; do grep "^$pat" file1; done
Ale to bude pomalejší.
Související:Zkopírovat všechny nainstalované programy a soubory na pevný disk (který má 32bitový Windows 7) a naklonovat/přenést jej do jiného počítače, který má 64bitový Windows 7?