1

My bash script uses a perl command to replace a variable within a file, with the contents of another file. Pretty standard I thought, yet I am really struggling here.

#/bin/bash

display_usage() {
        echo -e "\nUsage: This script must be run with an environment parameter (file in directory env/)."
        echo -e "Example: ./configureEnv <env parameter>\n"
        }

# If no env argument supplied, display usage.
if [  $# -eq 0 ]; then
        display_usage
        exit 1
fi

# Replace the placeholder of FIREBASE_ENV in index.html with the Firebase env settings.
perl -pi -e 's/%FIREBASE_ENV%/`cat testEnvConfig`/g;' index.html

if [ $? -eq 0 ]; then
   echo "Updated Firebase settings based on environment file: $1"
   exit 0
else
    echo "[Error] Environment settings configuration failed. Please check parameters are correct."
    exit 1
fi

As you can see, the key line is:

perl -pi -e 's/%FIREBASE_ENV%/`cat testEnvConfig`/g;' index.html

It should replace the placeholder string of %FIREBASE_ENV% with the contents of the file, but instead it replaces replaces %FIREBASE_ENV% with `cat testEnvConfig`.

0

3 Answers 3

2

The replacement in a substitution interpolates variables like double quotes, but it doesn't interpret backticks. You need to specify the /e modifier to evaluate the replacement as code.

s/%FIREBASE_ENV%/`cat testEnvConfig`/ge

You don't need to shell out for this, though. Perl can read a file and store its contents in a variable:

my $config = do { local( @ARGV, $/ ) = 'testEnvConfig'; <> };
# ...
s/%FIREBASE_ENV%/$config/g;
Sign up to request clarification or add additional context in comments.

1 Comment

Never seen local @ARGV=filename before --- thanks for showing me!
1

With a (very useful) Perl module Path::Tiny reading a file takes one statement and we have

perl -MPath::Tiny -i.bak -pe'
    BEGIN { $f = path("testEnvConfig")->slurp; chomp $f }; 
    s/%FIREBASE_ENV%/$f/g
' index.html

I've added a backup .bak for your safety while testing, and split code over lines for readability.

I remove the final newline from the file. If you actually want it remove that chomp $f


Why your honest attempt doesn't work has been explained, as you need to evaluate the replacement part as code, with /e. However, once you do that, look at the situation:

  • out of a bash script call a Perl program (the one-liner)

  • which goes out to the system (a syscall at least, perhaps another shell!)

  • where yet another program runs (cat)

  • with the file content sent back to Perl, which then does its thing.

Huh. Better just read that file in Perl, no?

Comments

0

By default the right-hand side of a substitution (s///) works like a double-quoted string. "`cat whatever`" doesn't do anything special in a string; it doesn't run any commands.

You need to use the /e flag:

s/%FIREBASE_ENV%/`cat testEnvConfig`/eg

This tells Perl that the right-hand side is to be evaluated as a block of code, not a string.

Alternatively you can avoid shelling out to cat by reading the file in Perl:

perl -pi -e 'BEGIN { my $file = "testEnvConfig"; open my $fh, "<", $file or die "$file: $!\n"; local $/; $config = readline $fh } s/%FIREBASE_ENV%/$config/g'

This also avoids having to re-read the file for each occurrence of %FIREBASE_ENV%.

1 Comment

This was the perfect answer. I was not using the /e flag (only /g). I was getting confused between Perl and SED. thx

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.