in reply to Read in hostfile, modify, output

I will demo another way (of many) to write the regex code below.

As others have said, this line,

map{if($_ =~ /^(#)?(10\.10\.1\.2.*)/){$_ = $1 eq '#' ? $2 : "#$2";}} @ +Output;
gives me a headache.

Do not make the mistake of assuming that fewer lines of Perl code means more efficient or "better" code. This map is an implied foreach loop whether you want to write the source code that way or not.

I prefer to translate $1, $2, etc into named variables when possible. Compared with firing up the regex engine, this is very "cheap" CPU wise. Also, white space consumes no MIPs! Space things out and write something that you will understand 2 years from now.

#!/usr/bin/perl use strict; use warnings; my @hosts = ("10.10.1.2 # some comment ...\n", "#10.10.1.56\n", "14.1.2.89\n"); my $pattern = '10.10.1'; foreach my $line (@hosts) { if ( my ($comment, $rest) = $line =~ /^(#)?($pattern.*\n)/) { if (defined $comment) { $line = $rest; # delete the beginning # comment char } else { $line = "#$rest"; # add a beginning # comment char } } } print @hosts; __END__ #10.10.1.2 # some comment ... 10.10.1.56 14.1.2.89
Your idea of reading the hosts file into memory, my @Output = <$In>; is a good one - this file will not be "huge" and this is fine.

The idea of over-writing the original file with the modified contents is not so good. That will work most of the time, but I would make a temp file of some sort, write to that, then rename the temp file to the host file name. If for nothing else, this will help with the debugging!

There is no truly "atomic" operation on the file system - something can always go wrong within a fileop. Good system code plans for that and also makes the "window of vulnerability" as short as possible.

Replies are listed 'Best First'.
Re^2: Read in hostfile, modify, output
by eyepopslikeamosquito (Archbishop) on Dec 17, 2016 at 22:31 UTC

    There is no truly "atomic" operation on the file system

    From the Open Group Specification of rename:

    That specification requires that the action of the function be atomic
    That is, the rename(1) system call is required to be atomic on all Unix systems. As tye points out, rename is also atomic on Windows.

    In practice, on Unix and Windows, so long as both files reside on the same OS file system, you should be able to rely on the Perl rename function being atomic.

      Geez, I see that my poorly explained comment about atomic operations generated some discussion.

      To digress a bit, Wiki Linearizability contains a good discussion about what "atomic" means. I'll just quote part: Atomicity is a guarantee of isolation from concurrent processes. Additionally, atomic operations commonly have a succeed-or-fail definition, they either successfully change the state of the system, or have no apparent effect.

      In the case of a single rename(), as long as the system software and hardware work as expected, a single rename can be considered atomic. There are ways (like system reset (hardware,software or human induced) or power supply transient) that can mess things up.

      To replace an important file with a new version, first get the new file onto the system in its entirety. Now a quick two step dance happens. At a minimum, rename the existing file to something else, probably some sort of .bak. Then as soon as possible, rename the new file to what the existing file's name was. With everything working perfectly, there is a brief interval where "File" does not exist - that happens between the 2 renames. Any open() attempted during that very short interval will fail.

      At the lowest level (disk writing hardware), a disk write operation is not "atomic" and can fail this test: either successfully change the state of the system, or have no apparent effect. When writing a sector on the HD, the sequence: a) Old data, b)No data(the write is occuring), c)New data occurs. If something goes wrong during step (b), then we are left with unknown garbage. Even the very fast rename function goes through these 3 steps.

      Summary: Rename is the fastest and best function to use for replacing files. Get the new file completely ready in advance. Do not mess around with writing the new file line by line - that is too slow and opens up corruption issues.

        To replace an important file with a new version, first get the new file onto the system in its entirety. Now a quick two step dance happens. At a minimum, rename the existing file to something else

        That's not how you use rename() if you want it to be atomic, you just rename the new file over the old file. There is never a moment when the file doesn't exist. Second, you should read up on journaling filesystems, the chance for corruption is much lower and in many cases the filesystems can indeed guarantee that there will be no corruption even in the case of sudden power loss.