简体   繁体   中英

Build a sed script from specific environment variables

I need to have a very basic template system in shell to port a windows installer to linux. So I can not change the syntax of the template variables.

I want to take specific environment variables (starting with $ENV_PREFIX) and build a sed script of the form s/@@@${TEMPLATE_VARIABLE}@@@/$VALUE_OF_ENVIRONMENT_VARIABLE/ .

$TEMPLATE_VARIABLE is the name of the environment variable with the $ENV_PREFIX stripped off.

#!/usr/bin/env sh   # no bashisms please!

TEMPLATE_FILE=$1
ENV_PREFIX="DMTMPL_"

SED_SCRIPT=""

OIFS="$IFS"
IFS=$'\012'
for VAR in "$(env | grep "^${ENV_PREFIX}")"
do
  VARIABLE=$(echo $VAR | cut -d= -f1 | cut -d_ -f2-)
  SED_SCRIPT="${SED_SCRIPT}\ns/${VARIABLE}/${???}/g"
done

echo ${SED_SCRIPT}
# invoke sed with $SED_SCRIPT on $TEMPLATE_FILE

Now I have all kinds of problems with this script:

  • I tried to do env --null , but could not combine this with the following grep.
  • The for loop does not exactly handle one environment variable in every loop
  • I did not manage to have $SED_SCRIPT nicely separated with newlines
  • How do I access the value of a variable when the variable name is stored in another variable? That's what I need to put where the ??? are in the script.

I thought I'd write a quick shell script for this but now I remember why I hate shell scripting... :-(

These Questions seem to answer part of my question:

The script is much simpler if you just write the sed commands to a temporary file, rather than trying to put them in a single string (especially if any of the environment variables used for substitution contain spaces in their values).

#!/usr/bin/env sh

TEMPLATE_FILE=$1
ENV_PREFIX="DMTMPL_"

env | grep "^$ENV_PREFIX" | while IFS="=" read -r name value; do
        printf "s/%s/%s/\n" "${name#$ENV_PREFIX}" "$value"
      done > sed-script.txt

cat sed-script.txt   # Optional
sed -f sed-script.txt "$TEMPLATE_FILE"
rm sed-script.txt

1. Major Problem

Don't screw around with IFS. changing IFS is going to render the REST of your script useless, because now instead of using a space you have to use \\012 to separate keywords;

Your problem is quite simple to solve and can be done using pure Bourne shell code:

#!/usr/bin/env sh   # no bashisms please!
TEMPLATE_FILE=$1
ENV_PREFIX="DMTMPL_"
delim='/'
sedscript="myscript.$$.sed"
rm -f $sedscript
touch $sedscript

VARS=$(env | grep "^${ENV_PREFIX}" | sed -e 's%^${ENV_PREFIX}%%')
for v in ${VARS}; do 
     eval value='${'$v'}'
     echo s${delim}@@@${v}@@@${delim}${value}${delim}g >> $sedscript
done
cat $sedscript

# sed -f $sedscript $TEMPLATE_FILE 

This script will create a sed script that should run against the template file as you see fit.

That's my current (working) solution:

#!/usr/bin/env sh

set -e

TEMPLATE=$1

if [ -z "${TEMPLATE}" -o ! -f ${TEMPLATE} ]
then
  echo "Did not find template file: ${TEMPLATE}"
  exit 1
fi

ENV_PREFIX="DMTMPL_"

TEMPLATE_PREFIX="PLACEHOLDER_"

SED_SCRIPT=""

OIFS=$IFS
# see https://bugs.launchpad.net/ubuntu/+source/dash/+bug/285651
IFS='
'

for VAR in `env | grep ^${ENV_PREFIX}`
do
  VARIABLE=$(echo $VAR | cut -d= -f1 )
  TEMPLATE_VARIABLE=$(echo $VARIABLE | cut -d_ -f2- )
  VALUE=$(eval "echo \$$VARIABLE")
  SED_SCRIPT="${SED_SCRIPT} --expression=\"s|${TEMPLATE_PREFIX}${TEMPLATE_VARIABLE}|${VALUE}|g\""
done

eval "sed --in-place=.sed.orig --posix ${SED_SCRIPT} ${TEMPLATE}"

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM