3

I have a shell script that I currently use for some build related stuff for a mobile application.

Due to the the subtle differences between BSD & GNU one of build scripts originally written on a Mac (BSD)

environment=$1

if [[ -z $environment ]]; then 
  environment="beta"
fi
if ! [[ $environment =~ (live|beta) ]]; then
  echo "Invalid environment: $environment"
  exit 1
fi

mobile_app_api_url="https://api"$environment".mysite.com"

cp app/index.html.mob MobileApp/www/index.html

sed -i'' "s#MOBILE_APP_API_URL#\"$mobile_app_api_url\"#g" MobileApp/www/index.html

The sed command has been written on BSD (Mac) but as builds may take place on both Mac or Ubuntu (GNU) I need to modify this to work with on both flavours, what is the best approach for this?

Kusalananda
  • 333,661
Zabs
  • 137

3 Answers3

2

Do this to circumvent the problematic portability issues with the -i flag of sed:

sed 'sed-editing-commands' thefile >tmpfile && mv tmpfile thefile

I.e., write to a temporary file, and then replace the input file with the temporary file if the sed command didn't fail.

This is portable to all implementations of sed that I know of.

To create a temporary filename safely, use mktemp. Although this isn't a standard utility, it is available on all Unices that I have access to (OpenBSD, NetBSD, Solaris, macOS, Linux):

tmpfile=$(mktemp)
sed 'sed-editing-commands' thefile >"$tmpfile" && mv "$tmpfile" thefile
Kusalananda
  • 333,661
0

You need to realize that the $mobile_app_api_url should not contain the chars that are meaningful to sed on the RHS of s///. Specifically, speaking, you need to make sure that this variable has the following properly escaped away: viz., & # \ newline before they are plugged in.

  • It looks as if that is already taken care of. The URL will not cause problems. The issue is with the non-portable -i flag for sed (it work very differently with different implementations of sed). – Kusalananda Mar 03 '17 at 14:44
  • From the OP's code shown there is nowhere any escaping the characters that I have mentioned above in my post. Just try placing an & in $1 to see what I mean. –  Mar 03 '17 at 14:50
  • 1
    The URL in $mobile_app_api_url will be either https://apibeta.mysite.com or https://apilive.mysite.com, no other values will be allowed. The escaping of characters in the substitution is furthermore an issue in all implementations of sed on all Unices. This question is about portability. – Kusalananda Mar 03 '17 at 14:55
  • 1
    @Kusalananda, any value of $environment that contains either live or beta would be allowed (though it doesn't look like it was the intention). – Stéphane Chazelas Mar 03 '17 at 15:53
  • @StéphaneChazelas Right you are. Any URL with & # \ newline in the domain part would be a bit broken anyway though. – Kusalananda Mar 03 '17 at 15:56
0

Instead of:

cp app/index.html.mob MobileApp/www/index.html
sed -i'' "s#MOBILE_APP_API_URL#\"$mobile_app_api_url\"#g" MobileApp/www/index.html

Just do:

sed "s#MOBILE_APP_API_URL#\"$mobile_app_api_url\"#g" \
  < app/index.html.mob >  MobileApp/www/index.html

You can also remove your dependency on ksh93/bash by changing the top part to:

environment=$1

case $environment in
  "") environment=beta;;
  live|beta) ;;
  *)
    printf >&2 'Invalid environment: "%s"\n' "$environment"
    exit 1;;
esac

See also environment=${1:-beta}.

BTW, [[ $environment =~ (live|beta) ]] in ksh93 and bash tests whether $environment contains live or beta which doesn't sound like what you want. You'd need [[ $environment =~ ^(live|beta)$ ]] to test whether it is live or beta.