0

I'm trying to run the command ls /home/aidan/Pictures/Wallpapers/*/*.{jpg,JPG,png,PNG} to get a list of wallpapers, and it runs fine in the terminal, but when I run it from C++ it tells me ls: cannot access /home/aidan/Pictures/Wallpapers/*/*.{jpg,JPG,png,PNG}: No such file or directory. Does anyone know what's up?

The command I used to run it:

std::string exec(std::string command) {
    const char *cmd = command.c_str();
    FILE* pipe = popen(cmd, "r");
    if (!pipe) return "ERROR";
    char buffer[128];
    std::string result = "";
    while(!feof(pipe)) {
        if(fgets(buffer, 128, pipe) != NULL)
            result += buffer;
    }
    pclose(pipe);
    return result;
}
Aido
  • 1,524
  • 3
  • 18
  • 41
  • Obviously - it does not expand the `{expression}` and treats it as a file name. – VP. Jul 09 '15 at 16:39
  • 1
    Maybe you should use the `glob` function instead of a shell command? See http://stackoverflow.com/questions/8401777/simple-glob-in-c-on-unix-system – Joe Jul 09 '15 at 16:45
  • Does `/bin/sh` do that expansion OK? Maybe the `popen()` is running a shell that doesn't do the `{…}` expansion for you. You might need to run `bash -c "ls /home/aidan/Pictures/Wallpapers/*/*.{jpg,JPG,png,PNG}"` instead of just the `ls` command. – Jonathan Leffler Jul 09 '15 at 16:58
  • @JonathanLeffler `exec("/bin/sh -c \"ls /home/aidan/Pictures/Wallpapers/*/*.{jpg,JPG,png,PNG}\""` gives the same error. – Aido Jul 09 '15 at 17:01
  • @Joe The solution the the question you pointed me at is returning nothing. How should I modify my input? – Aido Jul 09 '15 at 17:11
  • `exec`? I though you used `popen`? The rules for `exec` are radically different from the rules for `popen`. – Jonathan Leffler Jul 09 '15 at 17:11
  • @JonathanLeffler My `exec` method is using `popen`. I got it from [here](http://stackoverflow.com/questions/478898/how-to-execute-a-command-and-get-output-of-command-within-c). – Aido Jul 09 '15 at 17:12
  • Oh; uggh! Sorry, hadn't noticed that you were preempting a generic name. OK; I take back the comment. If you pass `bash -c "…"` (which mustn't contain backslashes when it is printed) and it still fails, I'm out of ideas. – Jonathan Leffler Jul 09 '15 at 17:13
  • @JonathanLeffler That worked! I got the globing to work too, though, and apparently that's safer, so I'll just use that. Thanks, though! – Aido Jul 09 '15 at 17:30
  • Globbing yourself (using the system-provided functions) instead of using `ls` and pipes has a number of merits — go with it. – Jonathan Leffler Jul 09 '15 at 17:32
  • 1
    I'm now using `std::vector walls = glob("/home/aidan/Pictures/Wallpapers/*/*.jpg") + glob("/home/aidan/Pictures/Wallpapers/*/*.JPG") + glob("/home/aidan/Pictures/Wallpapers/*/*.png") + glob("/home/aidan/Pictures/Wallpapers/*/*.PNG");` with `glob` from [here](http://stackoverflow.com/a/8615450/1526048) and `+` from [here](http://stackoverflow.com/a/21391109/1526048). – Aido Jul 09 '15 at 17:35

2 Answers2

2

Wildcards like "*" or "{x,y,z}" are evaluated by the shell. If you run a program without intermediate shell, those are not evaluated but passed verbatim to the program, which should explain the error message.

Ulrich Eckhardt
  • 16,572
  • 3
  • 28
  • 55
1

Wildcards like * are evaluated by the shell, so you'll have to invoke the shell directly to if you want it to process something for you.

For example, calling /bin/sh -c "ls /home/aidan/Pictures/Wallpapers/*/*.{jpg,JPG,png,PNG}" instead of ls /home/aidan/Pictures/Wallpapers/*/*.{jpg,JPG,png,PNG} will work. There is also a system call called system() that invokes a given command in the default shell for you.

However, using the shell to do the globbing is very dangerous if you pass untrusted user input to the shell. So try listing all the files and then using a native globbing solution to filter them instead of shell expansions.

Shnatsel
  • 4,008
  • 1
  • 24
  • 25
  • I'm pretty new to c++, what is globbing? – Aido Jul 09 '15 at 16:55
  • Globbing is the expansion of the 'glob' (`*`) in file names, and more generally, filename expansion. – Jonathan Leffler Jul 09 '15 at 16:58
  • Huh. I'll look into the comment about the `glob` function. Also, `exec("/bin/sh -c \"ls /home/aidan/Pictures/Wallpapers/*/*.{jpg,JPG,png,PNG}\""` gives the same error. – Aido Jul 09 '15 at 17:03
  • Concerning your question what globbing is, just search the web, @AidanEdwards: https://duckduckgo.com/?q=globbing. Concerning the error, what is the output if you run the command without `exec()`, i.e. outside of C++? – Ulrich Eckhardt Jul 09 '15 at 21:24