You could use rsync (it also does local copy)
rsync -r --ignore-existing --include=*/ --include=*.js --exclude=* source/ destination
-r
to recurse into directories,
--ignore-existing
to ignore existing files in destination,
- the
include
and exclude
filters mean: include all directories, include all *.js files, exclude the rest; the first include is needed, otherwise the final exclude will also exclude directories before their content is scanned.
Finally, you can add a -P
if you want to watch progress, a --list-only
if you want to see what it would copy without actually copying, and a -t
if you want to preserve the timestamps.
This is not related, but I learned the rsync command recently, when I moved 15 years of documents from one partition to another. Confident that my files were there, I then wiped the old partition and put some other stuff in there; I realized later that I lost all the timestamps, and discovered the -t flag. Just wanted to share my distress :'(
With Larry Wall's rename
/prename
(*) you can easily "flatten" the structure:
cd mainfolder
rename -n 's:/:-:g' */*/*.jpg
This will move subfolder1/0001.jpg
to subfolder1-0001.jpg
(in mainfolder
) because rename
edits the whole input path and then does the equivalent of mv
using source and edited names.
For instance:
Starting with
.
├── sub1
│ ├── subsub1
│ │ ├── 001.jpg
│ │ ├── 002.jpg
│ │ └── 003.jpg
│ └── subsub2
│ ├── 001.jpg
│ ├── 002.jpg
│ └── 003.jpg
└── sub2
├── subsub1
│ ├── 001.jpg
│ ├── 002.jpg
│ └── 003.jpg
└── subsub2
├── 001.jpg
├── 002.jpg
└── 003.jpg
Execute:
rename s:/:-:g */*/*.jpg
This results in:
.
├── sub1
│ ├── subsub1
│ └── subsub2
├── sub1-subsub1-001.jpg
├── sub1-subsub1-002.jpg
├── sub1-subsub1-003.jpg
├── sub1-subsub2-001.jpg
├── sub1-subsub2-002.jpg
├── sub1-subsub2-003.jpg
├── sub2
│ ├── subsub1
│ └── subsub2
├── sub2-subsub1-001.jpg
├── sub2-subsub1-002.jpg
├── sub2-subsub1-003.jpg
├── sub2-subsub2-001.jpg
├── sub2-subsub2-002.jpg
└── sub2-subsub2-003.jpg
And you can get rid of the subdirectories using
rm -r sub*/
(final slash is important! it restricts the match to directories)
So finally:
.
├── sub1-subsub1-001.jpg
├── sub1-subsub1-002.jpg
├── sub1-subsub1-003.jpg
├── sub1-subsub2-001.jpg
├── sub1-subsub2-002.jpg
├── sub1-subsub2-003.jpg
├── sub2-subsub1-001.jpg
├── sub2-subsub1-002.jpg
├── sub2-subsub1-003.jpg
├── sub2-subsub2-001.jpg
├── sub2-subsub2-002.jpg
└── sub2-subsub2-003.jpg
If you have a huge collection of files, you cannot process in one call because the file expansion of **/*.jpg will generate a list which is too long (/bin/sh: 1: rename: Argument list too long`). So you have to split the work, for instance by calling rename once by directory:
shopt -s globstar
for d in **/; do rename s:/:-:g "$d"*.jpg; done
(the /
in '**/' is important, it restricts the expansion to directories)
If you still get the Argument list too long
message then you have a directory with very many files :) You just have to find a way to split the work, for instance:
for f in path/to/hugedir/A*;jpg; do rename s:/:-:g "$d"*.jpg; done
for f in path/to/hugedir/B*;jpg; do rename s:/:-:g "$d"*.jpg; done
[... etc ...]
If this is still too big and or you want to be blunt, you can also call rename once for each file:
shopt -s globstar
for f in **/*.jpg; do rename s:/:-:g "$f"; done
(this will work because here the expansion of "**/*.jpg" is just a variable in your shell, and not the list of arguments to a command).
PS: bash
assumed here, if you are putting this in a script, make sure the "shebang" is /bin/bash
, on some systems sh
is a lightweight shell (dash
) that doesn't support globstar
.
(*) name varies depending on distro, rename
for Debian/Ubuntu and derivatives, and IIRC prename
on RedHat and derivatives.
Best Answer
Another way of doing this would be to use
inotify
:Install the
inotify-tools
packageWrite a little script that uses
inotifywatch
to check your folder for changes and moves any new files to the target directory:Save that script in your
$PATH
and make it executable, e.g.:Have it run every time your machine reboots, create a crontab (
crontab -e
, as described in @MariusMatutiae's answer) and add this line to it:Now, every time you reboot, the directory will automatically be watched and new files copied from source to target.