[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: Replace line in file based on pattern



On 1/2/22 8:46 PM, Greg Wooledge wrote:
I'm rearranging the order of the quoted sections.

On Sun, Jan 02, 2022 at 08:14:47PM -0500, The Wanderer wrote:
That's very interesting, although not all that accessible to the
relative newcomer to the field. It does leave me sad about the apparent
conclusion that there is no safe way to edit a file programmatically
(i.e., not via an interactive editor, and possibly not at all) in a way
which preserves the inode; the reasons why I thought of that as
desirable seem less clearly so on further analysis, but it's still
unfortunate for a thing to not be possible to do.

There are several things going on here.  I'll address two of them.

First: in order to "preserve the inode", you would need to open the
file in either read+write mode, or clobber+write mode, and then start
overwriting the file once you have the content in memory.  This is
inherently dangerous, because if the writing is interrupted before
completion, the file is now corrupted (in the read+write case), or
truncated (in the clobber+write case).

The writing can be interrupted if the process is terminated, or if the
system crashes.  Even with uninterruptible power supplies, there's no
100% sure way to prevent a system crash, so there is always a risk.

Second: the idea that a program should be altering (overwriting) the
contents of configuration files *at all* is sketchy.  It's a really
bad design.  The types of files that people usually want to alter with
sed are designed to be edited by humans.  They are *not* amenable to
programmatic alteration, which is why the answers that people come up
with are so contorted.

Altering a config file programmatically is exactly what ansible does, and the functionality desired in the original post is one of the things ansible has a module for.

I have no idea how ansible handles interruptions.


If you really need to alter a textual configuration file on a bunch of
servers, I suggest editing the file by hand on one machine, making a
diff out of that, and then using patch to apply that diff on all the
other machines.  Or use ansible, chef, puppet, etc.  This is not a new
or unique problem.  Stop reinventing wheels.

I'm not interested in hacking a bunch of servers. Just one. The whole purpose here is to restore a system to more or less its original configuration when a reinstall must occur. A reinstall must occur when there is a severe hardware failure, or when Debian (or any other operating system) comes up with a major revision (in Debian's case, every couple of years). The problem I've seen with just copying an old config file over the top of the one installed by default is that in some cases, syntax changes or options are added or deleted in the config files from one version to another. Thus, my idea of "surgical" alteration of the config files.

Ansible supposedly will do this, but in certain circumstances, I've been unable to make it work on a remote machine. I can't say why. However, it occurred to me that ssh, rsync and bash/basic tools can accomplish the same goals.

You mentioned diff and patch earlier, and these might well be good tools. The problem is that I'm relatively unfamiliar with patch and diff. I know how they work, but I'm inexpert in their use.


A much better approach is what people have started doing with ".d"
directories.  Instead of a single monolithic text configuration file
that requires a human brain to comprehend, you put individual pieces
of configuration in separate files.  If you want to change the phlogiston
level, you just put the new value in the foobar.d/phlogiston file.  No
need for a parser to find the phlogiston variable in a text file.

I absolutely abhor the *.d solution. Most software that I'm aware of is built to read a single config file. For example, exim. Personally, I find it vastly easier to load a single config file in an editor and search for a value, than to grep through a bunch of files and load the one which has the value I seek. My personal preference.



Of course, the program being configured has to be written to support
such a thing.

unicorn:~$ printf %s\\n foo foo foo | awk '!done && /foo/{$0="bar"; done=1} 1'
bar
foo
foo

I keep forgetting that printf is even a thing in shell, and while awk
did occur to my mind, I don't know it well enough to do anything useful
in it. I can only kind-of parse the syntax you gave there, and that only
because I just saw very similar-looking syntax given for sed in the
Stack Overflow answer linked above.

An awk program consists of a series of alternating conditions and actions.
Each line of input is matched against the conditions, in order.  If any
of the conditions matches the input line, then the corresponding action
block is executed.

Awk is another tool I'm only vaguely familiar with. I'm much more familiar with sed and grep. If I had your expertise, I might look at it differently.

Paul


Reply to: