The env command, when executed takes a number of arguments --just like any command-- from the execve() system call. The process executing it will do something like:
execve("/path/to/env", ["env", "-options", "var=value", "cmd", "arg"], environ);
And env, in turn, will do (generally in the same process):
execve("/path/to/cmd", ["cmd", "arg"], modified_environ);
where modified_environ is environ but with var=value appended to it, or if there was already one or more string starting with var= in environ, the first of them (at least) replaced with var=value.
Those arguments are NUL-terminated arrays of bytes, so the only bytes they can't contain is the NUL byte. Same applies to environment variables whose neither name nor value can contain NUL bytes.
env, upon startup, processes its arguments from first to last.
The ones at the start that start with - would be taken as options.
- alone is also treated as the ancient form of -i to ignore environ.
The ones following options (or -- that can be used to mark the end of options) that contain at least one = will be considered as env var strings (to put in modified_environ above). The first non-option argument that doesn't contain a = character is considered as the command name (which will be passed as first argument to the command and also used to look-up the path of the executable in $PATH).
Any argument after that will be passed as arguments to the command even if they start with - or contain = characters.
So for env itself, only the - and = characters are special; - only during option processing, and = only until the command name is found.
To be able to pass an environment variable name that starts with - or a command name that starts with -, you can just use --:
execve("/usr/bin/env", ["env", "--", "-var-=value", "cmd"], environ);
execve("/usr/bin/env", ["env", "--", "-cmd-"], environ);
With several env implementations, - alone following -- would still not be taken as a command name. So if you wanted to call the command called -, you'd need to pass at least one environment variable beforehand:
execve("/usr/bin/env", ["env", "--", "dummy=", "-", "args"], environ);
(or use /path/to/- or ./- instead of - and bypath $PATH look up of that - command).
env however doesn't let you run a command whose name contains = characters and can't pass a string without = characters in the modified_environ. There is no way to escape the = character in those cases.
But in your case of env FOO=LITERAL_STRING, there is no character in LITERAL_STRING other than the NUL byte that would be a problem as far as env itself is concerned.
Now, when writing code in some language to execute that env command, there will likely be characters in that language that can't be entered literally.
For instance, in perl, you'd do:
exec "env", "--", "-text-=hello\nworld\n", "printenv", "--", "-text-";
With the newline character expressed as \n inside double quotes, though you could also do:
exec qw(env --), q(-text-=hello world ), qw(printenv -- -text-);
To pass strings that contain newline characters.
In the syntax of Bourne-like shell languages, the newline character is not special when inside single or double quotes (like for the q(...) or qq(...) quoting operators of perl), so you could do:
exec env -- "-text-=hello world " printenv -- -text
It would be a different matter in the C shell, or in the rc shell where "..." is not a quoting operator.
Your env FOO=LITERAL_STRING ruby -e 'puts ENV["FOO"]' looks like code in a shell language. That syntax would be valid with most shells as virtually all understand space as word delimiters, and '...' as a quoting operator.
When you omit the exec at the start, shells run the command in a child process, and then wait for that process to terminate or be suspended.
If that env FOO=LITERAL_STRING ruby -e 'puts ENV["FOO"]' is for a language that doesn't allow entering newline characters literally (likely not a shell) nor using some form of encoding (\n, %0a, ...), but apparently supports '...' as a quoting operator like most shells do, beside the BSD env -S trick already suggested by @UncleBilly, you can invoke an interpreter or a language that can execute commands and allows specifying newline some encoded way, such as perl, ruby, python, ksh93, zsh, bash...
Since you already have ruby:
ruby -e 'exec "env", "FOO=a\n\n\nb", *ARGV' -- ruby -e 'puts ENV["FOO"]'
But any descent programming language including ruby can set environment variables by themselves, so you don't need env:
ruby -e 'ENV["FOO"]="a\n\n\nb"; exec *ARGV' -- ruby -e 'puts ENV["FOO"]'
export FOO="hello\nworld"works any differently thanenv BAR="hello\nworld"?export FOO="hello\nworld"shouldn't insert a literal newline.env FOO="hello\nworld"to add a newline? That isn't how it works. Bothenv FOO="hello\nworld" ruby -e 'puts ENV["FOO"]'andexport FOO="hello\nworld"; ruby -e 'puts ENV["FOO"]'will printhello\nworldand not an actual newline. That is the expected behavior.