5

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?

2
  • Your command works flawlessly, I justed tested it. Which version of find are you running?
    – kos
    Jul 2, 2015 at 22:05
  • Versions added in edit Jul 5, 2015 at 19:01

4 Answers 4

1

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.

1

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.

3
  • Will it also go in subfolders of subfolders (as 02-2015 also has subfolders) ? Jul 5, 2015 at 19:33
  • @PericaZivkovic - Do you want the index.html files out of those? Because we can make it do so - here I only glob specifically the files, but if I were just to do the directories, sure. And if so - how should they be named?
    – mikeserv
    Jul 5, 2015 at 19:34
  • I just want to pick up all index.html from all subfolders no matter how deep and dump them into output folder as a separate files - no matter what is rename pattern. If they end up like index1.html, index2.html etc. all fine as long as they are all there in one output folder Jul 5, 2015 at 19:40
0

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
$
4
  • Quoting {} makes no difference here. It doesn't affect what find command is executed. Jul 2, 2015 at 22:26
  • What is the function of {}?? Jul 2, 2015 at 22:29
  • The {} gets replaced with the filename. If unsure just try running with a echo inserted, e.g. find foo* -name index.html -exec echo cp --backup=t {} files_output \;
    – steve
    Jul 3, 2015 at 9:03
  • Quotes or no quotes - I get just one file copied... Jul 5, 2015 at 19:01
-1

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.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .