c++linuxc++17execvp

execvp() not executing correctly


I am trying to use execvp() to execute terminal programs from a GUI program. My test of choice was calling konsole (my terminal) with -e for execution and nvim ~/test.txt as the arguments. Calling the command from the Linux shell and writing the file yields expected results (the file already existed and had the following data prior to running both tests):

Output:

QLayout: Cannot add a null widget to QHBoxLayout/
Process <pid> did not die with SIGHUP

working

Calling the command using execvp() via the following example produces the following:

#include <unistd.h>

#include <string>
#include <vector>

using std::string;
using std::vector;

int main() {
    vector<string> strvec = {"konsole", "-e", "nvim", "~/test.txt"};
    vector<char*> vec;

    for (auto& str : strvec)
        vec.push_back(str.data());

    vec.push_back(nullptr);

    for (auto& arg : vec)
        printf("%s\n", arg);

    execvp(vec[0], vec.data());
}

Output:

konsole
-e
nvim
~/test.txt
(null)
QLayout: Cannot add a null widget to QHBoxLayout/
Process <pid> did not die with SIGHUP

image

The file is invalid?

Why is this happening, and what am I doing wrong?


Solution

  • ~ only has special meaning to a shell, not in general for path names.

    When you type ~ in a context where expansion happens in a shell, the shell will expand it to $HOME (i.e. the home directory). The result will be used in the shell command.

    So in your first example the shell will execute konsole and pass the arguments

    konsole
    -e
    nvim
    /home/user/test.txt
    

    (assuming $HOME is /home/user)

    not as you are doing

    konsole
    -e
    nvim
    ~/test.txt
    

    ~ itself is a valid character in Linux path names and ~ is just a normal directory with that name that nvim will then try to look for in the current working directory.


    Additionally, as mentioned in the question comments, printf("%s\n", arg); has undefined behavior when arg is a null pointer value, although implementations are often nice about it and define it to print something like (null).