4

In Bash, word splitting is a step in command line processing. From Bash Manual

The shell treats each character of $IFS as a delimiter, and splits the results of the other expansions into words using these characters as field terminators. 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 characters, 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.

I want to rewrite the following example, so that the delimiter space between the arguments a, b and c is replaced with tab or newline

$ echo a b c a b c 

But when I hit the key Tab, there is no response.

When I hit \ and return, there is no space between a, b and c in the output:

$ echo a\ > b\ > c abc 

Why can't I do what the quote says?

Btw, nothing comes out of $IFS:

$ echo $IFS 
13
  • 2
    echo $IFS isn't going to tell you anything - by definition, you'll have no arguments. You'll want to quote the expansion, and you'll want to see the whitespace characters - try printf '%q\n' "$IFS" instead. Commented Apr 28, 2016 at 16:27
  • echo "$IFS" | od -bc will show it. Commented Apr 28, 2016 at 16:29
  • You should focus on what you're trying to achieve as I don't think $IFS is meant for what you want. It serves when you want to use non standard delimiters or remove some, which would impact every other commands run in that shell. Commented Apr 28, 2016 at 16:46
  • do you mean like echo a$'\n'b$'\n'c and echo a$'\t'b$'\t'c ? Commented Apr 28, 2016 at 16:55
  • @JuliePelletier: what is $IFS meant for, if not for what the quote says? Commented Apr 28, 2016 at 17:37

3 Answers 3

4

Newlines are handled specially by bash, regardless of the value of IFS. A backslash before a newline causes the newline to be ignored. Has nothing to do with word splitting and would occur even if IFS were set to some custom value.

From LESS=+/^QUOTING man bash:

 A non-quoted backslash (\) is the escape character. It preserves the literal value of the next character that follows, with the exception of <newline>. If a \<newline> pair appears, and the backslash is not itself quoted, the \<newline> is treated as a line continuation (that is, it is removed from the input stream and effectively ignored). 

You can see the word splitting on newline occur another way: By stuffing a newline into a variable, and then echoing the variable without quoting it.

$ myvar=a$'\n'b$'\n'c $ echo "$myvar" a b c $ echo $myvar a b c $ 
2

Direct answer

The unquoted command: echo a b c, will be split on (metacharacter space) no matter what IFS is or is not. The split arguments to echo: a, b and c will be printed with spaces because echo is defined as this:

LESS=+/'^ *echo \[-neE\] \[arg ...\]' man bash 

Output the args, separated by spaces, followed by a newline.

Also no $IFS involved.

So, what you quoted has no relevance here. The key part is:

... splits the results of the other expansions into words ...

You must have an expansion before $IFS is used.
There is not any expansion in a b c.

If you must have an effect of $IFS, use an unquoted expansion:

$ var='a b c' $ echo $var a b c 

But that still does not use $IFS for output, only for splitting.

IFS in output.

Where $IFS does have relevance (for output) is in $*.

$ set -- a b c $ IFS=$'\t' $ printf '%s\n' "$*" | od -An -vtx1c 61 09 62 09 63 0a a \t b \t c \n 

Is that what you need?


Other issues.

Keyboard Tab

when I hit the key Tab, there is no response

Then press together CtrlV, release, and then press Tab.

But without quotes you will not be able to assign a tab to a variable. Test:

$ var=a b ### The space represents a tab as above. bash: b: command not found 

You will need:

$ var="a b" ### The space represents a tab as above. 

Double quotes at the very least.

Quote IFS

nothing comes out of $IFS:

$ echo $IFS 

Nothing comes out of $IFS because you did not quote $IFS. Try:

<user>$ echo "$IFS" | sed -n l \t$ $ <user>$ 

Which has one new line from $IFS and one from the command echo.
Better change to printf:

<user>$ printf '%s' "$IFS" | sed -n l \t$ <user>$ 

And use od:

$ printf '%s' "$IFS" | od -An -vtx1c 20 09 0a \t \n 

As we already have a way to "see" what characters are contained in an string.
We may as well use that to "see" what is inside a couple of strings:

$ var='a b c' $ echo "$var" | od -An -vtx1c 61 20 62 20 63 0a a b c \n 

That should not be any surprise. As this (with single quotes) should not be:

$ var='a\ > b\ > c' $ echo "$var" | od -An -vtx1c 61 5c 0a 62 5c 0a 63 0a a \ \n b \ \n c \n 

Exactly what was typed. If the var is properly quoted, the backslash appear correctly.

Quoting

But quoting with double quotes may change some characters:

$ var="a\ > b\ > c" $ echo "$var" | od -An -vtx1c 61 62 63 0a a b c \n 

But what you wrote has no quotes on setting the var nor using it on echo.
That is a no-no rule in shells. Please Quote correctly.

0

To replace a space with a tab character using $IFS you can use the argument array:

unset IFS set a b c IFS=$(printf \\t) printf "%s\n" "$*" 

Understand that $IFS is about splitting - it contains a list of characters the shell uses to split unquoted expansions in list contexts. You can't really use it to replace characters except in the special case of the $* special shell parameter. In all other cases its use will amount to nullifying and delimiting certain portions of unquoted shell expansions.

2
  • 1
    Aren't you stuffing arguments in a format string? I mean, you just set them—but otherwise printf "$*\n" would be a pretty bad idea, no? Commented Apr 28, 2016 at 19:11
  • @Wildcard - Good point. Commented May 3, 2016 at 21:47

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.