- I have a two directories,
input
andoutput
. input
is a flat directory containing, among others, some.jpg
files.output
has nested subdirectories and contains.jpg
files with same names as these ininput
.There can be some names in
input
missing inoutput
.Names in
output
can be duplicated in different subdirectories.
An example structure:
$ tree input/
input/
├── a
├── b
├── c
├── d
├── e.jpg
├── f.jpg
├── h
├── i
├── j.jpg
└── z.jpg
0 directories, 10 files
$ tree output
output
├── 1
│ └── 2
│ └── 3
│ └── e.jpg
├── A
│ └── B
│ └── f.jpg
├── O
│ └── j.jpg
└── X
└── Y
└── Z
└── j.jpg
9 directories, 4 files
The task is to overwrite all .jpg
files in output
directory with these from input
based on their names.
Python version:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import collections
import os
import shutil
import sys
def get_paths(root):
paths = collections.defaultdict(list)
for path, subdirs, files in os.walk(root):
for f in files:
if os.path.splitext(f)[1] == '.jpg':
paths[os.path.basename(f)].append(os.path.join(path, f))
return paths
def main():
if len(sys.argv) != 3:
msg = 'python {} path/to/input/dir path/to/output/dir'
print(msg.format(sys.argv[0]))
sys.exit(1)
input_dir, output_dir = sys.argv[1], sys.argv[2]
input_paths, output_paths = get_paths(input_dir), get_paths(output_dir)
for filename, input_path in input_paths.items():
for output_path in output_paths.get(filename, []):
shutil.copy(input_path[0], output_path)
if __name__ == '__main__':
main()
Usage:
$ cat input/e.jpg input/f.jpg input/j.jpg
e
f
j
$ cat output/1/2/3/e.jpg output/A/B/f.jpg output/X/Y/Z/j.jpg output/O/j.jpg
X
X
X
X
$ python test.py input/ output/
$ cat output/1/2/3/e.jpg output/A/B/f.jpg output/X/Y/Z/j.jpg output/O/j.jpg
e
f
j
j
C++14 version:
#include <map>
#include <list>
#include <iostream>
#include <boost/filesystem.hpp>
auto get_paths(boost::filesystem::path root) {
std::map<
const boost::filesystem::path,
std::list<boost::filesystem::path>
> paths;
boost::filesystem::recursive_directory_iterator it(root);
const boost::filesystem::path jpg(".jpg");
for(; it != boost::filesystem::recursive_directory_iterator(); ++it) {
if(boost::filesystem::is_regular_file(*it) && boost::filesystem::extension(*it) == jpg){
paths[it->path().filename()].push_back(it->path());
}
}
return paths;
}
int main(int argc, char** argv) {
if(argc != 3) {
std::cerr << argv[0] << " path/to/input/dir path/to/output/dir" << std::endl;
return 1;
}
boost::filesystem::path input_dir(argv[1]);
boost::filesystem::path output_dir(argv[2]);
auto input_paths = get_paths(input_dir);
auto output_paths = get_paths(output_dir);
for(auto const& input_pair: input_paths) {
const auto output_pair = output_paths.find(input_pair.first);
if(output_pair != output_paths.end()) {
for(auto const& output_path: output_pair->second) {
boost::filesystem::copy_file(
input_pair.second.front(),
output_path,
boost::filesystem::copy_option::overwrite_if_exists
);
}
}
}
}
Usage:
$ cat input/e.jpg input/f.jpg input/j.jpg
e
f
j
$ g++ test.cpp -o test -lboost_system -lboost_filesystem -std=c++14
$ cat output/1/2/3/e.jpg output/A/B/f.jpg output/X/Y/Z/j.jpg output/O/j.jpg
X
X
X
X
$ ./test input/ output/
$ cat output/1/2/3/e.jpg output/A/B/f.jpg output/X/Y/Z/j.jpg output/O/j.jpg
e
f
j
j