1

I have a multiline string which I want to transform into an array by using a single delimiter |. However, when setting IFS=| it will stop right before a new line appears:

IFS='|' read -a VARS <<< "var1|var2|var3
                          var4|var5|var6
                          var7|var8|var9"

echo ${VARS[@]}
#output => var1 var2 var3

I am wondering why the remaining lines won’t be evaluated and how to prevent that of happening, being able to assign every variable regardless the presence of a new line?

zanona
  • 12,345
  • 25
  • 86
  • 141
  • `IFS` is only used for splitting fields in a single string. `read` will read only one line at a time. Your here string consists of *three* lines. – chepner Aug 19 '14 at 14:24

2 Answers2

5

Set your IFS to | and \n and use -d to use another delimiter besides newline. You also need to keep your values intact. Spaces also get to be included.

IFS=$'|\n' read -d '' -a VARS <<< "var1|var2|var3
var4|var5|var6
var7|var8|var9"

read by default only reads up to the first newline character unless changed by -d. '' is also synonymous to $'\0' as an argument to it.

Another point

Spaces (including newlines) inside double-quotes are not silently ignored. They are also included literally as a value.

So perhaps what you really should have done is:

IFS='|' read -a VARS <<< "var1|var2|var3|var4|var5|var6|var7|var8|var9"
konsolebox
  • 72,135
  • 12
  • 99
  • 105
  • that is great konsolebox. Thanks for this. Any ideas why `IFS='|' read -a VARS <<< \`echo var1|var2|var3\`` won’t have the same effect (since it is the output of a command? – zanona Aug 19 '14 at 14:45
  • @zanona If you're not quoting `echo var1|var2|var3`, `|` would be interpreted as a pipe on a simple command. – konsolebox Aug 19 '14 at 14:49
  • 1
    Thanks @konsolebox, just figure out when it is a command output I should use `< <(command)` instead `<<<\`command\`` that works now – zanona Aug 19 '14 at 14:51
3

In bash, the proper syntax to write multiline strings is the following :

IFS='|' read -a VARS <<< "var1|var2|var3 \
                          var4|var5|var6 \
                          var7|var8|var9"
echo ${VARS[@]}
#>var1 var2 var3 var4 var5 var6 var7 var8 var9

#However, you will have
echo "${VARS[@]}"
#>var1 var2 var3                           var4 var5 var6                           var7 var8 var9

If you want to write your string as a multiline one and remove completely spaces, you could add | to your existing $IFS instead of erasing it

IFS=$IFS'|' read -a VARS <<< "var1|var2|var3 \
                              var4|var5|var6 \
                              var7|var8|var9"
echo "${VARS[@]}"
#>var1 var2 var3 var4 var5 var6 var7 var8 var9
Aserre
  • 4,916
  • 5
  • 33
  • 56
  • I really didn’t know about breaking lines with `\` thank you very much for the tip Plotoux – zanona Aug 19 '14 at 14:50