Как отфильтровать результат, чтобы получить только имена файлов в результате вывода linux на c 98

#c #linux #string #vector #absolute-path

#c #linux #строка #вектор #абсолютный путь

Вопрос:

Текущий фрагмент кода будет соответствовать шаблону и перечислит все соответствующие файлы шаблонов, присутствующие в каталоге, указанном где в приведенном ниже примере файла является шаблоном, который должен быть сопоставлен *, здесь вывод будет указан с абсолютным путем, как показано ниже.

     /home/downloads/File1
    /home/downloads/File2
    /home/downloads/File3
    /home/downloads/File4
 

при этом я ищу только имя файла, которое должно быть указано, например, как указано ниже:

 File1
File2
File3
File4
 

код c ниже:

     #include <glob.h>
    #include <cerrno>
    #include <cstring>
    #include <iostream>
    #include <stdexcept>
    #include <string>
    #include <vector>
    using namespace std;
    vector<string> glob(const stringamp; pattern) {
        glob_t glob_result = {0}; // zero initialize
        // do the glob operation
        int return_value = ::glob(pattern.c_str(), GLOB_TILDE, NULL, amp;glob_result);
        if(return_value != 0) throw runtime_error(strerror(errno));
        // collect all the filenames into a std::vector<std::string>
        // using the vector constructor that takes two iterators
        vector<string> filenames(
            glob_result.gl_pathv, glob_result.gl_pathv   glob_result.gl_pathc);
        // cleanup
        globfree(amp;glob_result);
        
        // done
        return filenames;
    }
    int main() {
        try { // catch exceptions
               vector<string> res = glob("/home/downloads/File*"); // files with an "File" in the filename
               for(size_t i = 0; i< res.size();   i)
                  std::cout << res[i] << 'n';
            } catch(const exceptionamp; ex) {
            cerr << ex.what() << endl;
        }
    }

 
 

Ответ №1:

Вроде как вы можете отфильтровывать каталоги. Измените GLOB_TILDE GLOB_TILDE | GLOB_MARK примерно так:

 vector<string> glob(const stringamp; pattern) {
    glob_t glob_result = {};
    vector<string> filenames;
    try {
        int return_value = ::glob(pattern.c_str(), GLOB_TILDE | GLOB_MARK, NULL, amp;glob_result);
        if (return_value != 0) {
            throw runtime_error(strerror(errno));
        }
        filenames.reserve(glob_result.gl_pathc);
        for (size_t globIndex = 0; globIndex < glob_result.gl_pathc;   globIndex) {
            std::string filename = glob_result.gl_pathv[globIndex];
            if (filename.size() > 0 amp;amp; filename[filename.size() - 1] != '/') {
                filenames.push_back(filename);
            }
        }
    } catch(...) {
        globfree(amp;glob_result);
        throw;
    }
    // cleanup
    globfree(amp;glob_result);

    // done
    filenames.shrink_to_fit();
    return filenames;
}
 

Примечания:

  • вам все равно придется stat просматривать каждый результат и проверять, является ли он файлом. Может быть символической ссылкой, файлом устройства, именованным каналом (FIFO)…
  • код не был безопасным для исключений, при заполнении вектора память может закончиться, и ваша очистка не произойдет. Используйте try / catch или что-то вроде scope_exit (если можете) или напишите объект guard и используйте его деструктор.
  • Я не уверен, следует ли вам globfree в случае ошибки, но valgrind предполагает, что это не проблема.