3

I am writing a bash script to loop through 2 identical directory trees in order to do run diffs on matching files. I just need to know what is correct syntax to setup 2 loops that will run in parallel. I'd also like to iterated through directories recursively, so if there's an additional step to accomplish that, can you mention it?

#!/bin/bash
FILES1=/path/to/one
FILES2=/path/to/two
for f1 in $FILES1; f2 in $FILES2
do
  echo "Processing $f1 $f2 file..."
done
7
  • 2
    Do you actually want to process the first file from $FILES1 with the first from $FILES2, then second with second, and so on, or each file from $FILES1 with each from $FILES2 (i.e. a cross product)? Commented Nov 7, 2011 at 16:21
  • 4
    What's wrong with diff -Naur /path/to/one /path/to/two? Commented Nov 7, 2011 at 16:21
  • Paulo, I want the former: first with first, second with second, etc. Commented Nov 7, 2011 at 16:49
  • @ted and you are sure they are always ordered the same way? Commented Nov 7, 2011 at 17:05
  • jamessan, you solved my problem the best possible way, a one-liner. Why didn't you post it as an answer? I'll leave the question as it is b/c the loop question may be useful for others. Commented Nov 7, 2011 at 20:01

3 Answers 3

3

diff already has the builtin functionality to run recursively against directories. You can run diff -Naur /path/to/one /path/to/two.

  • -N will show the diff for new files, instead of just saying it exists in the second path
  • -a treats all files as text, so you may or may not need this.
  • -u uses the common unified diff format
  • -r is the important, in this case, recursive flag
Sign up to request clarification or add additional context in comments.

Comments

3

There is no guarantee that the files will be in the same order in the two directories.

Do it like this:

FILES1=/path/to/one
FILES2=/path/to/two
for f1 in $FILES1/*
do
  f2=$FILES2/`basename f1`
  # ...
done

And if you need to do it recursively:

cd $FILES1
for f1 in `find`; do
  f2=$FILES2/$f1
  # ...
done

Comments

0

The closest you can get is to nest the for loops, i.e.

   for f in $FILES1 ; do
      for f2 in $FILES2 ; do
         if [ ${f##*/} = ${f2##*/} ]; then
             diff $f $f2
             break
         fi
      done
  done

to iterate thru recursive dirs, you could rely on find to return a list of files for processing

 PATH1=/path/to/one
 PATH2=/path/to/two

 for f in $(find $PATH1 -print ) ; do
    for f2 in $(find $PATH2 -print ) ; do
       if [ ${f##*/} = ${f2##*/} ]; then
           diff $f $f2
           break
       fi
    done
done

Sorry I don't have a way to test this right now, the ${f##*/} may not be exactly right. The intention is to create just the basename of a file (I guess you could use that too, $(basename $f ) at the expense of an 2 processes for each.

Both of these are very expensive processes, checking lots of non-matching filename pairs. The break inside loop2 helps a little.

An alternate solution is to rely on one path to create the driver list and then use the supplied names to generate alternate relative paths, i.e.

for f in $FILES1 ; do
   f2=../two/$f{##*/}
   if [ -f ${f2} ] ; the
       diff $f $f2
   else
       printf "no alternate file found in ../two for f=${f}"
   fi
done

If need be, you can duplicate that loop and reverse the location of f2 and f to check the 'other-side' of your system.

I hope this helps.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.