【问题标题】:Perl system command changes the variable values and throws errorPerl 系统命令更改变量值并引发错误
【发布时间】:2017-04-09 01:07:56
【问题描述】:

我有以下脚本:

#! /bin/env perl 

use File::Basename;
my @log_files;
my $log_dir = "/tmp/";
my $path = "find_failing/";
$log_files[0] = (`find $path -name compile.log -print0`)[0];
$log_files[1] = (`find $path -name sim.log     -print0`)[0];
my $rev = "100";

print "@log_files << \n";

foreach (@log_files) {
   if (-f $_) {
      chomp;
      my $dirn = sprintf "%s/%s.%s", $log_dir, basename ($_), $rev;
      chomp $dirn;
      my $cmd = "cp -v $_ $dirn";
      chomp $cmd;
      print "C: $cmd\n";
      system ($cmd);
      system ("cp", "-v", $_, $dirn);
      system ("echo");
   }
}

当我运行它时,我得到以下输出:

find_failing/simulation/tc_ctrl.rtl/compile/compile.log find_failing/simulation/tc_ctrl.rtl/test_prbs.nrz.16.prbs23/sim.log << 
C: cp -v find_failing/simulation/tc_ctrl.rtl/compile/compile.log /tmp//compile.log.100
cp: missing destination file operand after `find_failing/simulation/tc_ctrl.rtl/compile/compile.log'
Try `cp --help' for more information.
`find_failing/simulation/tc_ctrl.rtl/compile/compile.log' -> `/tmp//compile.log'

C: cp -v find_failing/simulation/tc_ctrl.rtl/test_prbs.nrz.16.prbs23/sim.log /tmp//sim.log.100
cp: missing destination file operand after `find_failing/simulation/tc_ctrl.rtl/test_prbs.nrz.16.prbs23/sim.log'
Try `cp --help' for more information.
`find_failing/simulation/tc_ctrl.rtl/test_prbs.nrz.16.prbs23/sim.log' -> `/tmp//sim.log'

命令的打印显示了我想要的变量的正确扩展。但是,当使用 system() 运行时,它会抛出一个错误,指出缺少目标。

此外,当我通过将命令作为列表提供命令来发出命令时,会发生复制,但目标路径缺少作为 $dirn 一部分的“.$rev”。

我使用 v5.8.8 和 v5.24.0 运行,得到相同的输出。

发生了什么?为什么 system() 会这样?

谢谢。

【问题讨论】:

    标签: perl


    【解决方案1】:

    -print0 打印 NUL 后跟的路径,所以

    • $log_files[0] 包含

      find_failing/foo/compile.log<NUL>find_failing/bar/compile.log<NUL>
      
    • $log_files[1] 包含

      find_failing/foo/sim.log<NUL>find_failing/bar/sim.log<NUL>
      

    替换

    $log_files[0] = (`find $path -name compile.log -print0`)[0];
    $log_files[1] = (`find $path -name sim.log     -print0`)[0];
    

    ( $log_files[0] ) = split /\0/, `find $path -name compile.log -print0`;
    ( $log_files[1] ) = split /\0/, `find $path -name sim.log     -print0`;
    

    $log_files[0] = `find $path -name compile.log -print0`;
    $log_files[1] = `find $path -name sim.log     -print0`;
    
    s/\0.*//s for @log_files;
    

    【讨论】:

    • 谢谢。那行得通。你能详细说明这个 NUL 是什么吗?我用谷歌搜索,但找不到与此示例相关的任何内容。
    • 首先,我之前的回答有问题。它已被修复。 /// find 的默认操作是-print,它打印路径后跟一个换行符。相反,您使用了-print0,它会打印 NUL 后跟的路径。大多数系统调用(包括反引号使用的exec* 系统调用)都接受以 NUL 结尾的字符串,因此您构建的命令会被缩短。
    • 我误以为使用 -print0 是避免在 for 循环中使用 chomp 的聪明方法。感谢您解释 NUL 终止字符串的概念。我将代码更改为使用默认的-printchomp,它按预期工作。
    猜你喜欢
    • 1970-01-01
    • 2012-07-03
    • 2015-04-05
    • 1970-01-01
    • 2013-06-25
    • 1970-01-01
    • 2014-01-21
    • 1970-01-01
    • 2021-11-24
    相关资源
    最近更新 更多