[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
String to array
From: |
Tapani Tarvainen |
Subject: |
String to array |
Date: |
Thu, 30 Sep 2021 15:52:16 +0300 |
Is there some simple way to convert a string into an array in bash,
with each character as an array element?
It can obviously be done with a loop, e.g.,
array=()
while [ -n "$string" ]
do
array+=("${string:0:1}")
string=${string:1}
done
or, preserving the original string,
array=()
i=0
while (( i < ${#string} ))
do
array+=("${string:$((i++)):1}")
done
and of course those are good enough for all(?) practical purposes, but
I started wondering if there's a way to do it without an explicit
loop. So this is not a practical problem, but perhaps someone will
find it an amusing exercise.
Here's my first idea:
array=($(sed 's/./& /g' <<<$string))
That sort of works, but it forks an extra process (sed) and loses
whitespace and breaks in interesting ways with any number of special
characters like *.
This fixes most of those problems:
fopt=${-//[!f]}
set -f
OLDIFS=$IFS
IFS=$'\n'
array=($(sed 's/./&\n/g' <<<$string))
IFS=$OLDIFS
set ${fopt:+-}${fopt:-+f}
but it still loses newlines in the string and is harder to understand
and indeed even longer than the loops above - and it still calls sed,
and I'd like to do this with shell builtins only.
(Side question: is there a better way to restore set -f/+f?)
Playing a little with brace expansion I came up with this:
eval tmparray=('\"\${string:'{0..$((${#string}-1))}':1}\"')
eval array=(${tmparray[@]})
That works, but... let's just say it might be useful in some code
confuscation contest, hardly otherwise.
But I can't shake the feeling that there should be some simple and
pretty way to do it with some such construct. Or at least something
simpler than that double eval thing. Especially since the reverse
operation is so simple:
OLDIFS=$IFS
IFS=
string=${array[*]}
IFS=$OLDIFS
Ideas?
--
Tapani Tarvainen
- String to array,
Tapani Tarvainen <=