Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I want to compare one file with other files in the same directory.

file1.txt contains:

move 34#123#    
get 11#278    
put 33#29#567#23

file1.txt should compare with files 1.txt and 2.txt.

1.txt contains:

move 11    
put 34    
run 13

2.txt contains:

get 14    
move 66

I need the results to be like this:

move 2    
get 1    
put 1

How can I accomplish this?

share|improve this question
You want the count of the number of move and get and put lines? – slm Apr 21 '14 at 6:43

Here is an awk solution:

$ awk 'FNR==NR{a[$1];next}($1 in a){++a[$1]}
    END{for(i in a){print i" "a[i]}}' file1.txt 1.txt 2.txt
put 1
get 1
move 2


  • FNR==NR{a[$1];next}: when processing file1.txt, we mark the occurence of $1 in associative array a.
  • ($1 in a){++a[$1]}: when processing 1.txt and 2.txt, we check if $1 is existed in associative array a, if yes, increasing the count by 1.
  • Finally, loop through associative array a, print the key (first field in files) and its value (number of ocurrences in 1.txt and 2.txt).

Here is another solution in perl, with the same logic:

$ perl -alne '++$i;                  
    if ($. == $i) {
        close ARGV if eof;
    ++$h{$F[0]} if defined $h{$F[0]};
    for (keys %h) {
        print $_." ".$h{$_};
}' file1.txt 1.txt 2.txt
move 2
get 1
put 1
share|improve this answer

Showing an alternative that uses a variety of tools, grep, awk, sort, & uniq. Granted it makes use of more tools but I find it easier to understand what's going on vs. AWK.

$ for i in 1.txt 2.txt; do grep -f <(awk '{print $1}' $i) file1.txt; done | \
    awk '{print $1}' | sort | uniq -c


$ for i in 1.txt 2.txt; do grep -f <(awk '{print $1}' $i) file1.txt; done | \
    awk '{print $1}' | sort | uniq -c
      1 get
      2 move
      1 put

How it works

Here's the example unrolled a bit.

$ for i in 1.txt 2.txt; do 
    grep -f <(awk '{print $1}' $i) file1.txt
  done | \
    awk '{print $1}' | sort | uniq -c

The for loop goes through the 2 files that we're matching against, 1.txt and 2.txt. Each time through the loop we're using the first column from one of these files as a static set of strings to grep looking for these in our target file, file1.txt. This is the line that does that:

$ grep -f <(awk '{print $1}' $i) file1.txt

After running that using each file from the for loop we take all that output and select only the first column of it:


We then use sort and uniq to tally up how many of each type we saw.

share|improve this answer

Here's another way with join:

join -1 1 -2 2 -o 0 2.1 <(sort -k1,1 file1.txt) <(cut -d ' ' -f1 1.txt 2.txt | sort | uniq -c)

note that the output will be sorted:

get 1
move 2
put 1

If you want to preserve the order from file1.txt e.g.

move 2
get 1
put 1

you could run:

join -j2 -o 1.1 0 2.1 <(nl -ba -nrz file1.txt | sort -k2,2) \
<(cut -d ' ' -f1 1.txt 2.txt | sort | uniq -c) | sort -k1 | cut -d ' ' -f2-
share|improve this answer

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.