Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flatten directory structure and preserve duplicate files

Tags:

bash

shell

unix

zsh

I have a directory structure that looks like this:

foo
├── 1.txt
├── 2.txt
├── 3.txt
├── 4.txt
└── bar
    ├── 1.txt
    ├── 2.txt
    └── 5.txt

I would like to flatten this directory structure so that all files are in the foo directory and duplicate files are preserved:

foo
├── 1.txt
├── 2.txt
├── 3.txt
├── 4.txt
├── bar-1.txt
├── bar-2.txt
└── bar-5.txt

The file names of the renamed duplicates is insignificant.

Is there a simple Unix one-liner or simple shell script I can use to do this?

like image 580
turtle Avatar asked Dec 03 '22 20:12

turtle


2 Answers

That should work:

target="/tmp/target"; find . -type f | while read line; do outbn="$(basename "$line")"; while true; do if [[ -e "$target/$outbn" ]]; then outbn="z-$outbn"; else break; fi; done; cp "$line" "$target/$outbn"; done

formatted as non-one-liner:

target="/tmp/target"
find . -type f | while read line; do
  outbn="$(basename "$line")"
  while true; do
    if [[ -e "$target/$outbn" ]]; then
      outbn="z-$outbn"
    else
      break
    fi
  done
  cp "$line" "$target/$outbn"
done

be sure to run that from the foo directory in you case and to set the $target variable to the target directory.

Example:

$ find foo
foo
foo/1
foo/2
foo/3
foo/4
foo/bar
foo/bar/1
foo/bar/2
foo/bar/3
foo/bar/4
foo/bar/5
$ cd foo/
$ target="/tmp/target"; find . -type f | while read line; do outbn="$(basename "$line")"; while true; do if [[ -e "$target/$outbn" ]]; then outbn="z-$outbn"; else break; fi; done; cp "$line" "$target/$outbn"; done

and then

$ find $target
/tmp/target
/tmp/target/1
/tmp/target/2
/tmp/target/3
/tmp/target/4
/tmp/target/5
/tmp/target/z-1
/tmp/target/z-2
/tmp/target/z-3
/tmp/target/z-4
like image 66
Johannes Weiss Avatar answered Dec 05 '22 10:12

Johannes Weiss


I assume that I can rename a/b/c.txt to a-b-c.txt (ie: that it such a file doesn't exist in the top directory). Then you can:

 #copy all the files in the top directory
 for i in $(find . -type 'f' ); do
     cp $i $(echo $i | sed -e 's#./##' | tr / - );
 done

#remove subdirectories
find . -type 'd' | egrep -v "^.$" | xargs rm -r 

Of course, you should backup your files before trying this kind of manipulations.

like image 25
gturri Avatar answered Dec 05 '22 11:12

gturri