Reputation: 43
I have a file server backup on an external hard drive a few months old for a file server that went down since then. Most of the data was recovered onto a temporary file server thats been in use since then but there are some inconsistencies.
I am going to mount the external and rsync it with the current data to it but first I need to establish files that have gotten updated on the newer copy.
I can do diff -r -q /old/ /new/ to obtain this, I am trying to get better at scripting so I am trying to write something that will rename the old file to filename.old whenever diff returns a difference.
Upvotes: 3
Views: 10534
Reputation: 20714
So after checking, I wasn't able to find an option in diff
to only output the filename differences so we'll just work with what diff outputs.
If diff
finds files that differ, the output is something like this:
Files old/file and new/file differ
Since all your bash script would be doing is renaming the changed file from the old directory, we want to extract old/file
from this output. Let's start by only displaying lines like Files...differ
(as other lines may be produced):
diff -rq old/ new/ | grep "^Files.*differ$"
Now you'll only get lines like the one shown before. Next step is getting the filename. You can do this with awk
by adding something like awk '{print $2}'
as another pipe but if the filename itself contains spaces, awk will break up that as two separate strings. We'll use sed instead:
diff -rq old/ new/ | grep "^Files.*differ$" | sed 's/^Files \(.*\) and .* differ$/\1/'
Now this will produce a list of files that have changed in the old directory. Using a simple for loop, you can now rename each of the files:
for old_file in `diff -rq old/ new/ | grep "^Files.*differ$" | sed 's/^Files \(.*\) and .* differ$/\1/'`
do
mv $old_file $old_file.old
done
And that's it!
edit: actually, that's not all. This loop still fails on files with spaces so let's muck with it a bit. for
will try to produce a list separated by a space by default. Let's change this to use newlines instead:
OLD_IFS=$IFS
# The extra space after is crucial
IFS=\
for old_file in `diff -rq old/ new/ | grep "^Files.*differ$" | sed 's/^Files \(.*\) and .* differ$/\1/'`
do
mv $old_file $old_file.old
done
IFS=$OLD_IFS
This temporarily replaces bash's default separator ($IFS
) to a newline and puts it back after it's done with the loop so you don't split by space.
Upvotes: 5
Reputation: 753675
There used to be a program dircmp
lurking around systems. If you have it, use it.
If you don't have and can't find it, then I have a version of it with minor extensions that you can use (see my profile for contact information).
Example output:
Files in ifxchkpath-4.12 only and in ifxchkpath-5.15 only
./Makefile ./absname.1
./program.mk ./absname.c
./chk.servers.sh
./chunklist.sh
./clnpath.c
./clnpath.h
./dirname.c
./enable.uids.sh
./errhelp.c
[...]
./lpt.pl
./makefile
./nvstrcpy.c
./realpath.c
./realpathtest.sh
./stderr.c
./stderr.h
./symlinks.tgz
./testids.mk
./test.linkpath.pl
./test.lpt.sh
./test.onsecurity.sh
./tokenise.c
Comparison of files in ifxchkpath-4.12 and ifxchkpath-5.15
directory .
different ./chk.ifxchkpath.sh
different ./ifxchkpath.c
same ./test.ifxchkpath.pl
Upvotes: 0