3

其实有两个问题:

我正在通过我的 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 并只查看命令状态?


回答

鲍罗丁有一个好主意。重定向STDERRSTDOUT并使用qx/.../. 我不必担心操作系统或NULvs. /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!);
}
4

2 回答 2

0

你可以处理两个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使用SVN::Client完全避免执行该可执行文件!

于 2013-06-11T18:38:13.720 回答
0

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

或者,你考虑过Alien::SVN吗?该SVN::Client模块有一种ls方法可以让您完全做到这一点,而无需使用命令行程序。如果您传递了一个不存在的目标,那么模块会引发$SVN::Error::FS_NOT_FOUND您可以使用Try::Tiny.

于 2013-06-11T18:24:03.647 回答