How to replace the home directory with a tilde? Li

2019-08-25 18:24发布

问题:

I'm currently making a shell in C++ and I've been able to output the absolute directory as the prompt with getcwd(), however when the user reaches the home directory I would like to output a tilde instead of the home directory.

So for example instead of

[bb@bbmachine bb]

I would like to output

[bb@bbmachine ~]

How would I do something like that?

回答1:

Read first about globbing, notably glob(7). For the expansion of path starting with tilde ~ consider wordexp(3) and glob(3).

For showing a path starting with the home directory, you need to get that home directory. You could use getenv(3) like getenv("HOME") (there are rare pathological cases where that could fail) or getpwuid(3) (or even getpw(3)) on the result of getuid(2). The home directory (when getpwuid succeeds) is given by the pw_dir field. See also credentials(7) (and execve(2)...)

There are rare pathological cases where getenv("HOME") and getpwuid(getuid()) fail or give unconsistent results (about the user's home directory). I believe you should detect failure, but you might not care about inconsistency. See also environ(7). You could even consider the GNU specific secure_getenv(3).

BTW, you could cache the home directory, i.e. compute it once in your shell. It is unlikely to change often.

You could also decide to canonicalize a path using realpath(3).

You certainly have corner cases: do you want to display /home/john/../mary/ as ~/../mary, as /home/mary/, as ~mary, (or even leave it as /home/john/../mary) assuming your process is running under john uid? (and both john and mary exist as user names in passwd(5) with home directories /home/john/ and /home/mary/). And what about /home/john/../../proc/$$/maps (see proc(5))?

You need to decide how you'll handle these corner or pathological cases, and document the behavior of your shell.

(the functions mentioned have a C API, you might want to use extern "C" in your C++ code)



回答2:

Exactly what @TheDude said. Here's some pseudocode.

#include "pwd.h"
#include <string>
string home=getenv("HOME");
int location=yourPathString.find(home);
length=home.length();
originalLength=yourPathString.length();
string newString=yourPathString.substr(0,location);
newString+= "~";
newString+= yourPathString.substr(location+length,originalLength);

This should give you the right idea, but remember, documentation and Google are your friends.String Reference



回答3:

You could use wordexp something like this:

#include <wordexp.h>

// put all the horrible bits into a function
std::string wordexp(std::string var, int flags = 0)
{
    wordexp_t p;
    if(!wordexp(var.c_str(), &p, flags))
    {
        if(p.we_wordc && p.we_wordv[0])
            var = p.we_wordv[0];
        wordfree(&p);
    }
    return var;
}

int main()
{
    auto const HOME = wordexp("~");

    std::string path = "/home/galik/wibble";

    if(path.find(HOME) == 0)
        path.replace(0, HOME.size(), "~");

    std::cout << path << '\n';
}

Output:

~/wibble