How do I find a user's home directory in Perl?

PerlHome DirectoryTilde Expansion

Perl Problem Overview


I need to check whether a file in a user's home directory exists so use file check:

if ( -e "~/foo.txt" ) {
   print "yes, it exists!" ;
}

Even though there is a file called foo.txt under the user's home directory, Perl always complains that there is no such file or directory. When I replace "~" with /home/jimmy (let's say the user is jimmy) then Perl give the right verdict.

Could you explain why "~" dosen't work in Perl and tell me what is Perl's way to find a user's home directory?

Perl Solutions


Solution 1 - Perl

~ is a bash-ism rather than a perl-ism, which is why it's not working. Given that you seem to be on a UNIX-type system, probably the easiest solution is to use the $HOME environment variable, such as:

if ( -e $ENV{"HOME"} . "/foo.txt" ) {
    print "yes ,it exists!" ;
}

And yes, I know the user can change their $HOME environment variable but then I would assume they know what they're doing. If not, they deserve everything they get :-)

If you want to do it the right way, you can look into File::HomeDir, which is a lot more platform-savvy. You can see it in action in the following script chkfile.pl:

use File::HomeDir;
$fileSpec = File::HomeDir->my_home . "/foo.txt";
if ( -e $fileSpec ) {
    print "Yes, it exists!\n";
} else {
    print "No, it doesn't!\n";
}

and transcript:

pax$ touch ~/foo.txt ; perl chkfile.pl
Yes, it exists!

pax$ rm -rf ~/foo.txt ; perl chkfile.pl No, it doesn't!

Solution 2 - Perl

I'm not sure how everyone missed File::HomeDir. It's one of those hard tasks that sound easy because no one knows about all of the goofy exceptions you have to think about. It doesn't come with Perl, so you need to install it yourself.

Once you know the home directory, construct the path that you need with File::Spec:

 use File::HomeDir qw(home);
 use File::Spec::Functions qw(catfile);

 print "The path is ", catfile( home(), 'foo.txt' ), "\n";

Solution 3 - Perl

You can glob the tilde, glob('~/foo.txt') should work. Or you can use the File::Save::Home module that should also take care of other systems.

Solution 4 - Perl

The home directory for a user is stored in /etc/passwd. The best way to get at the information is the getpw* functions:

#!/usr/bin/perl 

use strict;
use warnings;

print "uid:", (getpwuid 501)[7], "\n",
	"name:", (getpwnam "cowens")[7], "\n";

To address your specific problem, try this code:

if ( -e (getpwuid $>)[7] . "/foo.txt" ) {
   print "yes ,it exists!";
}

Solution 5 - Perl

Solution 6 - Perl

Fast forward to 2020 and there is now in perl since version 5.31.10 at its core a module called File::Glob which resolves the tilde, such as:

perl -MFile::Glob=":bsd_glob" -lE 'say File::Glob::bsd_glob( "~john" )'

would produce: /home/john

or

perl -MFile::Glob=":bsd_glob" -lE 'say File::Glob::bsd_glob( "~/some/folder" )'

would produce: /home/jack/some/folder

The File::Glob module exist since perl v5.6, but only with the glob subroutine which has been deprecated.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionHaiyuan ZhangView Question on Stackoverflow
Solution 1 - PerlpaxdiabloView Answer on Stackoverflow
Solution 2 - Perlbrian d foyView Answer on Stackoverflow
Solution 3 - PerlzoulView Answer on Stackoverflow
Solution 4 - PerlChas. OwensView Answer on Stackoverflow
Solution 5 - PerlphoebusView Answer on Stackoverflow
Solution 6 - PerlJacquesView Answer on Stackoverflow