在Perl中如何检测操作系统?

63

我在 Mac、Windows 和 Ubuntu 上都有 Perl。如何在脚本内部区分它们?

编辑:有人问我在干什么。这是一个脚本,是我们跨平台构建系统的一部分。该脚本递归遍历目录并确定要构建哪些文件。某些文件是特定于某些平台的,因此,在 Linux 上,我不想构建以 _win.cpp 结尾的文件等。


1
你为什么需要知道呢?根据你所做的与平台相关的工作,可能会有更合适的答案。 - Rob
11个回答

90

查看$^O变量,它将包含操作系统的名称:

print "$^O\n";

该程序在Linux系统上打印linux,在Windows系统上打印MSWin32

如果您使用English模块,也可以通过名称$OSNAME引用此变量:

use English qw' -no_match_vars ';
print "$OSNAME\n";

根据perlport,在Mac OS X上 $^O 将会是 darwin
您也可以使用Config核心模块,该模块可以提供相同的信息(以及更多):
use Config;

print "$Config{osname}\n";
print "$Config{archname}\n";

在我的Ubuntu机器上运行该命令,结果如下:

linux
i486-linux-gnu-thread-multi

请注意,这些信息是基于构建Perl的系统而得出的,这并不一定意味着Perl当前运行的系统也是如此($^O$OSNAME同样如此)。操作系统可能不会改变,但某些信息(例如架构名称)可能会发生变化。

2
谢谢 :) 对于其他可能使用此答案的人来说,cygwin perl 返回“cygwin”,因此在Windows中有两种可能性。 - mxcl
3
超过两个;曾经有一个 DOS 版本,并且 OS2 版本曾经可以在 Windows 上运行。$^O 的所有可能值在理论上都记录在 http://perldoc.perl.org/perlport.html 中。 - ysth
@ysth,顺便提一下,你的链接有错别字。 - thecoshman
这个错别字来自于尾随的尖括号。应该是perldoc.perl.org/perlport.html - Alan
6
如果有人因为输出STDOUT_TOP0而暂时被困住,请确保使用的是$^O而不是$^0。我不能告诉你我是怎么知道这个的,但请相信我... - Anthony
显示剩余2条评论

14
如果你需要关于Windows更具体的信息,这可能会有所帮助。
my $osname = $^O;


if( $osname eq 'MSWin32' ){{
  eval { require Win32; } or last;
  $osname = Win32::GetOSName();

  # work around for historical reasons
  $osname = 'WinXP' if $osname =~ /^WinXP/;
}}

这段文字来源于sysinfo.t,它是我编写的原始版本。

如果您需要更详细的信息:

my ( $osvername, $major, $minor, $id ) = Win32::GetOSVersion();

1
win32使用了一个已经弃用的函数GetVersionExA。这在版本大于6.2的情况下不起作用。 - Mayra Delgado
@MayraDelgado 确实如此,看起来没有直接的替代品。这就是为什么需要这个功能的人应该想办法修复它并提供一个拉取请求。我现在很少使用Windows了,所以不太可能是我。 - Brad Gilbert

9
请看File::Spec源代码,了解它如何根据操作系统加载正确的代理。

File::Spec为每个操作系统单独提供了一个Perl模块文件,例如File::Spec::Win32File::Spec::OS2等。

它检查操作系统,并在运行时基于操作系统加载适当的.pm文件。

# From the source code of File::Spec
my %module = (
      MSWin32 => 'Win32',
      os2     => 'OS2',
      VMS     => 'VMS',
      NetWare => 'Win32', # Yes, File::Spec::Win32 works on NetWare.
      symbian => 'Win32', # Yes, File::Spec::Win32 works on symbian.
      dos     => 'OS2',   # Yes, File::Spec::OS2 works on DJGPP.
      cygwin  => 'Cygwin',
      amigaos => 'AmigaOS');


my $module = $module{$^O} || 'Unix';

require "File/Spec/$module.pm";
our @ISA = ("File::Spec::$module");

3
这可能是所有答案中最好的一个。不幸的是,它没有被评为受欢迎,因为除了 Stack Overflow 之外,没有人愿意自己进行任何研究。我将添加一些内容到这个答案中,这样懒惰的人就不必费劲地点击链接了。 :P - tjwrona1992

8

Sys::Info::OS 看起来是一个相对干净的潜在解决方案,但目前似乎不支持 Mac。不过添加支持应该不会太麻烦。


如果它支持Mac的话,这将是一个更好的答案。我更喜欢编译器辅助函数,而不是维护问题字符串。 - mxcl

4

这里有一个快速参考,介绍如何使用Perl查找本地计算机的操作系统。

$^O变量(如果您使用英语,则为$OSTYPE)包含您的perl二进制文件构建的操作系统。


4

变量 $^O(注意是大写字母 O,不是数字 0)保存操作系统的名称。

根据您所需,它可能会或可能不会给出您想要的答案 - 在我的系统上,它给出“linux”,但没有指明哪个发行版。我不太确定它在 Windows 或 MacOS 上的表现如何。


3

关于 Mac 计算机的信息:$^O 现在返回 'darwin',适用于 10.13.6(High Sierra)、10.15.4(Catalina)...以及 13.4(Ventura)。


3

一个经典的单行代码:

my $windows=($^O=~/Win/)?1:0;# Are we running on windows?

8
除非你正在运行 Darwin 操作系统! - user392408
糟糕!你是对的!将它区分大小写似乎可以解决问题。我已经进行了更正。发现得好! - Hawk
区分大小写的版本无法检测到“cygwin”。 - Oh My Goodness

1

如果需要一个通用的CPAN模块映射,请查看Perl::OSType

它被Module::Build使用。

所谓“通用映射”,它返回一个较小的操作系统标识符集合中的值 - 在大多数情况下,这可能更有用($^O可以返回50多个值)。查看源代码,可能的返回值只有

Unix
Windows
EBCDIC
MacOS
VMS
VOS
RiscOS
Amiga
MPEiX

该模块已经超过5年没有更新了,根据@brian-d-foy的回答,OS2明显缺失。此外,如果您想使用File::Spec,他的回答可能更适合这种情况。

1
#Assign the $home_directory variable the path of the user's home directory
my $home_directory = ($^O eq /Win/) ? $ENV{HOMEPATH} : $ENV{HOME};
#Then you can read/write to files in the home directory
open(FILE, ">$home_directory/my_tmp_file");
print FILE "This is a test\n";
close FILE;
#And/or read the contents of the file
open(FILE, "<$home_directory/my_tmp_file");
while (<FILE>){
    print $_;
}
close FILE;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接