4

I'm making this test script to help me reverse engineer scripts in charge of setting the dev environment.

The script:

#env-changes
#!/bin/bash
TESTED_SCRIPT=$1
shift
ENV_BEFORE=$(env | sort)
. $TESTED_SCRIPT
ENV_AFTER=$(env | sort)
diff <(printf '%s\n' "$ENV_BEFORE") <(printf '%s\n' "$ENV_AFTER")

Dummy env script:

#!/bin/bash
export I_AM_NEW=hello

Usage:

$ ./env-changes dummy-env-script.sh 
21a22
> I_AM_NEW=hello

Currently it only works with bash. Suggestions on how to make it more POSIX compilant?

migrated from codereview.stackexchange.com Mar 14 '16 at 13:35

This question came from our site for peer programmer code reviews.

  • 3
    Why does it need to be more POSIX? Are you targetting a platform that does not have bash? Don't waste your time if this is not a real requirement for you. – glenn jackman Mar 14 '16 at 13:38
  • @glennjackman I had a general feeling that that is what one should always aim for :) . It isn't a real requirement so far. – TheMeaningfulEngineer Mar 14 '16 at 13:46
  • 1
    BTW, the #! line should be the FIRST line of the script. If your first line is #env-changes as you've posted it, it is only being run by bash because /bin/sh is the default interpreter and /bin/sh is bash on your system. It's not uncommon even on linux systems for /bin/sh to be dash or ash or some other minimalist posix sh (partly because they're much smaller and often faster than bash, and because some people see the huge size of bash as a potential security risk due to the larger "attack surface" of large programs vs small programs). – cas Mar 15 '16 at 2:07
5

First of all, the POSIX source command will only source files from directories in the PATH. To get around that, you will need to use a full path:

sh ./env-changes ./dummy-env-script.sh

Also, the portable version of source is .:

. "$1"

Then, the <() construct is not POSIX, so you'll need to work around that. For example, you can use temp files:

tmp1=$(mktemp)
tmp2=$(mktemp)
env | sort > "$tmp1"
. "$1"
env | sort > "$tmp2"
diff "$tmp1" "$tmp2"
rm  "$tmp1" "$tmp2"

Or, a different approach:

ENV_BEFORE=$(env)
. "$1"
ENV_AFTER=$(env)
printf -- '%s\n%s\n' "$ENV_BEFORE" "$ENV_AFTER" | sort | uniq -u

Here, we print both variables, sort them, pass them through uniq -u which will only print unique lines, printing only the new variable:

$ sh ./env-changes ./dummy-env-script.sh 
I_AM_NEW=hello

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.