【问题标题】:How do I find a user's home directory in Perl?如何在 Perl 中找到用户的主目录?
【发布时间】:2010-12-01 07:32:09
【问题描述】:

我需要检查用户主目录中的文件是否存在,所以使用文件检查:

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

即使在用户的主目录下有一个名为 foo.txt 的文件,Perl 总是 抱怨没有这样的文件或目录。当我将“~”替换为 /home/jimmy(假设用户是 jimmy)时,Perl 会给出正确的判断。

您能否解释一下为什么“~”在 Perl 中不起作用并告诉我 Perl 的方法是什么? 找到用户的主目录?

【问题讨论】:

  • ~ 是一个外壳。这就是为什么它在 Perl 中不起作用的原因。 :)
  • 你也可以这样看:如果这个 were 应该工作,那么 Perl 必须用你的替换 every 字符串中的波浪号主目录。然后,您将始终必须在编写的每个字符串中转义波浪号。还要与 bash 进行比较:如果你想要波浪号扩展,那么你的字符串必须 not 用引号引起来,否则 bash 不会扩展它。所以实际上你可以说 Perl 在这里的工作方式与 Bash 完全一样:如果波浪号在引号中,那么它没有什么特别的。 ;)

标签: perl home-directory tilde-expansion


【解决方案1】:

~bash-ism 而不是 perl-ism,这就是它不起作用的原因。鉴于您似乎使用的是 UNIX 类型的系统,可能最简单的解决方案是使用$HOME 环境变量,例如:

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

是的,我知道用户可以更改他们的$HOME 环境变量,但我会假设他们知道自己在做什么。如果没有,他们应该得到他们得到的一切:-)

如果您想以正确的方式进行操作,您可以查看File::HomeDir,它更懂平台。您可以在以下脚本 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";
}

和成绩单:

pax$ touch ~/foo.txt ; perl chkfile.pl 是的,它存在! pax$ rm -rf ~/foo.txt ; perl chkfile.pl 不,它没有!

【讨论】:

  • 这有几个问题:不是所有的会话都设置了 HOME,也不是所有的系统都像 unix 那样构建它们的路径。 File::HomeDir 会给你正确的答案。
  • 不要在不需要的时候假设。有用的程序倾向于迁移。 :)
  • 对此的回复真的晚了,但它可能对当前读者有用——另一种方法是使用glob('~/foo.txt')。这样做的好处是它也可以正确扩展 ~user123/foo.txt 之类的内容。我意识到 OP 特别提到了主目录,但我在寻找更通用的东西时遇到了这个问题,并认为我会帮助其他人走同样的路。
  • @John,不要忘记在这里投票给zoul的答案,因为它特别提到了glob()方法。
【解决方案2】:

我不确定每个人是如何错过File::HomeDir。这是听起来很容易的艰巨任务之一,因为没有人知道您必须考虑的所有愚蠢的例外情况。 Perl 没有自带,所以需要自己安装。

一旦你知道主目录,用File::Spec构造你需要的路径:

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

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

【讨论】:

  • 或与File::chdir(我最喜欢的CPAN模块)一起使用:... use File::chdir; { local $CWD = home; if (-e $file) { ... } },独立于平台,阻止本地工作目录管理!
【解决方案3】:

你可以glob 波浪号,glob('~/foo.txt') 应该可以工作。或者你可以使用File::Save::Home 模块,它也应该照顾其他系统。

【讨论】:

  • 为什么投反对票?这两种方法都有效。如果他们有问题,我想知道。
  • 您好,我只是一个初学者,但如果我的 Win 7 主目录中有一个 .jpg 文件并运行: print glob('~/*.jpg');它什么也没做。但如果我运行: print glob('Users/Daniel/*.jpg');它打印:/Users/Daniel/JanesJinormousJugs.jpg
  • 非常优雅的非便携式解决方案。如果你有一个专门为在 linux 环境中运行而编写的 perl 脚本(例如,你使用 bash 脚本,那么这样做不会丢失任何东西,因为你已经是不可移植的了)
【解决方案4】:

用户的主目录存储在/etc/passwd 中。获取信息的最佳方式是getpw* functions

#!/usr/bin/perl 

use strict;
use warnings;

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

要解决您的具体问题,请尝试以下代码:

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

【讨论】:

  • File::HomeDir 不是核心模块,因此如果您不想添加依赖项,这可能是一个不错的选择。
【解决方案5】:

【讨论】:

    【解决方案6】:

    快进到 2020 年,从 5.31.10 版开始,现在 perl 的核心是一个名为 File::Glob 的模块,它可以解析波浪号,例如:

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

    将产生:/home/john

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

    将产生:/home/jack/some/folder

    File::Glob 模块自 perl v5.6 起就存在,但仅限于已弃用的 glob 子例程。

    【讨论】:

      猜你喜欢
      • 2010-10-04
      • 1970-01-01
      • 2011-02-09
      • 1970-01-01
      • 2016-04-27
      • 1970-01-01
      • 1970-01-01
      • 2023-03-11
      相关资源
      最近更新 更多