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

时间:2021-11-02 07:12:28

The question

What is the difference between Cwd::cwd and Cwd::getcwd in Perl, generally, without regard to any specific platform? Why does Perl have both? What is the intended use, which one should I use in which scenarios? (Example use cases will be appreciated.) Does it matter? (Assuming I don’t mix them.) Does choice of either one affect portability in any way? Which one is more commonly used in modules?

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

Even if I interpret the manual is saying that except for corner cases cwd is `pwd` and getcwd just calls getcwd from unistd.h, what is the actual difference? This works only on POSIX systems, anyway.

即使我解释手册是说除了角落情况cwd是`pwd`和getcwd只是从unistd.h调用getcwd,实际的区别是什么?无论如何,这仅适用于POSIX系统。

I can always read the implementation but that tells me nothing about the meaning of those functions. Implementation details may change, not so defined meaning. (Otherwise a breaking change occurs, which is serious business.)

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

What does the manual say

Quoting Perl’s Cwd module manpage:

引用Perl的Cwd模块手册页:

Each of these functions are called without arguments and return the absolute path of the current working directory.

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

  • getcwd

    GETCWD

    my $cwd = getcwd();

    我的$ cwd = getcwd();

    Returns the current working directory.

    返回当前工作目录。

    Exposes the POSIX function getcwd(3) or re-implements it if it's not available.

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

  • cwd

    CWD

    my $cwd = cwd();

    我的$ cwd = cwd();

    The cwd() is the most natural form for the current architecture. For most systems it is identical to `pwd` (but without the trailing line terminator).

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

And in the Notes section:

在Notes部分:

  • Actually, on Mac OS, the getcwd(), fastgetcwd() and fastcwd() functions are all aliases for the cwd() function, which, on Mac OS, calls `pwd`. Likewise, the abs_path() function is an alias for fast_abs_path()
  • 实际上,在Mac OS上,getcwd(),fastgetcwd()和fastcwd()函数都是cwd()函数的别名,在Mac OS上,它们调用`pwd`。同样,abs_path()函数是fast_abs_path()的别名

OK, I know that on Mac OS1 there is no difference between getcwd() and cwd() as both actually boil down to `pwd`. But what on other platforms? (I’m especially interested in Debian Linux.)

好吧,我知道在Mac OS1上,getcwd()和cwd()之间没有区别,因为它们实际上归结为`pwd`。但是在其他平台上呢? (我对Debian Linux特别感兴趣。)


1 Classic Mac OS, not OS X. $^O values are MacOS and darwin for Mac OS and OS X, respectively. Thanks, @tobyink and @ikegami.

1经典Mac OS,而不是OS X. $ ^ O值分别是Mac OS和OS X的MacOS和darwin。谢谢,@ tobyink和@ikegami。

And a little meta-question: How to avoid asking similar questions for other modules with very similar functions? Is there a universal way of discovering the difference, other than digging through the implementation? (Currently, I think that if the documentation is not clear about intended use and differences, I have to ask someone more experienced or read the implementation myself.)

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

1 个解决方案

#1


8  

Generally speaking

I think the idea is that cwd() always resolves to the external, OS-specific way of getting the current working directory. That is, running pwd on Linux, command /c cd on DOS, /usr/bin/fullpath -t in QNX, and so on — all examples are from actual Cwd.pm. The getcwd() is supposed to use the POSIX system call if it is available, and falls back to the cwd() if not.

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

Why we have both? In the current implementation I believe exporting just getcwd() would be enough for most of systems, but who knows why the logic of “if syscall is available, use it, else run cwd()” can fail on some system (e.g. on MorphOS in Perl 5.6.1).

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

On Linux

On Linux, cwd() will run `/bin/pwd` (will actually execute the binary and get its output), while getcwd() will issue getcwd(2) system call.

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

Actual effect inspected via strace

One can use strace(1) to see that in action:

可以使用strace(1)来查看实际操作:

Using cwd():

使用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

Using getcwd():

使用getcwd():

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

Reading Cwd.pm source

You can take a look at the sources (Cwd.pm, e.g. in CPAN) and see that for Linux cwd() call is mapped to _backtick_pwd which, as the name suggests, calls the pwd in backticks.

您可以查看源代码(Cwd.pm,例如在CPAN中)并查看Linux cwd()调用是否映射到_backtick_pwd,顾名思义,它在反引号中调用pwd。

Here is a snippet from Cwd.pm, with my comments:

这是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;
    }
}

Performance benchmark

Finally, the difference between two is that cwd(), which calls another binary, must be slower. We can make some kind of a performance test:

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

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

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

Now compare it with the system call:

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

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

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

Discussion, choice

But as you don't usually query the current working directory too often, both options will work — unless you cannot spawn any more processes for some reason related to ulimit, out of memory situation, etc.

但由于您通常不经常查询当前工作目录,因此两个选项都可以正常工作 - 除非由于某些原因与ulimit,内存不足等情况相关而无法生成任何其他进程。

Finally, as for selecting which one to use: for Linux, I would always use getcwd(). I suppose you will need to make your tests and select which function to use if you are going to write a portable piece of code that will run on some really strange platform (here, of course, Linux, OS X, and Windows are not in the list of strange platforms).

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

#1


8  

Generally speaking

I think the idea is that cwd() always resolves to the external, OS-specific way of getting the current working directory. That is, running pwd on Linux, command /c cd on DOS, /usr/bin/fullpath -t in QNX, and so on — all examples are from actual Cwd.pm. The getcwd() is supposed to use the POSIX system call if it is available, and falls back to the cwd() if not.

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

Why we have both? In the current implementation I believe exporting just getcwd() would be enough for most of systems, but who knows why the logic of “if syscall is available, use it, else run cwd()” can fail on some system (e.g. on MorphOS in Perl 5.6.1).

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

On Linux

On Linux, cwd() will run `/bin/pwd` (will actually execute the binary and get its output), while getcwd() will issue getcwd(2) system call.

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

Actual effect inspected via strace

One can use strace(1) to see that in action:

可以使用strace(1)来查看实际操作:

Using cwd():

使用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

Using getcwd():

使用getcwd():

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

Reading Cwd.pm source

You can take a look at the sources (Cwd.pm, e.g. in CPAN) and see that for Linux cwd() call is mapped to _backtick_pwd which, as the name suggests, calls the pwd in backticks.

您可以查看源代码(Cwd.pm,例如在CPAN中)并查看Linux cwd()调用是否映射到_backtick_pwd,顾名思义,它在反引号中调用pwd。

Here is a snippet from Cwd.pm, with my comments:

这是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;
    }
}

Performance benchmark

Finally, the difference between two is that cwd(), which calls another binary, must be slower. We can make some kind of a performance test:

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

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

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

Now compare it with the system call:

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

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

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

Discussion, choice

But as you don't usually query the current working directory too often, both options will work — unless you cannot spawn any more processes for some reason related to ulimit, out of memory situation, etc.

但由于您通常不经常查询当前工作目录,因此两个选项都可以正常工作 - 除非由于某些原因与ulimit,内存不足等情况相关而无法生成任何其他进程。

Finally, as for selecting which one to use: for Linux, I would always use getcwd(). I suppose you will need to make your tests and select which function to use if you are going to write a portable piece of code that will run on some really strange platform (here, of course, Linux, OS X, and Windows are not in the list of strange platforms).

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