12

问题

通常,不考虑任何特定平台,PerlCwd::cwd和in之间有什么区别?Cwd::getcwd为什么 Perl 两者都有?预期用途是什么,我应该在哪些场景中使用哪一个?(示例用例将不胜感激。)这有关系吗?(假设我不混合它们。)任何一个的选择是否会以任何方式影响便携性?哪一个在模块中更常用?

即使我解释手册是说除了极端情况cwd`pwd`并且getcwd只是调用getcwdfrom unistd.h,实际区别是什么?无论如何,这只适用于 POSIX 系统。

我总是可以阅读实现,但这并没有告诉我这些函数的含义。实现细节可能会改变,没有那么定义的意思。(否则会发生重大变化,这是一件严肃的事情。)

说明书是怎么说的

引用 Perl 的Cwd 模块手册页

这些函数中的每一个都在没有参数的情况下调用,并返回当前工作目录的绝对路径。

  • 获取cwd

    my $cwd = getcwd();

    返回当前工作目录。

    公开 POSIX 函数 getcwd(3) 或在它不可用时重新实现它。

  • cwd

    my $cwd = cwd();

    cwd() 是当前架构最自然的形式。对于大多数系统,它与 `pwd` 相同(但没有尾随行终止符)。

在注释部分:

  • 实际上,在 Mac OS 上getcwd()fastgetcwd()fastcwd()函数都是函数的别名cwd(),在 Mac OS 上,函数称为 `pwd`。同样,该abs_path()函数是fast_abs_path()

好的,我知道在 Mac OS 1上 和 之间没有区别getcwd()cwd()因为两者实际上都归结为`pwd`. 但是在其他平台上呢?(我对 Debian Linux 特别感兴趣。


1经典 Mac OS,而不是 OS X。$^O值分别是 Mac OSMacOSdarwinOS X。谢谢@tobyink@ikegami

还有一个小问题:如何避免对其他功能非常相似的模块提出类似的问题?除了挖掘实现之外,是否有一种发现差异的通用方法?(目前,我认为如果文档不清楚预期用途和差异,我必须请教更有经验的人或自己阅读实现。

4

1 回答 1

10

一般来说

我认为这个想法cwd()总是解决外部的、特定于操作系统的获取当前工作目录的方式。也就是说,pwd在 Linux、command /c cdDOS、/usr/bin/fullpath -tQNX 等上运行——所有示例均来自实际的Cwd.pm. 如果getcwd()可用,则应该使用 POSIX 系统调用,如果不可用,则回退到cwd()

为什么我们两者都有?在当前的实现中,我相信导出getcwd()对于大多数系统来说就足够了,但是谁知道为什么“如果系统调用可用,使用它,否则运行cwd()”的逻辑在某些系统上会失败(例如在 Perl 5.6.1 中的 MorphOS 上) .

在 Linux 上

在 Linux 上,cwd()将运行`/bin/pwd`(将实际执行二进制文件并获取其输出),同时getcwd()将发出getcwd(2)系统调用。

实际效果检查通过strace

可以strace(1)用来查看实际情况:

使用cwd()

$ strace -f perl -MCwd -e 'cwd(); ' 2>&1 | grep execve
execve("/usr/bin/perl", ["perl", "-MCwd", "-e", "cwd(); "], [/* 27 vars */]) = 0
[pid 31276] execve("/bin/pwd", ["/bin/pwd"], [/* 27 vars */] <unfinished ...>
[pid 31276] <... execve resumed> )      = 0

使用getcwd()

$ strace -f perl -MCwd -e 'getcwd(); ' 2>&1 | grep execve
execve("/usr/bin/perl", ["perl", "-MCwd", "-e", "getcwd(); "], [/* 27 vars */]) = 0

阅读Cwd.pm

您可以查看源代码(Cwd.pm例如,在 CPAN 中)并查看 Linuxcwd()调用映射到_backtick_pwd哪个,顾名思义,调用pwdin 反引号。

这是来自 的片段Cwd.pm,附有我的评论:

unless ($METHOD_MAP{$^O}{cwd} or defined &cwd) {
    ...
    # some logic to find the pwd binary here, $found_pwd_cmd is set to 1 on Linux
    ...
    if( $os eq 'MacOS' || $found_pwd_cmd )
    {
        *cwd = \&_backtick_pwd;  # on Linux we actually go here
    }
    else {
        *cwd = \&getcwd;
    }
}

性能基准

最后,两者之间的区别在于cwd(),调用另一个二进制文件的速度必须慢一些。我们可以进行某种性能测试:

$ time perl -MCwd -e 'for (1..10000) { cwd(); }'

real    0m7.177s
user    0m0.380s
sys     0m1.440s

现在将其与系统调用进行比较:

$ time perl -MCwd -e 'for (1..10000) { getcwd(); }'

real    0m0.018s
user    0m0.009s
sys     0m0.008s

讨论、选择

但是由于您通常不会经常查询当前工作目录,因此这两个选项都可以使用 - 除非您由于某种原因无法生成更多进程ulimit,例如内存不足等情况。

最后,至于选择使用哪一个:对于 Linux,我总是使用getcwd(). 我想你需要进行测试并选择要使用的函数,如果你要编写一段可移植的代码,它将在一些非常奇怪的平台上运行(当然,这里不包括 Linux、OS X 和 Windows奇怪平台的列表)。

于 2014-08-25T11:26:43.960 回答