Perl Cwd :: cwd和Cwd :: getcwd函数有何不同?

时间:2014-08-09 15:17:36

标签: perl working-directory perl5 getcwd

问题

Perl中Cwd::cwdCwd::getcwd之间的区别是什么,通常不考虑任何特定平台?为什么Perl都有?什么是预期用途,我应该在哪些场景中使用哪一个? (示例用例将受到赞赏。)这有关系吗? (假设我不混合它们。)任何一个的选择是否会以任何方式影响可移植性?哪一个更常用于模块?

即使我解读说明书,除了角落案例cwd `pwd`getcwd只是从getcwd拨打unistd.h之外,是什么实际差异?无论如何,这仅适用于POSIX系统。

我总是可以阅读实现,但这并没有告诉我这些功能的含义。实施细节可能会发生变化,而非定义的含义。 (否则会发生重大变化,这是一项严肃的事情。)

手册说什么

引用Perl的Cwd module manpage

  

每个函数都不带参数调用,并返回当前工作目录的绝对路径。

     
      
  • GETCWD

         

    my $cwd = getcwd();

         

    返回当前工作目录。

         

    暴露POSIX函数getcwd(3)或者如果它不可用则重新实现它。

  •   
  • CWD

         

    my $cwd = cwd();

         

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

  •   

在Notes部分:

  
      
  • 实际上,在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 OS和OS X MacOSdarwin谢谢,@tobyink@ikegami

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

1 个答案:

答案 0 :(得分:9)

一般来说

我认为这个想法是cwd()总是解析为获取当前工作目录的外部特定于操作系统的方式。也就是说,在Linux上运行pwd,在DOS上运行command /c cd,在QNX中运行/usr/bin/fullpath -t,依此类推 - 所有示例都来自实际的Cwd.pmgetcwd()应该使用POSIX系统调用(如果可用),如果没有则返回cwd()

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

在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中)并查看针对Linux cwd()的调用是否已映射到_backtick_pwd,顾名思义,它调用了在反叛中pwd

以下是来自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不在奇怪的平台列表。)