【问题标题】:Perl System Command to Windows NUL or /dev/nullPerl 系统命令到 Windows NUL 或 /dev/null
【发布时间】:2013-06-11 17:48:14
【问题描述】:

实际上有两个问题:

我正在通过我的 Perl 脚本创建一个 Subversion 标记。在创建该标签之前,我想查看该标签是否已经存在。我可以做到这一点的一种方法是运行 svn ls $url 并查看命令是否失败:

my $error = system(svn ls $url);
if ( $error ) {
    say qq(URL "$url" doesn't exist. Create that tag);
}
else {
    say qq(Tag "$url" already exists. Abort! Abort!);
}

但是,STDERRSTDOUT 都将被推送到终端。因此,我必须捕获输出并将其转储为空。在 Windows 中,它是 NUL。在 Unix/Linux/Mac 中,它是 /dev/null:

use Config;

my $null;
if ( $Config{osname} =~ /Win(32|64)$/i ) {
    say "This is a Windows system":
    $null = 'NUL';
}
else {
    say "This is Unix or Linux";
    $null = '/dev/null';
}

my $command = qq(svn ls $url > $null 2>&1);
my $error = system $command;
if ( $error ) {
    say qq(URL "$url" doesn't exist. Create that tag);
}
else {
    say qq(Tag "$url" already exists. Abort! Abort!);
}

这行得通,但要查看 URL 是否存在似乎需要做很多工作。

问题 #2:有更好的方法吗?我知道在 Perl 中执行命令并查看命令是否失败的三种方法:

  1. my $error = system $command
  2. my $output = qx($command)
  3. open my $fh, '-|', $command

在每一个中,STDERR 都会打印到终端,并且必须被捕获。有没有办法执行命令,扔掉 STDERR 和/或 STDOUT 并只查看命令状态?


回答

Borodin 有一个好主意。将STDERR 重定向到STDOUT 并使用qx/.../。我不必担心操作系统或NUL/dev/null

my $command = qq(svn ls $url 2>&1);
my $output = qx($command);
if ( $? ) {
    say qq(URL "$url" doesn't exist. Create that tag);
}
else {
    say qq(Tag "$url" already exists. Abort! Abort!);
}

【问题讨论】:

  • 您可能需要检查 $? 的值,以确保它与URL doesn't exist 一致,因为不同的地方可能出错了。

标签: perl system


【解决方案1】:

您可以将STDERR 重定向到STDOUT,就像您在自己的示例中一样。然后qx/$command/,或从打开的管道读取的数据,会将组合输出返回到两个流。在任何平台上都会以$? 返回状态。

或者,您是否考虑过Alien::SVNSVN::Client 模块有一个 ls 方法,它允许您完全做到这一点,而无需使用命令行程序。如果你传递一个不存在的目标,那么模块会引发$SVN::Error::FS_NOT_FOUND,你可以使用Try::Tiny 捕获它。

【讨论】:

  • 在这个站点上安装 CPAN 模块是一件很痛苦的事情。但是,如果我将 STDERR 重定向到 STDOUT(您说的是 OUT->ERR 方式,但我认为您的意思是 ERR->OUT),并使用qx/../,我不必担心NUL/dev/null .我可以简单地将所有输出扔掉。好主意。
  • 不过,您仍然需要担心正确形成字符串文字
【解决方案2】:

你可以同时处理这两个 shell。

BEGIN {
    if ($^O eq 'MSWin32') {
        require Win32::ShellQuote;
        no warnings 'once';
        *shell_quote = \&Win32::ShellQuote::quote_system_string;
    } else {
        require String::ShellQuote;
        String::ShellQuote->import('shell_quote');
    }
}

my $null = $^O eq 'MSWin32' ? 'nul' : '/dev/null';
my $cmd = shell_quote('svn', 'ls', $url) . " >$null 2>&1";
system($cmd);

或者您可以完全避免使用外壳。

use IPC::Run3 qw( run3 );
run3 [ 'perl', '-e', "warn 'abc'" ], \undef, \undef, \undef;

您甚至可以使用SVN::Client 完全避免svn 可执行文件!

【讨论】:

  • 这是一个服务器盒,在上面安装 CPAN 模块很痛苦。另外,它是 Perl 5.8.8(这是我们在服务器上允许的所有版本)。我必须请求加载模块,然后希望服务人员做得对。否则,我只需安装 SVN::Client,这会让事情变得更容易。
  • @DavidW.:这似乎是一种非常复古的思维方式。你知道阻止 Perl 升级的原因吗?
  • 那你为什么需要跨平台可移植性??
  • 好吧,这对你来说真的很糟糕,因为这三个解决方案都需要一个非核心模块。您确实意识到安装模块不需要任何特殊权限,对吧?
  • 偏执狂。他们有供应商支持的 Linux,所有软件升级都必须经过非常严格的认证过程。任何可能导致问题的升级都可能使我们损失数百万美元的收入。用户安装 Perl 会触发很多警报,因为这可能是试图绕过他们的安全性。他们有数以千计的服务器连接到 Internet,并且对任何可能是恶意软件迹象的事情保持警惕。这就是为什么我会权衡我可能需要的每个 CPAN 模块的优缺点。
猜你喜欢
  • 2013-06-25
  • 2023-04-04
  • 1970-01-01
  • 2015-01-20
  • 2021-11-24
  • 2011-05-23
  • 1970-01-01
  • 1970-01-01
  • 2014-08-16
相关资源
最近更新 更多