Recursive copy files with rename

If I have input folder files_input that has subfilders like 01-2015, 02-2015, 03-2015 etc and all these subfolders have other subfolders. Each subfolder has only one file called index.html.

How can I copy all these index.html files into one folder called files_output so that they end up like separate files in the same folder. They should ofcourse be renamed and I have tried to use –backup for that…

I have tried

find files_input -name *.html -exec cp --backup=t '{}' files_output ;

to get them numbered but that copies only one file and nothing else.

I don’t know does that change anything but I’m using zsh, here are the versions:

   $ zsh --version | head -1
   zsh 5.0.2 (x86_64-pc-linux-gnu)
   $ bash --version | head -1
   GNU bash, version 4.3.11(1)-release (x86_64-pc-linux-gnu)
   $ cp --version | head -1
   cp (GNU coreutils) 8.21
   $ find --version | head -1
   find (GNU findutils) 4.4.2

Ideas?

Edit:

Trying to run e.g. following

cp --backup=t files_input/01-2015/index.html files_output

five times in a row still gives me one index.html in files_output folder! Is cp broken ? Why don’t I have five different files?

Asked By: Perica Zivkovic

||

Try removing the quotes around {}, as seemed to work for me that way.

$ find foo* files_output -ls
 27002    0 drwxrwxr-x   2 steve    steve          60 Jul  2 15:04 foo1
 25373    0 -rw-rw-r--   1 steve    steve           0 Jul  2 15:04 foo1/index.html
 27003    0 drwxrwxr-x   2 steve    steve          60 Jul  2 15:04 foo2
 25374    0 -rw-rw-r--   1 steve    steve           0 Jul  2 15:04 foo2/index.html
 48941    0 drwxrwxr-x   2 steve    steve          40 Jul  2 15:06 files_output
$ find foo* -name index.html -exec cp --backup=t {} files_output ;
$ find files_output -ls
 48941    0 drwxrwxr-x   2 steve    steve          80 Jul  2 15:08 files_output
 51354    0 -rw-rw-r--   1 steve    steve           0 Jul  2 15:08 files_output/index.html
 49595    0 -rw-rw-r--   1 steve    steve           0 Jul  2 15:08 files_output/index.html.~1~
$

In my case, versions of the utilities as below.

$ bash --version | head -1
GNU bash, version 4.2.53(1)-release (x86_64-redhat-linux-gnu)
$ cp --version | head -1
cp (GNU coreutils) 8.21
$ find --version | head -1
find (GNU findutils) 4.5.11
$
Answered By: steve

You can do it like this:

cd -P files_input/.. &&
mkdir files_output   &&
pax -rws'|.*/(.*)/(.*)|1.2|' 
     files_input/??-2015/index.html files_output

Which will glob all index.html files in folders in child directories of ./files_input named with two characters, then a dash, then the string 2015 and copy all of those files into the newly created files_output folder with names like ??-2015.index.html.

Answered By: mikeserv

This worked for me:

find files_input -name "20171123*" -exec cp --backup=t --target-directory=files_output {} +

Copies all files matching the -name pattern in dirs and subdirs of “files_input” to the “file_output” dir, and appends ~1~, ~2~, etc. for duplicate files.

Answered By: Nukolas

As you’re a zsh user:

$ tree files_input
files_input
|-- 01_2015
|   |-- subfolder-1
|   |   `-- index.html
|   |-- subfolder-2
|   |   `-- index.html
|   |-- subfolder-3
|   |   `-- index.html
|   |-- subfolder-4
|   |   `-- index.html
|   `-- subfolder-5
|       `-- index.html
|-- 02_2015
|   |-- subfolder-1
|   |   `-- index.html
|   |-- subfolder-2
|   |   `-- index.html
|   |-- subfolder-3
|   |   `-- index.html
|   |-- subfolder-4
|   |   `-- index.html
|   `-- subfolder-5
|       `-- index.html
(etc.)
$ mkdir -p files_output
$ autoload -U zmv
$ zmv -C './files_input/(*)/(*)/index.html' './files_output/$1-$2-index.html'
$ tree files_output
files_output
|-- 01_2015-subfolder-1-index.html
|-- 01_2015-subfolder-2-index.html
|-- 01_2015-subfolder-3-index.html
|-- 01_2015-subfolder-4-index.html
|-- 01_2015-subfolder-5-index.html
|-- 02_2015-subfolder-1-index.html
|-- 02_2015-subfolder-2-index.html
(etc.)

What’s happening here is that we make the command zmv available with autoload -U zmv. This command is used for renaming, copying or linking files matching a zsh extended globbing pattern.

We use zmv with its -C option, telling it to copy the files (as opposed to moving them, which is the default). We then specify a pattern that matches the files we’d want to copy, ./files_input/(*)/(*)/index.html. The two (*) matches the two levels of subdirectory names, and we put them within parentheses for use in the new name of each file. The new name of each file is the second argument, ./files_output/$1-$2-index.html, where $1 and $2 will be the strings captured by the parentheses in the pattern, i.e. back-references to the subdirectory names. Both arguments should be single quoted.

Answered By: Kusalananda
Categories: Answers Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.