I want to retrieve all the matching paths following this pattern in a vector<string>
:
"/some/path/img*.png"
How can I simply do that ?
I want to retrieve all the matching paths following this pattern in a vector<string>
:
"/some/path/img*.png"
How can I simply do that ?
I have that in my gist. I created a stl wrapper around glob so that it returns vector of string and take care of freeing glob result. Not exactly very efficient but this code is a little more readable and some would say easier to use.
#include <glob.h> // glob(), globfree()
#include <string.h> // memset()
#include <vector>
#include <stdexcept>
#include <string>
#include <sstream>
std::vector<std::string> glob(const std::string& pattern) {
using namespace std;
// glob struct resides on the stack
glob_t glob_result;
memset(&glob_result, 0, sizeof(glob_result));
// do the glob operation
int return_value = glob(pattern.c_str(), GLOB_TILDE, NULL, &glob_result);
if(return_value != 0) {
globfree(&glob_result);
stringstream ss;
ss << "glob() failed with return_value " << return_value << endl;
throw std::runtime_error(ss.str());
}
// collect all the filenames into a std::list<std::string>
vector<string> filenames;
for(size_t i = 0; i < glob_result.gl_pathc; ++i) {
filenames.push_back(string(glob_result.gl_pathv[i]));
}
// cleanup
globfree(&glob_result);
// done
return filenames;
}
I wrote a simple glob library for Windows & Linux (probably works on other *nixes as well) a while ago when I was bored, feel free to use it as you like.
Example usage:
#include <iostream>
#include "glob.h"
int main(int argc, char **argv) {
glob::Glob glob(argv[1]);
while (glob) {
std::cout << glob.GetFileName() << std::endl;
glob.Next();
}
}
You can use the glob()
POSIX library function.
For newer code to the C++17 standard, std::filesystem
exists and it can achieve this with std::filesystem::directory_iterator
and the recursive version. You will have to manually implement the pattern matching. For instance, the C++11 regex library. This will be portable to any platform with C++17 support.
std::filesystem::path folder("/some/path/");
if(!std::filesystem::is_directory(folder))
{
throw std::runtime_error(folder.string() + " is not a folder");
}
std::vector<std::string> file_list;
for (const auto& entry : std::filesystem::directory_iterator(folder))
{
const auto full_name = entry.path().string();
if (entry.is_regular_file())
{
const auto base_name = entry.path().filename().string();
/* Match the file, probably std::regex_match.. */
if(match)
file_list.push_back(full_name);
}
}
return file_list;
A similar API is also implemented in boost for non-C++17 cases. std::string::compare()
might be sufficient to find a match, including multiple calls, with len
and pos
arguments to match sub-strings only.
I've tried the solutions above on Centos6, and I found out that I needed to change:
int ret = glob(pat.c_str(), 0, globerr, &glob_result);
(where "globerr" is an error handling function)
Without the explicit 0, I got "GLOB_NOSPACE" error.