这些例程与系统 C 库中的对应例程相同。在列表上下文中,各种 get 例程的返回值如下
# 0 1 2 3 4
my ( $name, $passwd, $gid, $members ) = getgr*
my ( $name, $aliases, $addrtype, $net ) = getnet*
my ( $name, $aliases, $port, $proto ) = getserv*
my ( $name, $aliases, $proto ) = getproto*
my ( $name, $aliases, $addrtype, $length, @addrs ) = gethost*
my ( $name, $passwd, $uid, $gid, $quota,
$comment, $gcos, $dir, $shell, $expire ) = getpw*
# 5 6 7 8 9
(如果条目不存在,则返回值为单个无意义的 true 值。)
$gcos 字段的确切含义各不相同,但它通常包含用户的真实姓名(与登录名相对)以及与用户相关的其他信息。但是,请注意,在许多系统中,用户都可以更改此信息,因此它不可信,因此 $gcos 被污染(请参阅 perlsec)。出于相同的原因,$passwd 和 $shell(用户的加密密码和登录 shell)也被污染。
在标量上下文中,您将获得名称,除非该函数是按名称查找,在这种情况下,您将获得其他内容,无论它是什么。(如果条目不存在,您将获得未定义的值。)例如
my $uid = getpwnam($name);
my $name = getpwuid($num);
my $name = getpwent();
my $gid = getgrnam($name);
my $name = getgrgid($num);
my $name = getgrent();
# etc.
在 getpw*() 中,字段 $quota、$comment 和 $expire 是特殊的,因为它们在许多系统上不受支持。如果 $quota 不受支持,它将是一个空标量。如果它受支持,它通常会对磁盘配额进行编码。如果 $comment 字段不受支持,它将是一个空标量。如果它受支持,它通常会对用户进行一些管理注释编码。在某些系统中,$quota 字段可能是 $change 或 $age,这些字段与密码老化有关。在某些系统中,$comment 字段可能是 $class。如果存在 $expire 字段,它将对帐户或密码的过期期限进行编码。有关这些字段在系统中的可用性和确切含义,请查阅 getpwnam(3) 和系统的 pwd.h 文件。您还可以通过使用 Config
模块和值 d_pwquota
、d_pwage
、d_pwchange
、d_pwcomment
和 d_pwexpire
,从 Perl 中找出 $quota 和 $comment 字段的含义以及您是否有 $expire 字段。仅当您的供应商以直观的方式实现了影子密码文件时,才支持影子密码文件,即在您以特权运行或存在 shadow(3) 函数(如在 System V 中找到的)时,调用常规 C 库例程将获取影子版本(包括 Solaris 和 Linux)。实现专有影子密码机制的系统不太可能得到支持。
getgr*() 返回的 $members 值是组成员登录名的空格分隔列表。
对于 gethost*() 函数,如果在 C 中支持 h_errno
变量,则如果函数调用失败,它将通过 $?
返回给您。成功调用返回的 @addrs
值是相应库调用返回的原始地址列表。在 Internet 域中,每个地址的长度为四个字节;您可以通过说类似于以下内容来解包它
my ($w,$x,$y,$z) = unpack('W4',$addr[0]);
Socket 库使这变得稍微容易一些
use Socket;
my $iaddr = inet_aton("127.1"); # or whatever address
my $name = gethostbyaddr($iaddr, AF_INET);
# or going the other way
my $straddr = inet_ntoa($iaddr);
相反,要将主机名解析为 IP 地址,您可以编写以下内容
use Socket;
my $packed_ip = gethostbyname("www.perl.org");
my $ip_address;
if (defined $packed_ip) {
$ip_address = inet_ntoa($packed_ip);
}
确保在 SCALAR 上下文中调用 gethostbyname
,并检查其返回值是否已定义。
即使 getprotobynumber
函数只接受一个参数,它也具有列表运算符的优先级,因此请注意
getprotobynumber $number eq 'icmp' # WRONG
getprotobynumber($number eq 'icmp') # actually means this
getprotobynumber($number) eq 'icmp' # better this way
如果您厌倦了记住返回列表的哪个元素包含哪个返回值,则标准模块中提供了按名称接口:File::stat
、Net::hostent
、Net::netent
、Net::protoent
、Net::servent
、Time::gmtime
、Time::localtime
和 User::grent
。这些覆盖了正常的内置函数,提供返回具有每个字段的相应名称的对象的版本。例如
use File::stat;
use User::pwent;
my $is_his = (stat($filename)->uid == pwent($whoever)->uid);
即使它们看起来像是相同的函数调用(uid),但它们并不相同,因为 File::stat
对象与 User::pwent
对象不同。
在多个线程可以使用这些函数的多线程环境中,这些函数中的许多函数是不安全的。特别是,诸如 getpwent()
的函数按进程而不是按线程进行迭代,因此如果两个线程同时进行迭代,则两个线程都将无法获取所有记录。
某些系统具有某些函数的线程安全版本,例如 getpwnam_r()
而不是 getpwnam()
。在那里,Perl 会自动且无形地替换线程安全版本,而无需通知。这意味着在某些系统上安全运行的代码在缺少线程安全版本的其他系统上可能会失败。
可移植性问题:perlport 中的“getpwnam” 到 perlport 中的“endservent”。