The problem is that you're not quoting the $ENV
variable. As explained in man bash
:
Enclosing characters in double quotes preserves the literal value
of all characters within the quotes, with the exception of $, `,
\, and, when history expansion is enabled, !. The characters $
and ` retain their special meaning within double quotes. The
backslash retains its special meaning only when followed by one of
the following characters: $, `, ", \, or .
So, enclosing a sequence like \n
in double quotes preserves its meaning. This is why, when not quoted, \n
is just a normal n
:
$ printf \n
n$
While, when quoted:
$ printf "\n"
$
An unquoted variable in bash invokes the split+glob operator. This means that the variable is split on whitespace (or whatever the special variable $IFS
has been set to) and each resulting word is used as a glob (it will expand to match any matching file names). Your problem is with the "split" part of this.
To illustrate, let's take a simpler multiline variable:
$ var=$(printf "foo\nbar\n")
Now, using the shell's set -x
debug feature, you can see exactly what's going on:
$ echo $var
+ echo foo bar
foo bar
$ echo "$var"
+ echo 'foo
bar'
foo
bar
As you can see above, echo $var
(unquoted) subjects $var
to split+glob so it results in two separate strings, foo
and bar
. The newline was eaten by th split+glob. When the variable was quoted, it wasn't subjected to split+glob, the newline was kept and, because it is quoted, is also interpreted correctly ad printed out.
The next problem is that printf
is not like echo
. It doesn't just print anything you give it, it expects a format string. For example printf "color:%s" "green"
will print color:green
because the %s
will be replaced with green
.
It also ignores any input that can't fit into the format string it was given. So, if you run printf foo bar
, printf
will treat foo
as its format string and bar
as the variable it is supposed to format with it. Since there is no %s
or equivalent to be replaced by bar
, bar
is ignored and foo
alone is printed:
$ printf $var
+ printf foo bar
foo
That's what happened when you ran printf $ENV_BEFORE
. Because the variable wasn't quoted, the split glob effectively replaced newlines with spaces, and printf
only printed the first "word" it saw.
To do it correctly, use format strings, and always quote your variables:
printf '%s\n' "$ENV_BEFORE"
Should be possible with socat
.
Write such a script "getmsg.sh" to receive one message via stdin:
#!/bin/bash
read MESSAGE
echo "PID: $$"
echo "$MESSAGE"
Then run this socat
command to invoke our script for each tcp connection on port 7777:
socat -u tcp-l:7777,fork system:./getmsg.sh
Send a test message from another shell:
echo "message 1" | netcat localhost 7777
Best Answer
In
bash
you can use the syntaxSingle quotes preceded by a
$
is a new syntax that allows to insert escape sequences in strings.Also
printf
builtin allows to save the resulting output to a variableBoth solutions do not require a subshell.
If in the following you need to print the string, you should use double quotes, like in the following example:
because when you print the string without quotes, newline are converted to spaces.