amphibient
amphibient

Reputation: 31278

Display file contents with evaluated variables

Let's say I have a template text file most of whose content is static but has some variables. E.g.

My favorite site is ${FAV_SITE}

Let's say that FAV_SITE is set to stackoverflow.com:

export FAV_SITE=stackoverflow.com

How do I print to STDOUT the contents of the file with the vars resolved, i.e.

My favorite site is stackoverflow.com

without using fancy tools like sed or awk?

Upvotes: 0

Views: 291

Answers (4)

amphibient
amphibient

Reputation: 31278

Using Perl:

#!/usr/bin/perl

use strict;

my $inFile = $ARGV[0];

print "\nInput File=".$inFile;

open(FILEHANDLE, "<$inFile") || die("Could not open file");

my @fileLines = <FILEHANDLE>;

my $rslt;

foreach my $line(@fileLines)
{
    #chomp($line);

    #print "\nLINE BEFORE=".$line;

    while($line =~ m/(\${\w+})/g)
    {
        if($1)
        {
            my $plchldr = $1;

            my $varName = $plchldr;

            $varName =~ s/(\$|{|})//g;

            my $varVal = $ENV{$varName};

            if($varVal)
            {
                $line =~ s/\Q$plchldr/$varVal/g;
            }
        }
    }

    $rslt .= $line;

    #print "\nLINE AFTER=".$line;
}

print "\nRESULT = ".$rslt;

close(FILEHANDLE);

print "\n";

exit(0);

Upvotes: 0

Jonathan Leffler
Jonathan Leffler

Reputation: 754540

This is an almost trivial bit of Perl that does the job.

#!/usr/bin/env perl
#
# Substitute environment variables into text

use strict;
use warnings;

while (<>)
{
    while (m/\${(\w+)}/g)
    {
        my $env = $1;
        if (defined $ENV{$env})
        {
            my $sub = $ENV{$env};
            s/\${$env}/$sub/g;
        }
    }
    print;
}

If the environment variable is not defined, it leaves the ${VARIABLE} notation unchanged.

For example, on the input data:

This is ${HOME} and so is this (${HOME}) and that's ${USER} and that's all.
This is ${UNDEFINED} and that is ${UNDEF} too.

the output might be:

This is /work4/jleffler and so is this (/work4/jleffler) and that's jleffler and that's all.
This is ${UNDEFINED} and that is ${UNDEF} too.

The Perl probably isn't as compact is it could be, but it is more or less comprehensible if you know that the read operator <> and the match, substitute and print operators work on the default variable, $_.


Using Perl 5.12.1 (home-built) on RHEL 5 Linux (don't ask), I used:

$ cat x3 
This is ${UNDEFINED} and that is ${UNDEF} too.
This is ${HOME} and so is this (${HOME}) and that's ${USER} and that's all.
$ perl subenv.pl x3
This is ${UNDEFINED} and that is ${UNDEF} too.
This is /work4/jleffler and so is this (/work4/jleffler) and that's jleffler and that's all.
$

Just be careful if you create the template with a here document; the shell will expand those variables too.

I also found Perl 5.8.8 in /usr/bin/perl on the RHEL machine and that produced the same output. I also checked Perl 5.16.0 on Mac OS X 10.7.5, with the corresponding result (different home directory). I also found a Perl 5.6.1 on a HP-UX 11.00 machine where ${USER} was not set in the environment, but it substituted ${HOME} correctly.

Upvotes: 2

William Pursell
William Pursell

Reputation: 212434

Always be wary of eval, but:

while read l; do eval echo "\"$l\""; done < input-file

Only use this if you control the input. For example, if the input contains a line like "; rm -rf /" it would be most unfortunate to run this script.

Upvotes: 0

sehe
sehe

Reputation: 393537

Can you make the template file a bash script?

#!/bin/bash
# This is a template, execute it to get interpolated text:
cat <<HERE
My favorite site is ${FAV_SITE}
HERE

Example of use:

export FAV_SITE=stackoverflow.com
bash ./template.txt.sh

(oh and you might need to visit reddit.com)

Upvotes: 1

Related Questions