Patching multiple files with same text

Larry Wall lwall at jpl-devvax.JPL.NASA.GOV
Thu Mar 29 11:02:08 AEST 1990


In article <193 at rdb1.UUCP> root at rdb1.UUCP (Robert Barrell) writes:
:      In a case where several files may have a given group of text lines, and
: that group of lines must be replaced in all files by another group of lines,
: is there any way to use patch, sed, or awk (sorry, I don't have perl) to perform
: such a patch?  The problems I am encountering are:
: 
: 1) The original text contains multiple lines, and ALL lines of the original must
:    be replaced by the patch.
: 2) The patch is not the same length as the original text.
: 3) The original text is not always in the same relative position within each
:    file, so "diff -e" scripts will only work for one file, due to the specific
:    line numbers, and context diffs have the same problem because of the actual
:    context (which may be different in all files).
: 4) Normal "diff" output, run through "patch" DOES work, but isn't specific
:    enough about matching the ENTIRE original text, so if a similar group of
:    lines appears in a file which doesn't contain the exact original, or if
:    such appears BEFORE the original, a false patch can occur.
: 
:      I see, in the manuals, that sed has an "N" command for, supposedly, dealing
: with multiple lines, but I haven't quite figured-out how to use it yet (all the
: examples in the manuals are for single lines, and the description of "N" is
: rather terse.

Just construct yourself a fake diff listing that has one hunk containing
all the lines, with no context.

1,3c1,8
< This are
< the old
< lines
---
> And these
> are the new
> lines--
> as many
> as you like,
> but make sure
> the line numbers
> are right.

Then use patch.  Depending on the lines, you may be able to generate them
with diff -c0.  Or maybe not, if there are common lines.

The shell script to iterate over all the files is left as an exercise.

Or GET perl, and say something like

#!/usr/bin/perl -i.bak

eval 'exec /usr/bin/perl -Si.bak $0 ${$1+"$@"}'
    if $running_under_some_shell;

$old = <<'EOF';
This are
the old
lines
EOF

$new = <<'EOF';
And these
are the new
lines--
as many
as you like,
and it
doesn't matter
how many lines you
put here
EOF

$old =~ s/(\W)/\\$1/g;		# protect any metacharacters.
undef $/;			# treat each file as one line
while (<>) {			# for each file
    s/$old/$new/;		# (add g to do multiple times in each file)
    print;
}

This will iterate over all the files you mention on the command line
and edit them in place.

Larry Wall
lwall at jpl-devvax.jpl.nasa.gov



More information about the Comp.unix.questions mailing list