List file NOT present in other directory

Dear community,
I have one LOG directory with some files. What I need to do is list ONLY the files that are not present in other directory.
Using Bash programming!

LOG DIR      |     SYNC DIR
FILE1        |      FILE1
FILE2        |      FILE3
FILE3        |      OTHER FILENAME
FILE4        |
FILE5        |

In this case there are 5 files under LOG directory and 3 files under SYNC directory, so the output list I'm expecting is

FILE2
FILE4
FILE5

Could someone help me? Thanks.

ls dir1 | while read FILE
do
        [ -e "dir2/$FILE" ] || echo "$FILE"
done

Thanks for reply Corona, but it doesn't work! :frowning:

#!/bin/bash
ls /log/*.DAT | while read FILE
do
        [ -e "/log/sync/$FILE" ] || echo "$FILE"
done

This is the LOG dir:

[root@RedHat5 ~]# ls /log
FILE1.DAT
FILE2.DAT
FILE3.DAT
FILE4.DAT
sync
[root@RedHat5 ~]# ls /log/sync
FILE2.DAT

Execution:

[root@RedHat5 ~]# ./test.sh 
/log/FILE1.DAT
/log/FILE2.DAT
/log/FILE3.DAT
/log/FILE4.DAT

FILE2.DAT should not be in the list!

Please read what Corona688 has posted carefully. He didn't suggest globbing.
And if you need to use globbing to perform that operation on a select list of files from the directory, try a slight modification:

printf "%s\n" /log/*.DAT | while read FILE
do
   [[ -e /log/sync/${FILE##*/} ]] || echo "$FILE"
done
1 Like

Sorry Elixir, what do you mean with "globbing"? :confused:
I applied exactly what Corona suggest me.

That's the expansion of asterisk (in this case) by the shell to filenames.
Have you tried what I've suggested in my earlier post?

Ah ok! You had modified the previous post and I don't see the code.
Now it working fine. BTW, I'm used asterisk because under LOG directory there is the SYNC directory, so I've to use * to take only .DAT files! :wink:

Just another question, if the file doesn't exists I need to show it and then copy to SYNC dir (so next time will not be shown). How can I add the copy command to the following line?

[[ -e /log/sync/${FILE##*/} ]] || echo "$FILE" > /tmp/DAT.tmp

Change

[[ -e /log/sync/${FILE##*/} ]] || echo "$FILE" > /tmp/DAT.tmp

to

[[ -e /log/sync/${FILE##*/} ]] || { echo "$FILE"; cp "$FILE" /log/sync/; }

Ooook Thank you!
But I also need to redirect the "filtered" output to a file, that's why I add the redirect ">"

But this doesn't work:

[[ -e /log/sync/${FILE##*/} ]] || { echo "$FILE" > /tmp/DAT.tmp; cp "$FILE" /log/sync/; }

Using process substitution:

grep '\.DAT$' <(comm -23 <(ls log) <(ls log/sync))

A more traditional, more readable approach:

ls log > a
ls log/sync > b
comm -23 a b | grep '\.DAT$'

Regards,
Alister

1 Like