3

Let's say I have a file (called e) with this content:

a=3
b="5 6"

How can I get each one to be interpreted as a separate argument to env? That is, to have it equivalent to:

$ env a=3 b="5 6" ruby -e 'p ENV["a"]; p ENV["b"]'
"3"
"5 6"
$ env a=3 "b=5 6" ruby -e 'p ENV["a"]; p ENV["b"]'
"3"
"5 6"

This one obviously doesn't work because of the space:

env $(cat e) ruby -e 'p ENV["a"]; p ENV["b"]'

But neither does this one:

IFS=$'\n' env $(cat e) ruby -e 'p ENV["a"]; p ENV["b"]'

And quoting $(cat e) will result in:

"1\nb=2 3"
nil
2

This is an example of not using the right tool for the job. env isn't the only tool that sets environment variables and then chain loads another program. And it doesn't read variable data from file.

Of course, the . a.k.a. source command is not the right tool for this job, either.

  1. It permits the file to unexpectedly contain shell commands other than simple variable assignments, which in certain circumstances (depending from what the configuration file is) can be a massive security hole.
  2. A series of assignments as in the example in the question, sourced by ., sets shell variables, not environment variables. They aren't automatically exported.

The right tools are ordinary chain-loading tools from several toolsets of such tools.

One such is read-conf from the nosh toolset, designed to read exactly this kind of configuration file (such as /etc/rc.conf from — say — PC-BSD) and set environment variables without implementing and opening up configuration data files to an entire shell language syntax:

jdebp % uname
Linux
jdebp % cat e
a=3
b="5 6"
jdebp % read-conf e printenv | tail -n 3
USER=jdebp
a=3
b=5 6
jdebp %
jdebp % uname
FreeBSD
jdebp % read-conf /etc/rc.conf printenv | head -n 2
cron_enable=NO
sendmail_msp_queue_enable=NO
jdebp %

Another such tool is Wayne Marshall's runenv from perp.

  • Thanks. But I wonder why it's so difficult to take a file and have each line of it be an argument in bash. – Artefacto Jun 7 '16 at 13:04
2

You don't even need env here. In any Bourne-like shell (assuming the file is in sh syntax like in your example):

(set -a; . ./e && ruby -e 'p ENV["a"]; p ENV["b"]')

(set -a causes all future variable assignments to be exported to the environment).

You could also do:

cat e - << 'EOF' | paste -sd ' ' - | sh
ruby -e 'p ENV["a"]; p ENV["b"]'
EOF

That is join all the lines in the e file and that ruby command line to build a long command line for sh to interpret (still assuming that e file is in sh syntax as those double quotes suggest). That assumes the assignments are single line.

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.