append newline to variable in loop

append newline to variable in loop

am 03.10.2007 11:38:37 von mark

Hi all

I want to build a message buffer with newline but can't get it
working. I've tried various types of here document, blank lines, echo
and printf without success.

I'm using /bin/sh with basic posix features for portability. I want
something like (simplified for post):

var=
for i in 1 2 3
do
var=$var\nline $i
done
echo $var

Expected output:
line 1
line 2
line 3

Can anyone help?

Thanks.

Re: append newline to variable in loop

am 03.10.2007 12:11:53 von Cyrus Kriticos

Mark wrote:
>
> I want to build a message buffer with newline but can't get it
> working. I've tried various types of here document, blank lines, echo
> and printf without success.
>
> I'm using /bin/sh with basic posix features for portability. I want
> something like (simplified for post):
>
> var=
> for i in 1 2 3
> do
> var=$var\nline $i
> done
> echo $var
>
> Expected output:
> line 1
> line 2
> line 3

$ for i in 1 2 3; do var="${var}\nline $i"; done
$ echo $var

line 1
line 2
line 3

--
Best regards | "The only way to really learn scripting is to write
Cyrus | scripts." -- Advanced Bash-Scripting Guide

Re: append newline to variable in loop

am 03.10.2007 12:30:37 von mark

> $ for i in 1 2 3; do var="${var}\nline $i"; done
> $ echo $var

That's what I thought but it dosen't work for me, here's a complete
test script:

#!/bin/sh -

mbuf=

# Do some things.
# ...

for i in 1 2 3
do
mbuf="${mbuf}\nline $i"
done

# Do more things
# ...

echo $mbuf

Output:
\nline 1\nline 2\nline 3

Any ideas?

Re: append newline to variable in loop

am 03.10.2007 13:32:59 von Janis Papanagnou

Mark wrote:
>>$ for i in 1 2 3; do var="${var}\nline $i"; done
>>$ echo $var
>
>
> That's what I thought but it dosen't work for me, here's a complete
> test script:
>
> #!/bin/sh -
>
> mbuf=
>
> # Do some things.
> # ...
>
> for i in 1 2 3
> do
> mbuf="${mbuf}\nline $i"
> done
>
> # Do more things
> # ...
>
> echo $mbuf
>
> Output:
> \nline 1\nline 2\nline 3
>
> Any ideas?
>

I suppose /bin/sh rules out using $'\n', so see whether the following
is sufficient for you...

for i in 1 2 3
do
var="$var
line $i"
done
echo "$var"


Janis

Re: append newline to variable in loop

am 03.10.2007 14:07:08 von mark

> I suppose /bin/sh rules out using $'\n', so see whether the following
> is sufficient for you...
>
> for i in 1 2 3
> do
> var="$var
> line $i"
> done
> echo "$var"
>
> Janis

