With GNU awk for arrays of arrays:
$ awk '{a[$1][(NR>FNR)]=$2} END{for (i in a) print i, a[i][0], a[i][1]}' file{1,2}
1 dog woof
2 cat meow
3 fox
4 cow mooh
or with any awk:
$ awk '{keys[$1]; a[$1,(NR>FNR)]=$2} END{for (i in keys) print i, a[i,0], a[i,1]}' file{1,2}
1 dog woof
2 cat meow
3 fox
4 cow mooh
Although the above produces the output in numerically ascending order of the first field that's just luck/coincidence - the order of the output lines is actually "random" (typically hash order) courtesy of the "in" operator. Pipe the output to sort -k1,1n (or set PROCINFO["sorted_in"]="@ind_num_asc" at the start of the END section in GNU awk) if you care about that.
The significant differences between this and a join solution are that:
- This will work even if the input is not sorted while
join requires input sorted on the key field(s) and,
- If there's a line in file2 with a key not present in file1 (or vice-versa) this will display it spaced in a way that you can tell which file that unique line came from (unlike adding
-a2 to a join command).
Here's some more comprehensive sample input/output to test with:
$ head file{1,2}
==> file1 <==
1 dog
2 cat
4 cow
5 bear
==> file2 <==
1 woof
2 meow
3 growl
4 mooh
which we can then run either of the above awk scripts on to get the same output:
$ awk '{a[$1][(NR>FNR)]=$2} END{for (i in a) print i, a[i][0], a[i][1]}' file{1,2}
1 dog woof
2 cat meow
3 growl
4 cow mooh
5 bear
and note that 3 growl has an extra blank before growl so you know that was a unique line from file2 as opposed to using join:
$ join -a1 -a2 file1 file2
1 dog woof
2 cat meow
3 growl
4 cow mooh
5 bear
where you can't tell a unique line from file1 (e.g. 5 bear) from a unique line from file2 (e.g. 3 growl).