Steve McLeod
Steve McLeod

Reputation: 52458

Replacing single line of text with multiple lines of HTML using Perl

I'm using the following in a bash script to replace a string with the contents of a file:

readonly changes=`cat changes.txt`
perl -pi -e 's/\${changesMarker}/'"$changes"'/g' changelog_template.html

The file "changes.txt" contains a few lines of HTML. Nothing extraordinary, just an unordered list, including the <UL> open and closing tags and the <LI> tags.

Perl keeps telling me:

Illegal division by zero at -e line 1, <> line 1.

I guess Perl is trying to evaluate the replace text? How do I fix this?

The file changelog_template.html is something like this:

<html>
<body>
    What's changed:
    ${changesMarker}
</body>
</html>

The file changes.txt is something like this:

<ul>
<li>Fixed unicode error</li>
</ul>

Upvotes: 0

Views: 452

Answers (2)

ikegami
ikegami

Reputation: 385917

You converted the string into a shell literal, but you failed to convert it into Perl code first.

For example, If the content of $changes was <b>foo</b>, you end passing the following program to Perl:

s/\${changesMarker}/<b>foo</b>/g
                           ^
                           |
               Ends the substitution operator

My recommendation is to avoid generating Perl code. Either pass the string as an argument

perl -i -pe'
   BEGIN { $replacement = shift(@ARGV) }
   s/\${changesMarker}/$replacement/g
' "$change" changelog_template.html

Or as an environment variable.

REPLACEMENT="$changes" \
   perl -i -pe's/\${changesMarker}/$ENV{REPLACEMENT}/g' \
      changelog_template.html

Upvotes: 2

TLP
TLP

Reputation: 67918

With that exact text this might be solved using your solution. However, I would not recommend using it if your text changes. Assuming the single quotes prevents shell interpolation, you can get away with doing this:

readonly changes=`cat changes.txt`
perl -pi -e 's/\${changesMarker}/$ENV{changes}/g' changelog_template.html

Technically, you can replace this with:

perl -0777 -pie 'BEGIN { local @ARGV = shift; $changes = <>; }
           s/\${changesMarker}/$changes/g;' changes.txt changelog_template.html

Which will slurp the file, which is better since it allows multiline matches (theoretically).

This is a simple enough Perl script:

use strict;
use warnings;

undef $/;
open my $in, "<", shift or die "Cannot open input file: $!";
my $changes = <$in>;

while (<>) {
    s/\${changesMarker}/$changes/g;
    print;
}

Used like this:

perl -pi script.pl changes.txt changelog_template.html

Upvotes: 2

Related Questions