Thanks but already tried that without success. I also tried a heredoc
to assign to a variable using blank lines, echo and printf; all
without joy :(

Re: append newline to variable in loop

am 03.10.2007 14:19:59 von Ed Morton

Mark wrote:

>>I suppose /bin/sh rules out using $'\n', so see whether the following
>>is sufficient for you...
>>
>> for i in 1 2 3
>> do
>> var="$var
>> line $i"
>> done
>> echo "$var"
>>
>>Janis
>
>
> Thanks but already tried that without success. I also tried a heredoc
> to assign to a variable using blank lines, echo and printf; all
> without joy :(

Given what you posted so far:

> var=
> for i in 1 2 3
> do
> var=$var\nline $i
> done
> echo $var

> for i in 1 2 3
> do
> mbuf="${mbuf}\nline $i"
> done
>
> # Do more things
> # ...
>
> echo $mbuf


it seems more likely that you aren't quoting your variable when you do
the echo or printf than that nothing is working in your shell.

echo "$mbuf" NOT echo $mbuf

Regards,

Ed.

Re: append newline to variable in loop

am 03.10.2007 15:25:47 von mark

Thanks all

Here's a more realistic (but still simplified) example:

#!/bin/sh -

mbuf=
var=42
bld_msg () {
if [ "X$mbuf" = "X" ] ; then
# First message.
mbuf="$@"
else
mbuf="${mbuf}
$@"
# How can we indent the line above while preserving message?
fi
}

bld_msg "Create message A"
# Do some stuff ...
bld_msg "Then message B" and more text
# Do some stuff ...
bld_msg And now message C \$var=$var
# Do some stuff ...

echo "$mbuf"

Output:

Create message A
Then message B and more text
And now message C $var=42

This seems to work for me now, anyone know how to indent the $@ line
in the script WITHOUT affecting the message (all indents in the script
are spaces, ie tabs are converted to spaces).

Thanks.

Mark.

Re: append newline to variable in loop

am 03.10.2007 16:41:33 von Bill Marcum

On 2007-10-03, Mark wrote:
> Thanks all
>
> Here's a more realistic (but still simplified) example:
>
> #!/bin/sh -
>
> mbuf=
> var=42
> bld_msg () {
> if [ "X$mbuf" = "X" ] ; then
> # First message.
> mbuf="$@"
> else
> mbuf="${mbuf}
> $@"
> # How can we indent the line above while preserving message?
> fi
> }
>
mbuf=$(printf "%s\n%s" "$mbuf" "$@")

Re: append newline to variable in loop

am 03.10.2007 16:48:39 von Glenn Jackman

At 2007-10-03 06:30AM, "Mark" wrote:
> > $ for i in 1 2 3; do var="${var}\nline $i"; done
> > $ echo $var
[...]
>
> echo $mbuf
>
> Output:
> \nline 1\nline 2\nline 3
>
> Any ideas?

1. echo -e "$mbuf"
2. printf "$mbuf"


--
Glenn Jackman
"You can only be young once. But you can always be immature." -- Dave Barry

Re: append newline to variable in loop

am 03.10.2007 16:52:38 von Stephane CHAZELAS

2007-10-3, 14:48(+00), Glenn Jackman:
> At 2007-10-03 06:30AM, "Mark" wrote:
>> > $ for i in 1 2 3; do var="${var}\nline $i"; done
>> > $ echo $var
> [...]
>>
>> echo $mbuf
>>
>> Output:
>> \nline 1\nline 2\nline 3
>>
>> Any ideas?
>
> 1. echo -e "$mbuf"
> 2. printf "$mbuf"

printf %b "$mbuf"

First argument of printf is a format string.

Note that "echo -e" is not standard, both POSIX and Unix even
require it to output "-e" (that's a known
non-conformance of GNU versions of echo).

--
Stéphane

Re: append newline to variable in loop

am 03.10.2007 17:02:19 von Stephane CHAZELAS

2007-10-03, 06:25(-07), Mark:
> Thanks all
>
> Here's a more realistic (but still simplified) example:
>
> #!/bin/sh -
>
> mbuf=
> var=42
> bld_msg () {
> if [ "X$mbuf" = "X" ] ; then
> # First message.
> mbuf="$@"
> else
> mbuf="${mbuf}
> $@"
> # How can we indent the line above while preserving message?
> fi
> }
[...]

NL='
'
....
mbuf="$mbuf$NL$*"

Note that "$*" expands to the concatenation of the positional
arguments with the first character of IFS. For $@ inside
assignments, it depends on the shell you use. POSIX is not clear
on what a shell should do in that case.

--
Stéphane

Re: append newline to variable in loop

am 04.10.2007 09:19:29 von mark

Thanks to everyone for the suggestions.

St=E9phane, I tried the NL technique without success.

Everything works as expected now (see earlier post), my only gripe is
the formatting...

...
else
mbuf=3D"${mbuf}
$@"
fi

I would like to indent the $@" line without affecting the text.

Thanks again all.

Mark.

Re: append newline to variable in loop

am 04.10.2007 09:47:56 von Stephane CHAZELAS

2007-10-04, 00:19(-07), Mark:
> Thanks to everyone for the suggestions.
>
> Stéphane, I tried the NL technique without success.
>
> Everything works as expected now (see earlier post), my only gripe is
> the formatting...
>
> ...
> else
> mbuf="${mbuf}
> $@"
> fi
>
> I would like to indent the $@" line without affecting the text.
[...]

NL='
'

(that's NL='')

stores the LF/NL character in $NL. You may put that at the
beginning of your script.

else
mbuf="$mbuf$NL$@"
fi

would then do what you want. But again using "$@" in an
assignment is not portable especially if you've modifed $IFS.
So I would recommand using "$*" instead.

--
Stéphane

Re: append newline to variable in loop

am 04.10.2007 10:50:03 von mark

My scripting is a bit rusty (not done anything serious for many
years).

I'm re-learning from O'Reilly Classic Shell Scripting (Robbins &
Beebe), this has good write ups and covers secure, portable scripts.

I still don't get the correct result if I try the changes you suggest?

The other issue (in the real script, not the example I posted) is that
IFS is set to newline, space and tab; this is for security so I can't
use $*.

One thing I don't recall knowing about is $@ being unportable, do you
have any details on how/why?

Thanks again St=E9phane.

Re: append newline to variable in loop

am 04.10.2007 11:05:20 von Stephane CHAZELAS

2007-10-04, 01:50(-07), Mark:
> My scripting is a bit rusty (not done anything serious for many
> years).
>
> I'm re-learning from O'Reilly Classic Shell Scripting (Robbins &
> Beebe), this has good write ups and covers secure, portable scripts.
>
> I still don't get the correct result if I try the changes you suggest?

Then please post what you get when you run:

NL='
'
set a b
a=A
a="$a$NL$@"
echo "$a"

>
> The other issue (in the real script, not the example I posted) is that
> IFS is set to newline, space and tab; this is for security so I can't
> use $*.

How does that IFS setting help with /security/?

> One thing I don't recall knowing about is $@ being unportable, do you
> have any details on how/why?
[...]

Try:

set a b
IFS=:
a="$@"
echo "$a"

with a variety of POSIX shells. Most will output a:b (as they
should, to my mind: ash, dash, zsh, pdksh, mksh, posh), some
will output "a b" (bash, AT&T ksh).

The Bourne shell outputs "a b" which is correct given that
for the Bourne shell, $*, $@ are not the concatenation of
arguments with the first character of IFS in any context.

--
Stéphane

Re: append newline to variable in loop

am 04.10.2007 11:44:42 von mark

> Then please post what you get when you run:

Sorry, after more checking I found that I managed to insert a control
character into the test script which affected things. The example
with NL that you gave IS now working for me; sorry for the confusion -
I thought I was going mad :)

> How does that IFS setting help with /security/?

IFS should always be explicitly set by the script, this prevents
another program from setting it themselves and then calling the script
which will inherit IFS. If IFS is set to '/' for example and the
script uses something like /bin/some_cmd, it will expand to 'bin
some_cmd' (ie two commands), the hacker (technically cracker) could
have their own rougue program called bin or some_cmd that does
anything, combined with setuid it becomes a serious problem.

The other point is the default for IFS is space, tab, newline, if we
also change it to put the space between newline and tab it prevents
whitespace trimming tools.

Thanks again for your help St=E9phane

Mark.

Re: append newline to variable in loop

am 04.10.2007 13:04:26 von Stephane CHAZELAS

2007-10-04, 02:44(-07), Mark:
[...]
>> How does that IFS setting help with /security/?
>
> IFS should always be explicitly set by the script, this prevents
> another program from setting it themselves and then calling the script
> which will inherit IFS. If IFS is set to '/' for example and the
> script uses something like /bin/some_cmd, it will expand to 'bin
> some_cmd' (ie two commands), the hacker (technically cracker) could
> have their own rougue program called bin or some_cmd that does
> anything, combined with setuid it becomes a serious problem.
[...]

Even if this used to be true with early versions of the Bourne
shell, no shell nowadays will inherit $IFS from the environment.
Every shell nowadays initialise $IFS to either
"" (or "" for the
shells supporting the NUL character) or leave it unset which has
the same effect.

> The other point is the default for IFS is space, tab, newline, if we
> also change it to put the space between newline and tab it prevents
> whitespace trimming tools.

???

The order is only important (in POSIX shells) in that the first
character is used in computing the value of $* or $@. That's
all. Changing the order of the characters in $IFS has no effect
whatsoever on the behavior of "read" or word splitting performed
upon parameter or command substitution.

--
Stéphane

Re: append newline to variable in loop

am 07.10.2007 21:38:17 von mark

On Oct 4, 1:04 pm, Stephane CHAZELAS wrote:
> 2007-10-04, 02:44(-07), Mark:
> [...]>> How does that IFS setting help with /security/?
>
> > IFS should always be explicitly set by the script, this prevents
> > another program from setting it themselves and then calling the script
> > which will inherit IFS. If IFS is set to '/' for example and the
> > script uses something like /bin/some_cmd, it will expand to 'bin
> > some_cmd' (ie two commands), the hacker (technically cracker) could
> > have their own rougue program called bin or some_cmd that does
> > anything, combined with setuid it becomes a serious problem.
>
> [...]
>
> Even if this used to be true with early versions of the Bourne
> shell, no shell nowadays will inherit $IFS from the environment.
> Every shell nowadays initialise $IFS to either
> "" (or "" for the
> shells supporting the NUL character) or leave it unset which has
> the same effect.
>
> > The other point is the default for IFS is space, tab, newline, if we
> > also change it to put the space between newline and tab it prevents
> > whitespace trimming tools.
>
> ???
>
> The order is only important (in POSIX shells) in that the first
> character is used in computing the value of $* or $@. That's
> all. Changing the order of the characters in $IFS has no effect
> whatsoever on the behavior of "read" or word splitting performed
> upon parameter or command substitution.
>
> --
> St=E9phane

Re: append newline to variable in loop

am 07.10.2007 21:41:47 von mark

Hi St=E9phane

Couldn't reply sooner, got tied up at work.

Anyway, I definately remember issues with IFS, particularly with
setuid and also issues with whitespace but I can't remember the
details.

When (or if) If I look into it again I'll be happy to let you know
what if find (let me know if you're interested).

But for now thanks for the feedback.

Mark.

Re: append newline to variable in loop

am 04.11.2007 15:44:32 von Sven Mascheck

Stephane CHAZELAS wrote:

> Even if this used to be true with early versions of the Bourne
> shell, no shell nowadays will inherit $IFS from the environment.

Sun fixed this in their SunOS 5.7 variant of the SVR4 shell
(earlier variants might still run here and there).
On SCO OpenServer and DEC OSF1, IFS is still inherited (/bin/sh).
AFAIK current IRIX and UnixWare, too, but i couldn't try these yet.