OrenIshShalom
OrenIshShalom

Reputation: 7142

Open an ofstream with tilde (~) in path name

I have to open some file for writing, and its name contains the tilde sign (~). The following code fails to create the desired text file. If I replace the ~ with /home/oren then everything works fine.

#include <fstream>
#include <string>

const std::string dirname  = "/home/oren/GIT/";
// const std::string dirname  = "~/GIT/";
const std::string filename = "someTextFile";

int main(int argc, char **argv)
{
    std::ofstream log_file(dirname+filename+".txt");
    log_file << "lorem ipsum";
    log_file.close();
}

Is there any way to (easily) handle a file with ~ in its name?

Upvotes: 7

Views: 4531

Answers (3)

eerorika
eerorika

Reputation: 238371

The tilde is expanded to the home directory by the shell. The iostreams don't use a shell, so you have to take care of the expansion for them. Tilde is a actually a valid character to use in a file name so without expansion, a file is created into a directory named ~ - which fails if the directory does not exist.

There is no standard way in C++ for shell expansions, nor a way to get the home directory, but there are several ways in POSIX systems:

wordexp is probably one of the most useful functions for this case. You can pass the path to the function and it will expand the tilde, as well as variables and braces. An example:

std::string full = dirname+filename+".txt"
wordexp_t p;
wordexp(full.c_str(), &p, 0);
std::string expanded = p.we_wordv[p.we_offs];
wordfree(&p);
std::ofstream log_file(expanded);

Other alternatives:

getpwuid gives you a structure with the home directory as a member. This can be used to get home directory of another user as well, in case that is needed.

HOME environment variable should also be available. It can be accessed with the standard std::getenv.

Upvotes: 2

erenon
erenon

Reputation: 19118

The ~ shortcut in paths is not something magical at the filesystem level, opening ~/GIT literally tries to access ~/GIT, i.e: a file named GIT in the ~ directory. You can verify this by creating ~ and GIT first.

In the command line, ~ is typically resolved by your shell. e.g: in bash:

~ : The value of $HOME

https://www.gnu.org/software/bash/manual/html_node/Tilde-Expansion.html

Therefore, to achieve the same effect, you have to query the $HOME envvar, and replace the usage of leading ~/ in the path:

#include <stdlib.h>
const char* home = getenv("HOME")
if (home) { /* replace ~/ with home */ }

In addition, on linux, the wordexp function can be used to perform these replacements (~ to current user, ~other_user to home of other user)

Upvotes: 19

Some programmer dude
Some programmer dude

Reputation: 409216

The tilde is part of the shell expansion, it's not something handled by the underlying operating system. You need to resolve it yourself.

One simple way is to replace leading "~/" with the contents of the environment variable HOME (if it exists).

Upvotes: 5

Related Questions