[comp.lang.perl] script efficiency improvement

bitbug@lonewolf.sun.com (James Buster) (01/03/90)

I have the following script, called make_symlinks:

#!/usr/local/bin/perl

# make_symlinks: each argument is 'oldfile newlink'
while (<>) {
    chop;
    $limit = (@array = split);
    for ($i = 0; $i < $limit; $i++) {
	symlink(@array[$i], @array[++$i]);
    }
}

This script takes argument pairs (from standard input usually) of the
form 'oldfile link', and makes symbolic links to 'oldfile'. Its primary
purpose is the create clone symlink trees of a directory hierarchy.
I would like any pointers on how this script may be optimized.
Here is how this script is invoked (from a much larger /bin/sh script:

THERE=`(cd $1; pwd)`
type_arg="! -type d"

(cd $THERE; find . $type_arg -print | sed -e 's/^..//') | \
	sed -e "s/'/'\\\\''/" -e "s#.*#$THERE/& &#" | $BIN/make_symlinks

I would also appreciate any pointers on how this these sh pipelines
can be optimized.

Thanks for your support (and perl!).

--
---------------------------------------------------------------------
        James Buster		(Domain) bitbug@lonewolf.ebay.sun.com
  Mad Hacker Extraordinaire	(UUCP)   ...!sun.com!lonewolf!bitbug
---------------------------------------------------------------------

hakanson@ogicse.ogc.edu (Marion Hakanson) (01/04/90)

In article <BITBUG.90Jan2225503@lonewolf.sun.com> bitbug@lonewolf.sun.com (James Buster) writes:
>I have the following script, called make_symlinks:
>. . .
>This script takes argument pairs (from standard input usually) of the
>form 'oldfile link', and makes symbolic links to 'oldfile'. Its primary
>purpose is the create clone symlink trees of a directory hierarchy.
>I would like any pointers on how this script may be optimized.
>Here is how this script is invoked (from a much larger /bin/sh script:
>. . .

I have a tool, all in Perl-3.0, which does exactly this task.  It builds
the complete clone directory (we call them "shadow" directories here),
including making the subdirectories themselves, as well as copying any
symlinks in the original (as opposed to making a symlinks to symlinks).

The one "different" thing it does is that all the symlinks are made
relative to a single toplevel link in the shadow directory.  That
toplevel symlink then points at the "real" directory, and can be
changed to retarget the shadow directory without rebuilding the
whole thing.  It's also an advantage over symlinks to full paths,
which can sometimes get too long for "tar" to be able to archive.

I hope folks will find this as useful as we do here.  Do send me any
problems or suggestions for improvements (you can already see the
beginnings of one or two, but I didn't want to break it before
sending it out today).

==============cut here==============
#!/usr/bin/perl
#
# $Id: mkshadowdir.pl,v 1.9 90/01/03 14:46:46 hakanson Exp $
#
# Make a shadow directory of symlinks to a directory tree.
#   Marion Hakanson (hakanson@cse.ogi.edu)
#   Oregon Graduate Institute of Science and Technology

$prog = $0;
$prog =~ s?.*/??;

$FALSE = 0;
$TRUE = 1;

# Defaults
# for -e option when we add it (put these in a file?)
# Note the need for escaping things for the shell,
# and putting blanks between the elements.
$exclude  = " ! \\( -type d -name RCS -prune \\)";
$exclude .= " ! \\( -type f \\( -name Make.log -o -name Make.err \\) \\)";

$preserve = $FALSE;	# for -p option when we add it (preserve dir. modes)
$quiet = $FALSE;	# for -q option when we add it
$shadroot = 'SRC';	# for -r option when we add it
$verbose = $FALSE;	# for -v option when we add it


unless ( $#ARGV == $[ + 1 ) {
  print STDERR "usage: $prog real-path shadow-path\n";
  exit(1);
}

$real = shift;
$shad = shift;

chop($cwd = `pwd`);	# save for below

mkdir($shad,0777) || die "Can't mkdir $shad: $!, aborted";
chdir($shad) || die "Can't chdir $shad: $!, aborted";
chop($shad = `pwd`);

chdir($cwd) || die "Can't chdir back to $cwd: $!, aborted";
chdir($real) || die "Can't chdir $real: $!, aborted";
chop($real_abs = `pwd`);

unless ( $real =~ m?^/.*? ) {
  print STDERR "$prog: $real not absolute path, using $real_abs\n"
    unless ( $quiet );
  $real = $real_abs;
}

open(FIND, "find . $exclude -print |")
  || die "Can't run 'find' command, aborted";

# skip the first "." entry
chop($_ = <FIND>);
m?^\.$? || die "'find' command's first output not '.', aborted";

symlink("$real", "$shad/$shadroot") ||
  die "Can't symlink $shad/$shadroot: $!, aborted";
print "$real\n" unless ( $quiet );

while ( <FIND> ) {
  chop;
  # clean up for appending, plus a sanity check
  s?^\./?? || die "Unexpected output from 'find' command: $_, aborted";

  $tail = $_;
  $tail =~ s?^.*/??;

  die "$shadroot occurs in $real, aborted"
    if ( $tail eq $shadroot );

  if ( -l ) {
    defined ( $sym = readlink("$real/$_") )
      || die "Can't readlink $real/$_: $!, aborted";
    symlink($sym, "$shad/$_")
      || die "Can't symlink $shad/$_: $!, aborted";
    print "$real/$_ -> $sym\n" if ( $verbose );
    next;
  }
  if ( -d _ ) {
    # try to avoid a major loop-type bummer
    die "$shad is a subdirectory of $real, aborted"
      if ( "$real_abs/$_" eq $shad );
    mkdir("$shad/$_", 0777)
      || die "Can't mkdir $shad/$_: $!, aborted";
    symlink("../$shadroot/$tail", "$shad/$_/$shadroot")
      || die "Can't symlink $shad/$_/$shadroot: $!, aborted";
    print "$real/$_\n" unless ( $quiet );
    next;
  }
  symlink("$shadroot/$tail", "$shad/$_")
    || die "Can't symlink $shad/$_: $!, aborted";
  print "$real/$_\n" if ( $verbose );
}

close(FIND);
exit($?);
==============cut here==============

-- 
Marion Hakanson         Domain: hakanson@cse.ogi.edu
                        UUCP  : {hp-pcd,tektronix}!ogicse!hakanson