Shell Problems passing strings containing a space to env

I am writing a rc script to start a node application. I am trying to use /usr/bin/env to set environment variables I have put in a file. The Problem I have is the variable that was loaded in the script is not being treated the same way as if I was using literals. if I call /usr/bin/env TEST="TEST TEST TEST" /usr/local/bin/zsh when I look call /usr/bin/env inside new zsh shell it will show the saved envronment variable as TEST=TEST TEST TEST. If the same TEST="TEST TEST TEST" line were read from a file and stored in a variable only TEST="TEST would be passed and the program would not be called. If I change the file to remove the spaces zsh would be called but the TEST variable would have the value "TESTTESTTEST" (including the quotes.) I seems like I am missing something basic here but how can I have the sh varable pass a string to env as if it were typed?
 
Inside a script /usr/bin/env "TEST=TEST TEST TEST" /usr/local/bin/zsh -c env works for me (look at the position o fthe doublequotes).
export TEST="TEST TEST TEST" and then /usr/local/bin/zsh -c env works, too.
(-c env just used for testing)
 
I am trying to use /usr/bin/env to set environment variables I have put in a file.
Not sure exectly what you mean but I think what are trying to achieve is something like the following.

First, taking that you're trying to call from inside an rc script, that assumes you're running the standard sh(1) when you execute:
/usr/bin/env TEST="TEST TEST TEST" /usr/local/bin/zsh
or at least the equivalent you want. You haven't shown what exactly you have tried and how that failed. As an example, I'll take an ordinary sh script file test.sh to represent the relevant stuff.
Demonstration run:
Rich (BB code):
# ps -p $$
  PID TT  STAT    TIME COMMAND
93299  1  S    0:00.01 sh
# cat test.sh
#!/bin/sh
# testing environment value passing to zsh
T1='TEST TEST'
T2='bla blup'
/usr/bin/env E1="${T1}" E2="${T2}" C1="${T1}--${T2}" /usr/local/bin/zsh
# env | grep -E 'E1|E2|C1'
# ./test.sh
tm1# ps -p $$
  PID TT  STAT    TIME COMMAND
93305  1  S    0:00.02 /usr/local/bin/zsh
tm1# env | grep -E 'E1|E2|C1'
C1=TEST TEST--bla blup
E2=bla blup
E1=TEST TEST
tm1#
Before calling the zsh(1), you can see that when running sh(1) (line # ps -p $$ tells what shell you are currently running) the enviroment variables E1, E2 and C1 are not in the sh(1) environment. After invoking the zsh(1) the values for E1, E2 and C1 have been successfully passed and are part of the zsh(1) environment.

In the script line /usr/bin/env E1="${T1}" E2="${T2}" C1="${T1}-${T2}" /usr/local/bin/zsh, the use of "${<variable>}" is a good way to reference a variable in a script, it also enables the combination of variables and strings together. More information about that: Using curly braces with variables

Edit: the use of /usr/bin/env in the above script, follows the [name=value ...] convention of env(1).
 
strings in the environment are null terminated so the quotes are not saved. Your problem is in understanding when/how the var is expanded/decoded. you should always quote a var as

program "myvar$"

to preserve spaces, if there are any. and because the argument is quoted, it will be passed in its entirety as argv[1] to program, and as mentioned above, curley brace notation is good to differentiate a var name from pure text inside a string.
 
Sorry, I will provide more background to what I am trying to do. I was providing a simple example of what I was trying to do instead of making an overly complex post.

I am trying to make a port of a Node server application, the Joplin server backend, to go along with the desktop application. I have the server running, but it is a manual process to build and run it. It is Linux-centric, so it uses Docker and PM2 to build and run the server. PM2 passes environment variables to Node when the app runs. I thought I could have my RC script read a config file and load the environment variables. This worked great until I had entries in the config file that had spaces in them. I had made something simple that still showed the problem, but it lacked the context for anyone to understand what I was trying to accomplish. The -c env worked for the example but wouldn't work when I ran node or daemon(8) from inside my rc script (it did work in other test scripts I was playing with). I also tried using it
Code:
eval `echo /usr/bin/env ${parameters} /usr/loca/bin/zsh`
in various ways where parameters has a string with spaces in it. This passed in the variables as I expected in the sample script, but it still had the same issue as the parameters got passed down to rc.subr(8) in the real thing.

I'm looking at the Node application, and I think I can set these environment variables through a file it reads instead of mimicking how Docker starts the app.

This is my first real dive into making a port and fully integrating an application with the FreeBSD system. I've never written sh before and I am not a Node/TypeScript developer. but I do have have a good amount of C++ under my belt (that's why I am being too clever by half).. I thought I was missing something super obvious, but now I think I am going about the problem from the wrong angle.

Thank you for all the feedback and help!
 
This passed in the variables as I expected in the sample script, but it still had the same issue as the parameters got passed down to rc.subr(8) in the real thing.
If you (still) need to work with rc(8) & rc.subr(8), then you should know about Practical rc.d scripting in BSD; other links that might be useful:
 
As kent_dorfman766 already commented on #4, at which point the variable / quotations are decoded often affects.
And more, how many time the variable is decoded may affect, too.

In many cases, surrounding ${varname} with double quotes like "${varname}" helps when passed to something as parts of command line in case the variable varname contains white spaces.

But when the decodings are done in multiple places (steps), the quotations are stripped out BEFORE these are really needed to be stripped out, causing breakages. This could also apply to "\" escapes.

If single pair of double quotes (single quote avoids expanding the variable with ${varname} (string ${varname} would be passed) in /bin/sh scripts.
For example, if "${varname}" doesn't work, I would try "\"${varname}\"" first.
 
I tryied to use -S option of env command to embed double quoted strings with no success. Perhaps someone can explain the following excerpt from env manpage (second paragraph)
Code:
Details of -S (split-string) processing
     The  processing  of the -S option will split the given string into separate
     arguments based on any space or <tab> characters found in the string.  Each
     of those new arguments will then be treated as if it had been specified  as
     a separate argument on the original env command.

     Spaces and tabs may be embedded in one of those new arguments by using sin-
     gle ("'") or double (`"') quotes, or backslashes (`\').  Single quotes will
     escape  all  non-single  quote characters, up to the matching single quote.
     Double quotes will escape all non-double quote characters, up to the match-
     ing double quote.	It is an error if the end of the string is  reached  be-
     fore the matching quote character.
 
Ok, catch it. When I used it was in passing variables that contained arguments with spaces from one sh script to another, and another but variables was expanded many times so the double quetes was missed.
 
Back
Top