Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

The Shell Corner: cmptree


February 2001

The Shell Corner: cmptree

Ed Schaefer

Convert Revisited

Last month, Gerard van Wageningen submitted convert, a Korn script to display numbers in binary, decimal, hexadecimal, and base 36. After my deadline, Gerard submitted a change, adding base 64. If anyone desires this change, please email me and I'll send it to you.

Directory Comparison with cmptree

This month, Ives Aerts submits cmptree, a bash script that compares the contents of two directories and reports if like-named files are different. It also reports a missing file or directory as not existing. Simply execute:

cmptree directory1 directory2</Pre>


Comparing directories is not new. SCO Unix has provided shell script <code>dircmp</code> since before System V, and Solaris also provides a version of <code>dircmp</code>. For Unix variants that dont have a directory compare, such as RedHat Linux 6.1, <code>cmptree</code> is a worthy addition.</P>


While <code>dircmp</code> executes a <code>find</code> on each directory comparing contents, <code>cmptree</code> elegantly compares the two directories recursively. The simplicity of <code>cmptree</code> eliminates some of the functionality of <code>dircmp</code>.</P>
<B>
<h3><code>cmptree</code> Limitations</h3>
</B>


<code>cmptree</code> reports only if files are different -- not what the differences are.</P>


<code>cmptree</code> only compares normal files. Special files, such as block, character, named pipe, semaphore, and shared memory are marked as "unknown."</P>


Also, <code>cmptree</code> uses <code>test -e</code> to check whether an object exists; thus, no read permissions causes an "object does not exist" error.</P>


Soft links report only if they are different. For example, two directories exist: <code>/tmp/dir1</code> and <code>/tmp/dir2</code>. In the present working directory, create two soft links:</P>
<Pre>ln -s /tmp/dir1 linkdir1
ln -s /tmp/dir2 linkdir2
Executing the following:

cmptree /tmp/dir1 /tmp/dir2
performs a valid search, but executing:

cmptree linkdir1 linkdir2
displays a "different link targets" message.

Bash Versus Korn Shell

cmptree is a bash shell script, but removing the function keyword in each function allows Korn shell execution.

In Ives' original submission, cmptree's comparefile function performed compares with:

cmp $1 $2

While the command above works fine in the bash shell, in the Korn, the file name does not list. I changed the cmp command to return an exit code, sampling the value as such:

  cmp -s $1 $2
  if [ $? -gt 0 ]; then
    echo "$1 different from $2"
  fi
The code snippet above works in both the bash and Korn shells.

#!/bin/bash
#
# cmptree: compare directory trees recursively and report the differences.
# Author: Ives Aerts

function gettype () {
  if [ -L $1 ]; then
    echo "softlink"
  elif [ -f $1 ]; then
    echo "file"
  elif [ -d $1 ]; then
    echo "directory"
  else
    echo "unknown"
  fi
}

function exists () {
  if [ -e $1 -o -L $1 ]; then
    return 0;
  else
    echo "$1 does not exist."
    return 1;
  fi
}

function comparefile () {
  cmp -s $1 $2
  if [ $? -gt 0 ]; then
    echo "$1 different from $2"
#  else
#    echo "$1 same as $2"
  fi
  return
}

function comparedirectory () {
  local result=0
  for i in `(ls -A $1 && ls -A $2) | sort | uniq`; do
    compare $1/$i $2/$i || result=1
  done
  return $result
}

function comparesoftlink () {
  local dest1=`ls -l $1 | awk '{ print $11 }'`
  local dest2=`ls -l $2 | awk '{ print $11 }'`

  if [ $dest1 = $dest2 ]; then
    return 0
  else
    echo "different link targets $1 -> $dest1, $2 -> $dest2"
    return 1
  fi
}

# compare a file, directory, or softlink
function compare () {
  (exists $1 && exists $2) || return 1;

  local type1=$(gettype $1)
  local type2=$(gettype $2)

  if [ $type1 = $type2 ]; then
    case $type1 in
      file)
        comparefile $1 $2
        ;;
      directory)
        comparedirectory $1 $2
        ;;
      softlink)
        comparesoftlink $1 $2
        ;;
      *)
        echo "$1 of unknown type"
        false
        ;;
    esac
  else
    echo "type mismatch: $type1 ($1) and $type2 ($2)."
    false
  fi

  return
}

if [ 2 -ne $# ]; then
cat << EOU
Usage: $0 dir1 dir2
Compare directory trees:
  files are binary compared (cmp)
  directories are checked for identical content
  soft links are checked for identical targets
EOU
  exit 10
fi

compare $1 $2
exit $?

Check out past winners of shell corner!!!

By day, Ed Schaefer is a mild-mannered senior programmer-analyst for Intel's Factory Integrated Information Systems (FIIS). The standard employer-employee disclaimer is in effect: In this forum, Ed doesn't speak for Intel and his views on Unix and all other topics are his own.


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.