• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 238
  • Last Modified:

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
0
oumer
Asked:
oumer
1 Solution
 
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
 
oumerAuthor Commented:
could you tell me what is wrong with my script?
0
VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

 
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
 
ecwCommented:
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
 
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

Featured Post

Free Tool: Site Down Detector

Helpful to verify reports of your own downtime, or to double check a downed website you are trying to access.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Tackle projects and never again get stuck behind a technical roadblock.
Join Now