4

I'm trying to use env to set environment variables (read from another source, say for example a file) for a subprocess. Essentially, I am attempting the following:

env VALUE=thisisatest ./somescript.sh

If, for example, somescript.sh was:

echo $VALUE

Then this would print thisisatest as expected. But I would like to load the variables from a file. I've gotten to this point:

env $(cat .vars | xargs -d '\n') ./somescript.sh

But, I run into trouble when any of the variables contain spaces (and quotes don't work as expected). So for example:

env $(echo 'VALUE="this is a test"' | xargs -d '\n') ./somescript.sh

Will error with

env: is: No such file or directory

And trying:

env $(echo 'VALUE="thisisatest"' | xargs -d '\n') ./somescript.sh

Will give me the unexpected:

"thisisatest"

I assumed this would work properly since running env VALUE="thisisatest" ./somescript.sh prints it without the quotes.

From the error, I glean that for some reason env is not understanding that the quotes mean that the value that follows should be a string. However, I'm unsure how to interpolate these vars in a way that the quotes are correctly interpreted.

Can anyone provide any hints for how I could accomplish this?

Thanks!

4

You need double quote in command substitution, otherwise, the shell will perform field splitting with the result of command substitution:

$ env "$(echo 'VALUE="this is a test"')" ./somescript.sh
"this is a test"

For env reading from file, you must let the shell does field spliting, but set IFS to newline only, so your command won't break with space:

$ IFS='
'
$ env $(cat .vars) ./somescript.sh

If you want to read from file, it's better if you just source (aka dot) the file in somescript.sh:

#!/bin/bash

. .vars
: The rest of script go here
  • Thanks! This fixes the space problem. However, it breaks with multiple variables (they all get passed in as one big argument instead of separate ones). For example: env "$(printf 'VALUE=test one\nVALUE2=test two\n' | xargs -d '\n')" printenv prints VALUE=test one VALUE2=test two instead of VALUE=test one and VALUE=test two on separate lines. Is there a way to fix this or am I using it incorrectly? – Bailey Parker Apr 17 '15 at 7:09
  • I've tried wrapping each arg in quotes env "$(printf 'VALUE=test one\nVALUE2=test two\n' | sed 's/.*/"&"/' | xargs -d '\n')" printenv, but this still fails. – Bailey Parker Apr 17 '15 at 7:14
3

This works:

env -S "`cat .vars`" command

First, in your file, you'll need to quote the variable value.

VALUE="This has spaces"

Then use the -S flag to parse the vars (which strips out the quotes).

env -S "`cat .vars`" command-refers-to-env-vars

You can't refer to $VALUE in the command, of course, because the command is evaluated by the shell prior to the action of env. To do that you'd need to use the following:

( . .vars ; echo $VALUE )

The parentheses open a subshell so that you don't pollute your shell with all the definitions in .vars. However, the variables are available only to the shell. They're not actually in the env, so processes wouldn't be able to access them with process.ENV.VALUE or getenv("VALUE") as with the env -S invocation.

You can combine both with

( . .vars ; env -S "`cat .vars`" command-refers-to-envs $VALUE )
0

I think you're over-complicating things.

$ env FOO='this is a test' printenv | egrep -i foo
FOO=this is a test

By the way quotes aren't part of this issue. Use double quotes if you want, e.g., variable substitution in your value; use single quotes if you want to prevent variable substitution, etc.

Heck, use command substitution if that suits your needs. Use formatted character strings. Use both.

$ env FOO=$'this\tis a test' printenv | egrep -i foo | cat -t
FOO=this^Iis a test
$ env FOO="$(echo $'this\tis a test')" printenv | egrep -i foo | cat -t
FOO=this^Iis a test

Oops, this may be a better example of using command substitution. The idea is to put the output of some required command into the variable, not just gratuitously use command substitution where none is necessary.

$ env FOO="$(man man)" printenv | egrep -iA5 foo=
FOO=man(1)                                    man(1)



NAME
   man - format and display the on-line manual pages

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.