Matching Against Specific Filenames

I have a working for-loop in my program, but it iterates over the files it creates, which use the same filename extension as the input files. How can I specify the filename extension while excluding specific characters before the extension?

In the following for-loop, *.pub is targeted for input, and the outputted files are suffixed with -cert.pub, causing an error (and potential endless loop):

let mut user_dir_pubkey = [&config.key.user_dir, "/*.pub"].join("");

for user in glob(&user_dir_pubkey).expect("Failed to read glob pattern") {

                let pub_key = user.expect("Failed to read glob result");

                let output = Command::new("ssh-keygen")
                        .args([
                                "s", &config.key.ca_priv_key,
                                "i", "name",
                                "n", &config.cert.principle,
                                "v", &config.cert.validity,
                                "O", "clear",
                                "O", "permit-pty",
                                "z", &serial_read,
                                &pub_key.display().to_string(),
                        ])
                        .output()
                        .unwrap_or_else(|_| panic!("Failed to generate OpenSSH certificate for {}", pub_key.display()));

                if !output.status.success() {
                        eprintln!("Command failed: {}", String::from_utf8_lossy(&output.stderr));
                        panic!("Certificate generation failed");
                }
        }

The outputted files should not be included in the loop, by excluding *-cert.pub, while including only *.pub.

glob patterns are not regular expression, using glob to exclude such patterns is very hard (if not impossible).

instead, I would suggest to filter out the unwanted paths manually.

the easiest solution is to just skip the entry in the loop:

for user in globe(...).expect("glob") {
    let pub_key = user.expect("glob entry");
    if pub_key
        .file_name()
        .expect("get path file name")
        .to_str()
        .expect("non utf8 file name")
        .ends_with("-cert.pub")
    {
        continue;
    }
    //...
}

or equialently, you can use Iterator::filter_map():

for pubkey in glob(&user_dir_pubkey)
        .expect("glob")
        .filter_map(|path| {
            let path = path.expect("glob entry");
            if path.file_name()
                    .expect("get path file name")
                    .to_str()
                    .is_some_and(|name| name.ends_with("-cert.pub")) {
                None
            } else {
                Some(path)
            }
        }) {
    let output = Command::new("ssh-keygen")
        .args(...)
    ...
}

alternatively, collect() the glob result first and then iterate through the collection, which will NOT include new files you generated during the iteration.

let glob_result: Vec<_> = glob(...).expect("glob").collect();
for user in glob_result {
    //...
}

I expected that using a glob-pattern was going to make it unreasonably difficult, but didn't know how the other methods worked in Rust. It seems like a niche thing to do, and couldn't find any examples of it.

For now, I went with the initialisation method (the latter method you provided), but will optimise it with the manual method, later.

Thank you for the assistance.