Apple
Apple

Reputation: 441

How do I compare file names in two directories in shell script?

Right now, this is what my code looks like:

#!/bin/bash

Dir1=$1
Dir2=$2

for file1 in $Dir1/*; do
    for file2 in $Dir2/*; do
        if [[ $file1 == $file2 ]]; then
            echo "$file1 is contained in both directories"
        fi
    done
done

I am trying to compare the file names of the two directories entered and say that the file is in both directories if the filename matches. When I try to run it though, nothing is echo-ed even though I have the same file in both directories.

Upvotes: 29

Views: 48256

Answers (5)

Super-intelligent Shade
Super-intelligent Shade

Reputation: 6449

Files that are in both Dir1 and Dir2:

find "$Dir1/" "$Dir2/" -printf '%P\n' | sort | uniq -d

Files that are in Dir1 but not in Dir2:

find "$Dir1/" "$Dir2/" "$Dir2/" -printf '%P\n' | sort | uniq -u

Files that are in Dir2 but not in Dir1:

find "$Dir1/" "$Dir1/" "$Dir2/" -printf '%P\n' | sort | uniq -u

Upvotes: 62

ghoti
ghoti

Reputation: 46846

Your comparison fails because Dir1/foo is not the same as Dir2/foo. Instead, if you change to one directory, your * will expand to just the filenames:

#!/bin/bash

Dir1="$1"
Dir2="$2"

if ! cd "$Dir1"; then
  echo "ERROR: Couldn't find directory $Dir1" >&2
  exit 1
fi

if [[ ! "$Dir2" =~ ^/ ]]; then
  echo "ERROR: Second directory must be a full path." >&2
  exit 1
fi

for file1 in *; do
    if [ -f "$Dir2/$file1" ]; then
        echo "$file1 is contained in both directories"
    fi
done

Note that this only matches file names. If you want to make sure it's really the same file, you should use cmp to compare them.

Upvotes: 0

user3439894
user3439894

Reputation: 7555

If you want to know what's common to two directories then this is another way with much less coding.

#!/bin/bash

comm -12 <(ls -F $1) <(ls -F $2)

See man comm for more information about the comm utility.

Upvotes: 6

Mikolaj
Mikolaj

Reputation: 708

I just tested this and it worked:

DIR1=$(ls dir1)
DIR2=$(ls dir2)

for i in $DIR1; do
    for j in $DIR2; do
        if [[ $i == $j ]]; then
            echo "$i == $j"
        fi
    done
done

Upvotes: 1

Barmar
Barmar

Reputation: 780974

It doesn't work because you're comparing variables that contain the directory prefix. Just remove the prefix before comparing:

name1=${file1##*/}
name2=${file2##*/}
if [[ $name1 == $name2 ]]; then
    echo "$name1 exists in both directories"
fi

Also, nested loops seems like an inefficient way to do this. You just need to get the filenames from one directory, and use a simple file existence check for the other directory.

for file in $Dir1/*; do
    name=${file##*/}
    if [[ -f $Dir2/$name ]]; then
        echo "$name exists in both directories"
    fi
done

Upvotes: 3

Related Questions