11

Given two files, I want to write a shell script that reads each line from file1 and checks if it is there in file2. If a line is not found it should output two files are different and exit. The files can contain words numbers or anything. For example :

file1 :

Hi!
1234
5678
1111
hello

file2:

1111
5678
1234
Hi!
hello

In this case two files should be equal. if file2 has "hello!!!" instead of "hello" then the files are different. I'm using bash script. How can I do this. It is not important that I need to do it in a nested loop but that's what I thought is the only way. Thanks for your help.

5 Answers 5

10

In bash:

diff --brief <(sort file1) <(sort file2)
4
  • What if the file is a csv file. would sorting still work ?
    – 0x0
    Jan 18, 2011 at 17:36
  • sort doesn't care about the exact contents unless you tell it to. Jan 18, 2011 at 17:37
  • Is it possible to find which lines differ ?
    – 0x0
    Jan 19, 2011 at 2:07
  • Remove --brief and add format options, e.g. -u. Jan 19, 2011 at 2:07
12

diff sets its exit status to indicate if the files are the same or not. The exit status is accessible in the special variable $?. You can expand on Ignacio's answer this way:

diff --brief <(sort file1) <(sort file2) >/dev/null
comp_value=$?

if [ $comp_value -eq 1 ]
then
    echo "do something because they're different"
else
    echo "do something because they're identical"
fi
1
  • 3
    You can just do if diff ... >/dev/null without the brackets and variable. Jan 18, 2011 at 20:34
3

Whilst diff is a perfectly fine answer, I'd probably use cmp instead which is specifically for doing a byte by byte comparison of two files.

https://linux.die.net/man/1/cmp

Because of this, it has the added bonus of being able to compare binary files.

if cmp -s "file1" "file2"
then
   echo "The files match"
else
   echo "The files are different"
fi

I'm led to believe it's faster than using diff although I've not personally tested that.

3
  • Wouldn't the "files are different" case go first? The if test asks if something is true, ie, a nonzero return code. If the files match, cmp returns 0 (per the manpage), and so that should be the second case.
    – user8162
    Mar 10, 2019 at 19:56
  • @user8162 What you say makes sense, however I've just tested it and that is the right way around. I'm not sure why that is the case to be honest.
    – Richard
    Mar 12, 2019 at 22:33
  • 1
    @user8162 0 means success on the shell and thus true. if <condition>; then will be executed if <condition> is true and for commands that is if they return success. /bin/true always exists with 0 and /bin/false always exists with 1. That's because the exit code is interpreted as an error code and error code 0 means no error == success.
    – Mecki
    Oct 14, 2020 at 12:24
2

Should also work :

comm -3 file1 file2

I think this is enough characters for an answer...

1

Adding this because I think the [[ ]] && || construct is pretty neat:

#!/bin/bash

[[ `diff ${HOME}/file1 ${HOME}/file2` ]] &&  
   (echo "files different") ||
   (echo "files same")

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .