I'm totally striking out figuring out how to do something that I think should be simple.
The following test code demonstrates the issue I'm bumping up against.
#!/bin/bash
# Declare array with 4 elements
#
ARRAY_1=( 'Debian Linux' 'Redhat Linux' Ubuntu Linux )
# Contents of ARRAY_1
#
echo ARRAY_1: ${ARRAY_1[@]}
# Get number of elements in the array
#
NUM_ELEMENTS=${#ARRAY_1[@]}
# echo each element in array
#
for (( i=0;i<$NUM_ELEMENTS;i++ )); do
echo ${ARRAY_1[${i}]}
done
echo
echo Now try with reading from a file.
echo The goal is to behave like ARRAY_1
echo Note: Its important that all the elements appear
echo on one line in the file.
echo
tmpFile=/tmp/TEST_ELEMENTS.$$
cat << EOF > $tmpFile
'Debian Linux' 'Redhat Linux' Ubuntu Linux
EOF
# How to get this to behave like ARRAY_1 assignment above?
#
# ARRAY_2=( `eval "cat $tmpFile"` ) # Nope.
# ARRAY_2=( $(cat $tmpFile) ) # Also Nope
# ARRAY_2=( $(xargs < $tmpFile) ) # Also Nope
declare -a ARRAY_2=( $(xargs < $tmpFile) ) # Also Nope
echo ARRAY_2: ${ARRAY_2[@]}
NUM_ELEMENTS=${#ARRAY_2[@]}
for (( i=0;i<$NUM_ELEMENTS;i++ )); do
echo ${ARRAY_2[${i}]}
done
/bin/rm $tmpFile
The output appears as follow, or worse depending on what assignment line is uncomment and run.
ARRAY_1: Debian Linux Redhat Linux Ubuntu Linux
Debian Linux
Redhat Linux
Ubuntu
Linux
Now try with reading from a file.
The goal is to behave like ARRAY_1
Note: Its important that all the elements appear
on one line in the file.
ARRAY_2: Debian Linux Redhat Linux Ubuntu Linux
Debian
Linux
Redhat
Linux
Ubuntu
Linux
I really can't figure it out, and not for lack of trying! by searching various forums etc. Someone please put me to shame and point out how easy this is!
Thanks kindly for your help on this!
Using xargs
is an interesting approach as it has the often-overlooked behaviour of handling single- and double-quoted strings in a way that may be compatible with the behaviour you seem to want. But note the additional backslash escaping:
If the -0 option is not specified, the application shall ensure that arguments in the standard input are delimited by unquoted <blank> characters, unescaped <blank> characters, or <newline> characters, and quoting characters shall be interpreted as follows:
A string of zero or more non-double-quote ('"' ) non-<newline> characters can be quoted by enclosing them in double-quotes.
A string of zero or more non-<apostrophe> ('\'') non-<newline> characters can be quoted by enclosing them in <apostrophe> characters.
Any unquoted character can be escaped by preceding it with a <backslash>.
https://pubs.opengroup.org/onlinepubs/9799919799/utilities/xargs.html
As you require that the file contains only a single line, this allows use of xargs
to split into one argument per line and then mapfile
to load each line:
unset ARRAY_2
mapfile -t ARRAY_2 < <(xargs -r -n1 < "$tmpFile")
If your bash is too old to have mapfile
(e.g. macOS), then a read loop can be used:
unset ARRAY_2
while IFS= read -r; do
ARRAY_2+=("$REPLY")
done < <(xargs -r -n1 < "$tmpFile")