When setting IFS to split on newlines, why is it necessary to include a backspace?

后端 未结 5 1189
灰色年华
灰色年华 2020-12-12 20:29

I\'m curious as to why the backspace is necessary when setting IFS to split on newlines like this:

IFS=$(echo -en \"\\n\\b\")

Why can I not

相关标签:
5条回答
  • 2020-12-12 20:45

    I just remembered the easiest way. Tested with bash on debian wheezy.

    IFS="
    "
    

    no kidding :)

    0 讨论(0)
  • 2020-12-12 20:45

    It's a hack because of the use of echo and command substitution.

    prompt> x=$(echo -en "\n")
    prompt> echo ${#x}
    0
    prompt> x=$(echo -en "\n\b")
    prompt> echo ${#x}
    2
    

    The $() strips trailing newlines and \b prevents \n from being a trailing newline while being highly unlikely to appear in any text. IFS=$'\n' is the better way to set IFS to split on newlines.

    0 讨论(0)
  • 2020-12-12 20:46

    Because as bash manual says regarding command substitution:

    Bash performs the expansion by executing command and replacing the command substitution with the standard output of the command, with any trailing newlines deleted.

    So, by adding \b you prevent removal of \n.

    A cleaner way to do this could be to use $'' quoting, like this:

    IFS=$'\n'
    
    0 讨论(0)
  • 2020-12-12 21:04

    \b char as a suffix of newline \n is added due to removal of tailing \n of the command substitution $(...) so the \b is used as a suffix to \n and by that \n is no longer trailing so it is returned from the the command substitution.

    The side effect that is that IFS also will have \b char as well as a separator instead of just \n that is the sole interest.

    If you expect \b may someday happen in the string (why not?) then you may use:

    IFS="$(printf '\nx')" && IFS="${IFS%x}";
    

    that returns \n suffixed with x && removes x

    now IFS has only the \n char.

    IFS="$(printf '\nx')" && IFS="${IFS%x}";
    echo ${#IFS}; # 1
    

    and nothing will break in case of \b, test:

    #!/bin/sh
    
    sentence=$(printf "Foo\nBar\tBaz Maz\bTaz");
    IFS="$(printf '\nx')" && IFS="${IFS%x}";
    
    for entry in $sentence
    do
        printf "Entry: ${entry}.\n";
    done
    

    gives two lines (due to one \n):

    Entry: Foo.
    Entry: Bar      Baz Maz Taz.
    

    as expected.

    instead of IFS="$(printf '\nx')" && IFS="${IFS%x}"; using:

    IFS="
    "
    

    gives the same result but these two lines must not be indented and if you accidentally put space or tab or any other white char between " and " you'll no longer have only \n char there but some "bonuses" as well That will be hard to spot unless you use option show all characters in your editor.

    0 讨论(0)
  • 2020-12-12 21:04

    Just pressing enter without assigning anything also works. Although, it looks like someone made a mistake and difficult to understand.

    IFS=
    #This is a line
    
    0 讨论(0)
提交回复
热议问题