shellfish

Multi-line variables remove new line character - Fish


When I set any multiline text as a variable in fish, it removes the new line characters and replaces them with space, how can I stop it from doing that? Minimal complete example:

~ ) set lines (cat .lorem); set start 2; set end 4;
~ ) cat .lorem 
once upon a midnight dreary while i pondered weak and weary
over many a quaint and curious volume of forgotten lore
while i nodded nearly napping suddenly there came a tapping
as of some one gently rapping rapping at my chamber door
tis some visiter i muttered tapping at my chamber door
~ ) cat .lorem | sed -ne $start\,{$end}p\;{$end}q  # Should print lines 2..4
over many a quaint and curious volume of forgotten lore
while i nodded nearly napping suddenly there came a tapping
as of some one gently rapping rapping at my chamber door
~ ) echo $lines
once upon a midnight dreary while i pondered weak and weary over many a quaint and curious volume of forgotten lore while i nodded nearly napping     suddenly there came a tapping as of some one gently rapping rapping at my chamber door tis some visiter i muttered tapping at my chamber door

Solution

  • fish splits command substitutions on newlines. This means that $lines is a list. You can read more about lists here.

    When you pass a list to a command, each entry in the list becomes a separate argument. echo space-separates its arguments. That explains the behavior you're seeing.

    Note that other shells do the same thing here. For example, in bash:

    lines=$(cat .lorem)
    echo $lines
    

    If you want to prevent the splitting, you can temporarily set IFS to empty:

    begin
       set -l IFS
       set lines (cat .lorem)
    end
    echo $lines
    

    now $lines will contain newlines.

    As faho says, read can also be used and is a little shorter:

    read -z lines < ~/.lorem
    echo $lines
    

    but consider whether splitting on newlines might actually be what you want. As faho hinted, your sed script can be replaced with array slices:

    set lines (cat .lorem)
    echo $lines[2..4] # prints lines 2 through 4