If the files are sorted (the samples you posted are) then it's as simple as
join -t : File1.txt File2.txt
join
pairs up lines from two files where the join field is equal. By default, the join field is the first field, the fields are output in order except that the join field is not repeated, and non-pairable lines are skipped, which is exactly what you want.
Note that if the files have Windows line endings, they appear under Unix systems to have an extra carriage return character at the end of each line. The CR is mostly visually invisible, but as far as join
and other text tools are concerned, it's a character like any one else, and it means the fields of File1.txt
all end with a CR whereas the ones in File2.txt
don't so they don't match. You need to strip the CR, at least in File1.txt
.
<File1.txt tr -d '\r' | join -t : - File2.txt
You do need to sort the files. If they aren't, then ksh/bash/zsh, you can use process substitutions. (Add tr -d '\r' |
if needed.)
join -t : <(sort File1.txt) <(sort File2.txt)
In plain sh, if your Unix variant has /dev/fd
(most do), you can use that instead to pipe the output of two programs through two file descriptors.
sort File2.txt | { sort File1.txt | join -t : /dev/fd/0 /dev/fd/3; } 3<&1
If you need to preserve the original order of File1.txt
and it isn't sorted by the join field, then add line numbers to remember the original order, sort by the join field, join, sort by line numbers and strip the line numbers. (You can do something similar if you want to preserver the order of the other file.)
<File1.txt nl -s : |
sort -t : -k 2 |
join -t : -1 2 - <(sort File2.txt) |
sort -t : -k 2,2n |
cut -d : -f 1,3
File1.txt
orFile2.txt
in the result?