0

I have the following script:

#! /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");
   }
}

When I run this, I am getting the following output:

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'

The print of the command shows the correct expansions of the variables as I intended. However, when run using the system (), it throws an error saying the destination is missing.

Further, when I issue the command by giving it as a list, the copy happens but the destination path is missing the ".$rev" that is part of the $dirn.

I ran with v5.8.8 and v5.24.0 and I'm getting the same output.

What is happening? Why is system () behaving this way?

Thank you.

1 Answer 1

2

-print0 prints the paths followed by a NUL, so

  • $log_files[0] contains

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

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

Replace

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

with

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

or

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

s/\0.*//s for @log_files;
Sign up to request clarification or add additional context in comments.

3 Comments

Thank you. That worked. Could you elaborate on what this NUL was? I googled but couldn't find anything relevant to this example.
First of all, there was a problem with my earlier answer. It has been fixed. /// find's default action is -print, which prints the paths followed by a newline. Instead, you used -print0, which prints the paths followed by a NUL. Most system calls including the exec* system call used by backticks accept a NUL-terminated string, so the command you build gets cut short.
I misthought that using -print0 would be a clever way to avoid using the chomp inside the for loop. Thank you for explaining the concept of NUL-terminated strings. I changed the code to use the default -print and chomp and it works as expected.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.