Bash: reading a multiline string in multiple variables
How can I assign a newline delimited string eg. from three lines to three variables?
# test string
s='line 01
line 02
line 03'
# this doesn't seem to make any difference at all
IFS=$'\n'
# first naive attempt
read a b c <<< "${s}"
# this prints 'line 01||':
# everything after the first newline is dropped
echo "${a}|${b}|${c}"
# second attempt, remove quotes
read a b c <<< ${s}
# this prints 'line 01 line 02 line 03||':
# everything is assigned to the first variable
echo "${a}|${b}|${c}"
# third attempt, add -r
read -r a b c <<< ${s}
# this prints 'line 01 line 02 line 03||':
# -r switch doesn't seem to make a difference
echo "${a}|${b}|${c}"
# fourth attempt, re-add quotes
read -r a b c <<< "${s}"
# this prints 'line 01||':
# -r switch doesn't seem to make a difference
echo "${a}|${b}|${c}"
I also tried using echo ${s} | read a b c
instead <<<
but couldn't get this to work.
Can this be done in bash at all?
source to share
Reading the default input delimiter is \ n
{ read a; read b; read c;} <<< "${s}"
-d char: allows you to specify a different input delimiter
For example, there is no SOH (1 ASCII) character in the input line
IFS=$'\n' read -r -d$'\1' a b c <<< "${s}"
EDIT: -d can take a null argument, the space is required between the -d and null arguments:
IFS=$'\n' read -r -d '' a b c <<< "${s}"
EDIT: Following a comment about a solution for any number of lines
function read_n {
local i s n line
n=$1
s=$2
arr=()
for ((i=0;i<n;i+=1)); do
IFS= read -r line
arr[i]=$line
done <<< "${s}"
}
nl=$'\n'
read_n 10 "a${nl}b${nl}c${nl}d${nl}e${nl}f${nl}g${nl}h${nl}i${nl}j${nl}k${nl}l"
printf "'%s'\n" "${arr[@]}"
source to share
You are looking for a command readarray
, not read
.
readarray -t lines <<< "$s"
(In theory, $s
there is no need to quote here. If you are not using bash
4.4 or newer, I would still quote it due to some bugs in previous versions bash
.)
Once the strings are in the array, you can assign separate variables if you need
a=${lines[0]}
b=${lines[1]}
c=${lines[2]}
source to share