From: Dominic Fandrey on
On 08/03/2010 16:17, Dominic Fandrey wrote:
> On 08/03/2010 14:55, Decare wrote:
>> The following two commands have different effect.
>>
>> $ echo A${IFS}B
>> A B
>>
>> $ echo "A${IFS}B"
>> A
>> B
>>
>> It is obvious that the first one interprets `IFS' as
>> space,
>
> IFS is appropriately interpreted, by the shell, however, \t
> and \n are control characters, so the shell removes them,
> because they are not protected by quotes.
>

Ignore that one, it's all wrong.

This is actually a word splitting issue as other posters have
pointed out.

--
A: Because it fouls the order in which people normally read text.
Q: Why is top-posting such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
From: Decare on
pk <pk(a)pk.invalid> writes:

> Decare wrote:
>
>> The following two commands have different effect.
>>
>> $ echo A${IFS}B
>> A B
>>
>> $ echo "A${IFS}B"
>> A
>> B
>>
>> It is obvious that the first one interprets `IFS' as
>> space, while the second interprets it as new line.
>> In fect, the `IFS' represents three characters, namely
>> space, tab, and new line. why different choices occur
>> in different situations?

>
> It's not like you think. There's no "interpretation" whatsoever, only normal
> shell operation. Run the output through "od -c":
>
> $ echo A${IFS}B | od -c
> 0000000 A B \n
> 0000004
> $ echo "A${IFS}B" | od -c
> 0000000 A \t \n B \n
> 0000006
>
> Hint: when using double quotes, word splitting does not happen.

The output of command od is just the result.
But, what is the meaning of `normal shell operation'?
What does cause shell expand the former to a space, the
latter to three characters?
Does word splitting matter? Any hints about it is appreciated.

--
ego cogito ergo sum
From: pk on
Decare wrote:

>> It's not like you think. There's no "interpretation" whatsoever, only
>> normal shell operation. Run the output through "od -c":
>>
>> $ echo A${IFS}B | od -c
>> 0000000 A B \n
>> 0000004
>> $ echo "A${IFS}B" | od -c
>> 0000000 A \t \n B \n
>> 0000006
>>
>> Hint: when using double quotes, word splitting does not happen.
>
> The output of command od is just the result.

That "result" shows what's really happening, and shows that in the second
case IFS is not "interpreted as newline", but is instead left untouched with
its original value, including space and tab.

> But, what is the meaning of `normal shell operation'?
> What does cause shell expand the former to a space, the
> latter to three characters?
> Does word splitting matter?

Exactly because of word splitting.

(simplified explanation, but appropriate for this case, follows)

After the value of the variabile has been replaced, *if the variable does
not appear between double quotes*, the shell performs word splitting, that
is, sequences of blanks (like space, tab and newline) are replaced with a
single space (they are actually replaced with the first character of $IFS,
which happens to be a space). Then, each "word" obtained this way is treated
as a separate argument to the command that the shell will run. In your case,

A${IFS}B

becomes (after variable substitution)

A \t\nB

word splitting turns the " \t\n" sequence into a single space. The result is
thus two arguments "A" and "B", which are passed to echo.

If you use double quotes, word splitting does not happen within them. So

"A${IFS}B"

after variable substitution becomes

A \t\nB

and, because it was in double quotes, that is preserved and passed *as a
single argument* to echo.

Anoter example of word splitting:

$ ls
file1 file2 file3
$ a=`ls`
$ echo "$a" # no word splitting, everything's preserved
file1
file2
file3
$ echo $a # word splitting kicks in
file1 file2 file3

Yet another example. $# is a special variable representing the number of
arguments received by a script.

$ ls
file1 file2 file3
$ a=`ls`
$ sh -c 'echo "Number of arguments: $#"' sh "$a"
Number of arguments: 1
$ sh -c 'echo "Number of arguments: $#"' sh $a
Number of arguments: 3

To return to your example:

$ sh -c 'echo "Number of arguments: $#"' sh A${IFS}B
Number of arguments: 2
$ sh -c 'echo "Number of arguments: $#"' sh "A${IFS}B"
Number of arguments: 1

Your shell should have a good description of the word splitting process in
the man page. If this helps, this is what bash man page says (slightly
reformatted):

Word Splitting
The shell scans the results of parameter expansion, command
substitution, and arithmetic expansion that did not occur within dou?
ble quotes for word splitting.

The shell treats each character of IFS as a delimiter, and splits the
results of the other expansions into words on these charac?
ters. If IFS is unset, or its value is exactly
<space><tab><newline>, the default, then sequences of <space>,
<tab>, and <newline> at the beginning and end of the results of
the previous expansions are ignored, and any sequence of IFS
characters not at the beginning or end serves to delimit words. If
IFS has a value other than the default, then sequences of the
whitespace characters space and tab are ignored at the beginning and
end of the word, as long as the whitespace character is in the value
of IFS (an IFS whitespace character). Any character in IFS that is
not IFS whitespace, along with any adjacent IFS whitespace charac?
ters, delimits a field. A sequence of IFS whitespace characters is
also treated as a delimiter. If the value of IFS is null, no word
splitting occurs.

From: pk on
pk wrote:

> not appear between double quotes*, the shell performs word splitting, that
> is, sequences of blanks (like space, tab and newline) are replaced with a
> single space (they are actually replaced with the first character of $IFS,
> which happens to be a space).

This is actually incorrect. I was getting confused with something else.
They're not actually replaced with anything; what matters is that the
sequence of blanks is treated as a word separator.
Sorry for the confusion.
From: Seebs on
On 2010-03-08, Decare <decare(a)yeah.net> wrote:
> The following two commands have different effect.

Yes, they do.

> $ echo A${IFS}B
> A B

> $ echo "A${IFS}B"
> A
> B

> It is obvious that the first one interprets `IFS' as
> space, while the second interprets it as new line.
> In fect, the `IFS' represents three characters, namely
> space, tab, and new line. why different choices occur
> in different situations?

Actually, it is not obvious at all that the first one interprets
IFS as space, or the second interprets it as new line.

In the first one, there's no quotes. When you expand any variable
unquoted, it is then split into fields... By removing any characters
from $IFS and replacing them with a separation-of-fields. Thus, you
end up producing two arguments to echo, "A" and "B". These arguments
are then echoed, with a space between them.

In the second, there's quotes. When you expand a variable inside quotes,
it is not split into fields. So you pass a single argument to echo,
which argument happens to contain a space, tab, and newline. So it
echoes A, space, tab, newline, B. But you can't see the space and tab.

You can see this as follows:

#!/bin/sh
for i
do
echo "<$i>" | sed -e 's/^/:/g' -e 's/$/:/g'
done

$ ./args A${IFS}B
:<A>:
:<B>:
$ ./args "A${IFS}B"
:<A :
:B>:

In short: If you think something is obvious, and you don't understand it,
it probably isn't really obvious. In this case, your interpretation of the
output was wrong in both cases, and that was the source of the confusion.

-s
--
Copyright 2010, all wrongs reversed. Peter Seebach / usenet-nospam(a)seebs.net
http://www.seebs.net/log/ <-- lawsuits, religion, and funny pictures
http://en.wikipedia.org/wiki/Fair_Game_(Scientology) <-- get educated!