How to convert a String into Array in shell script
bkpIFS="$IFS"
IFS=',()][' read -r -a array <<<"(5,[a,b,c,d,e,f,g,h,i,j])"
echo ${array[@]} ##Or printf "%s\n" ${array[@]}
5 a b c d e f g h i j
IFS="$bkpIFS"
Explanations:
- First we are taking backup of default/current shell IFS with
bkpIFS="$IFS"
; Then we set IFS to set of delimiters
,
,(
,)
,]
and[
withIFS=',()]['
which means our input string can be delimited with one-or-more of these delimiters.Next
read -r -a array
reads and split the line into an array calledarray
only based on defined IFS above from input string passed in Here-String method. The-r
option is used to tellread
command don't does expansion on back-slash\
if come in input.IFS=',()][' read -a array <<<"(5,[a,b,c,d,e,f,g,h,i,j,\,k])" echo ${array[@]} 5 a b c d e f g h i j ,k
see the last
,k
which it caused by having back-slash in input andread
without its-r
option.With
echo ${array[@]}
we are printing all elements of array. see What is the difference between $* and $@? and Gilles's answer about${array[@]}
there with more details.With
printf "%s\n" ${array[@]}
also there is other approach to printing array elements.Now you can print a specific element of array with
printf "%s\n" ${array[INDEX]}
or same withecho ${array[INDEX]}
.Ah, sorry, forgot to give
IFS
back to shell,IFS="$bkpIFS"
: )
Or using awk
and its split
function.
awk '{split($0,arr,/[][,)(]/)}
END{for (x in arr) printf ("%s ",arr[x]);printf "\n"}' <<<"(5,[a,b,c,d,e,f,g,h,i,j])"
Explanations:
Same here, we are splitting the entire line of input based on defined group of delimiters
[...]
in regexp constant/[...]/
which support in modern implementation ofawk
usingsplit
function. read more in section ofsplit()
function.Next at the
END{for (x in arr) printf ("%s ",arr[x]); ...}
we are looping over array calledarr
and print their corresponding value.x
here point to the index of arrayarr
elements. read more aboutawk
's BEGIN/END rules.
Side-redirect to How to add/remove an element to the array in bash?.
data=$(tr -d '[]()' | tr ',' '\n')
readarray -t -n 1 group <<<"$data"
readarray -t -s 1 letters <<<"$data"
printf 'group = %s\n' "$group"
printf 'data: %s\n' "${letters[@]}"
This will first get rid of all ()
and []
from the input data that is arriving on standard input using tr
, and then it will replace the commas with newlines and assign the result to data
.
We then use readarray
to parse this data.
The first call will only read the first entry (with -n 1
) and assign it to the variable group
.
The second call to readarray
will skip the first entry (with -s 1
) and assign the remaining entries to the array letters
.
The -t
removes the actual newlines from each entry.
Even though group
is an array here, it's only containing one single element, and you may use it as $group
.
$ echo '(5,[a,b,c,d,e,f,g,h,i,j])' | bash ./script.sh
group = 5
data: a
data: b
data: c
data: d
data: e
data: f
data: g
data: h
data: i
data: j
The following retains the commas in the string and lets readline
use these to delimit the entries, but for some reason, the last element of letters
has a newline at the end:
data=$(tr -d '[]()')
readarray -d, -t -s 1 letters <<<"$data"
printf '>%s<\n' "${letters[@]}"
Running:
$ echo '(5,[a,b,c,d,e,f,g,h,i,j])' | bash ./script.sh
>a<
>b<
>c<
>d<
>e<
>f<
>g<
>h<
>i<
>j
<
POSIXly:
string='(5,[a,b,c,d,e,f,g,h,i,j])'
set -o noglob
IFS=',['
string=${string#'('}
string=${string%'])'}
set -- $string''
gid=$1; shift 2
printf '%s\n' "gid=$gid; group-data:"
printf ' <%s>\n' "$@"
It should work with any value for the group-data fields, even those with newline characters.