Duplicating a directory tree

I want a bash script that will duplicate the directory structure and the files (only the names of files but not their contents). So for example if called like

test.sh previousdir newdir

it should create the overall directory structure and also the files (empty ones) of previousdir into newdir. So what we tried was to write a recursive functions that will call itslef whenver it comes across a directory, and otherwise touch the file with the same name (see below for the script). The problem is the test
if [ -d $foo ]; always evaluates to false. and we suspect that this is due to some hidden character or something like that when we get $foo from the ls command (in the for loop). Could you please look into this and tell us what we are doing wrong? If I get a working answer within 24 hours I will be happy to add extra 50 points.



#test.sh
echo "source= $1"
echo "destination=$2"
mkdir $2
for foo in $(ls $1)
do
echo $foo
if [ -d $foo ]; then
   echo "directory!"
   echo  $1\/${foo}
   test.sh $1\/${foo} $2\/${foo}
else
   echo "file!"
   echo  $1\/${foo}
   touch $2\/${foo}
fi
done
LVL 4
oumerAsked:
Who is Participating?

Improve company productivity with a Business Account.Sign Up

x
 
ecwConnect With a Mentor Commented:
It doesn't work because "ls dir" list the file in dir and you're not prepending dir to foo.  ie.
  if [ -d "$1/$dir" ] ; then
    ...
  fi
0
 
ahoffmannCommented:
find $1 -type d -exec mkdir -p ./\{} \;
find $1 -type f -exec touch ./\{} \;
#
# not exactly what you asked for, but simple to understand ;-)
0
 
tsinoaCommented:
Hi!

Below is a perl script that does the job! It's pretty explicit so I hope you'll have no trouble to follow ;)

Try it,

Enjoy, Robert

# START SCRIPT
#! /usr/bin/env perl
# copies complete SourceDir directory structure to DestinationDir but leaves out file content
# calls subroutine branchcp recursively to inspect subbranches

die "Usage: perl dirtreecp.pl SourceDir Destination\n" unless (scalar(@ARGV)==2);
($src,$des)=@ARGV;
die "Source directory \"$src\" does not exist" unless (-d $src);
die "Destination directory \"$des\"does not exist" unless (-d $des);
&branchcp($src,$des);

# recursive subrutine that expands/duplicates all dir branches
sub branchcp {
  my ($src,$des,@list,$item,$src2,$des2); # local variables

  ($src,$des)=@_;
  open LIST, "ls -1 $src |" or die "ls command not successful"; # list src dir content into @list
  @list= <LIST>;
  close LIST;
  foreach $item (@list) { # process all item in a dir list
    chomp($item);
    $src2=$src."\/".$item; # append item to previos src path to create new path
    $des2=$des."\/".$item; # "      "    "  "       des "    "  "      "   "
    if (-d $src2) { # is it directory
      printf "%s -> %s\n", $src2, $des2;
      !system("mkdir $des2") or die "Couldn't create destination directory $des2! $?\n"; # duplicate dir in dest. path
      &branchcp($src2,$des2); # inspect dir's subtree
    } elsif (-f $src2) { # is it file
      printf "%s -> %s\n", $src2, $des2;
      !system("touch $des2") or die "Couldn't create destination file $des! $?\n "; # touch it, create an empty file with the same name in dest. path
    } else { # found something else
      print "$src2 - not a file or directory ... skipped";
    }
  }
}

# END SCRIPT
0
Free Tool: Subnet Calculator

The subnet calculator helps you design networks by taking an IP address and network mask and returning information such as network, broadcast address, and host range.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

 
oumerAuthor Commented:
could you tell me what is wrong with my script?
0
 
ahoffmannCommented:
your script does not work if there are directory and/or filenames which contain white spaces.
Also try to add as very first line in your script:

#! /bin/sh
0
 
oumerAuthor Commented:
There wasn't any directory with white spaces. The problem is the test if [ -d $foo ] always fails, so does the [ -f $foo ] (please refer to my code above). That is why I think when I got the ls and get the name of every file, maybe I am getting also some unprintable character.
0
 
ahoffmannCommented:
did you add the very first line as suggested?
Also replace  ls  by  \ls   or   /bin/ls
0
 
yuzhCommented:
Hi
  In your script
       "for foo in $(ls $1)"
  You should change it to:

      for foo in `ls -R $1` ; do
          ........
      done

Here 's a sample script for you to do this job:

#!/bin/sh
# first arg = src, 2nd arg=des
cd $1
find . -type d -print |sort >/tmp/dirlist.$$
find . -type f -print | sort >/tmp/filelist.$$
cd $2
for dir in `cat /tmp/dirlist.$$`; do
   mkdir -p $dir
done

for f in `cat /tmp/filelist.$$` ; do
   touch $f
done
echo "Job done !!!!!\n"

0
 
samriCommented:
listening.

(I hope this trick still works with EE revamp).

:)
0
 
mliberiCommented:
test -d $foo

fails because the test is done in the current directory instead of in the source directory.
The same happens, obviously for files.

change it to 'test -d $1/$foo'
0
 
oumerAuthor Commented:
ecw has said exactly the same thing and it works. Sorry but I am gonna give the points to ecw. Thank you very much, all of you, for such interesting suggestions.
0
 
oumerAuthor Commented:
It is nice to get an answer so small but 100% to the point! Thanks
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.