Your error handling is not revealing the actual error message. Consider this code:
|| die "File not found";
Are you sure that's why open failed? There are reasons other than the file not being found, and you aren't actually displaying the message that the system call produces. Your "die" statements should also output the contents of $!, which is described in perlvar.
|| die "Unable to open input file: $!"; # ... and ... || die "Unable to open output file: $!";
By displaying the actual error message instead of the one you assume happened, you learn a lot more about why something failed.
If I were writing it, the code would look more like this:
use strict; use warnings; use File::Temp; use File::Copy qw(move); use Fcntl qw(:flock); my $target_file = 'generic_bist_ctrl_defines.sv'; { open my $in_fh, '<', $target_file or die "Cannot open input file: +$!\n"; flock $in_fh, LOCK_EX | LOCK_NB or die "Cannot obtain a lock on $t +arget_file: $!\n"; my $temp_out = File::Temp->new(TEMPLATE => "$0-$$-XXXXX"); while (my $line = <$in_fh>) { $line =~ s/=131/= $a/g; # Did you actually mean $line =~ s/=(1 +31)/= $1/g; ??? print $temp_out $line; } close $in_fh or die "Failed to close $target_file. Aborting. $!\n" +; $temp_out->flush; eval { move($temp_out->filename, $target_file); } or do { warn "Failed to swap $temp_out into $target_file: $!\n"; # There may need to be more cleanup here, or possibly a die is + more appropriate. }; } # $temp_out falls out of scope; temp file should be removed even i +f the move call failed. # flock falls out of scope; lock is released on $target_file.
And I'd want to test it to make sure I hadn't missed something, since File::Temp can be tempermental if used incorrectly, and because I would want to verify I'm using File::Copy's move correctly. But the pattern is approximately correct.
The pattern here is:
The reason for writing to a tempfile and moving is to reduce the potential for corruption of the input file, by making its replacement an atomic event.
Alternatively, you could use a module such as Tie::File, which is a fairly safe way to work line-by-line through files, modifying as you go. But it's less efficient. For small files or infrequent writes, it probably doesn't matter. For large files or frequent rewrites, it's probably not optimal. Here's an example:
use strict; use warnings; use Fcntl qw(:flock); use Tie::File; my $target_file = '.....'; { my ($tied, @file_content) $tied = tie @file_content, 'Tie::File', filename or die "Unable to + tie $target_file: $!\n"; $tied->flock(LOCK_EX|LOCK_NB) or die "Cannot lock $target_file. Ab +orting. $!\n"; foreach my $line (@file_content) { $line =~ s/foo/bar/; } } # $tied falls out of scope. File is closed, lock expires.
It's simpler code, just less efficient. And it does allow you to avoid meddling with tempfiles yourself. However, File::Temp doesn't create a single atomic write; it writes changes as you make them line by line. So you could become exposed to corruption if someone else is messing with the file (ignoring advisory locks). If that's a possibility, you're much better off going with some version of the first solution.
Dave
In reply to Re: Unable to write the .sv file
by davido
in thread Unable to write the .sv file
by suvendra123
| For: | Use: | ||
| & | & | ||
| < | < | ||
| > | > | ||
| [ | [ | ||
| ] | ] |