I want to split 'hello' into h e l l o in an array using only bash, I could do it in sed with sed 's/./& /g' but I want to know how to split a string into an array in Bash when I do not know what the delimiter would be, or the delimiter is any single character. I don’t think I can use ${i// /} without some creativity because the delimiter is an unknown, and I don’t think that expression accepts regex. I tried using BASH_REMATCH with [[ string =~ ([a-z].).* ]] but it doesn’t work as I expected. What is the proper way to use only bash to accomplish a string.split() type of behavior? The reason is that I am trying to write the rev utility in all bash:
while read data; do
word=($(echo $data|tr ' ' '_'|sed 's/./& /g'))
new=()
i=$((${#word[@]} - 1))
while [[ $i -ge 0 ]]; do
new+=(${word[$i]})
(( i-- ))
done
echo ${new[@]}|tr -d ' '|tr '_' ' '
done
But I used tr and sed, I want to know how to do the split properly and then I will fix it to be all bash. Just for fun.
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
s="hello"
declare -a a # define array a
for ((i=0; i<${#s}; i++)); do a[$i]="${s:$i:1}"; done
declare -p a # print array a in a reusable form
Output:
declare -a a='([0]="h" [1]="e" [2]="l" [3]="l" [4]="o")'
or (please note the comments)
s="hello" while read -n 1 c; do a+=($c); done <<< "$s" declare -p a
Output:
declare -a a='([0]="h" [1]="e" [2]="l" [3]="l" [4]="o")'
Method 2
To split string into array of characters, with null delimiter, you can:
str='hello'
arr=()
i=0
while [ "$i" -lt "${#str}" ]; do
arr+=("${str:$i:1}")
i=$((i+1))
done
printf '%sn' "${arr[@]}"
With delimiter other than null, you can:
set -f
str='1,2,3,4,5'
IFS=',' arr=($str)
printf '%sn' "${arr[@]}"
Method 3
Just for fun (and other shells) other variant:
word=hello
unset letter
while [ ${#word} -gt 0 ]
do
rest=${word#?}
letter[${#letter[*]}]=${word%$rest}
word=$rest
done
And check
for l in "${!letter[@]}"
do
echo "letter [$l] = ${letter[l]}"
done
will print
letter [0] = h letter [1] = e letter [2] = l letter [3] = l letter [4] = o
Method 4
Method 1:
Oneliner:
s="hello"
for ((i=0;i<${#s};i++)); do result[$i]="${s:i:1}"; done
echo ${result[@]}
Expanded code:
s="hello" # Original string.
for ((i=0;i<${#s};i++)); do # For i=0; i<(length of s); i++
result[$i]="${s:i:1}" # result[i] is equal to the i th character of $s
done # End of the loop
echo ${result[@]} # Print all elements of $result.
Method 2:
Oneliner:
s="hello"
var=($(while read -n 1; do printf "$REPLY "; done <<< "$s"))
echo "${var[@]}"
Expanded code:
s="hello" # Original string.
while read -n 1; do # Read chraracter by character the string.
space_separated=$(printf "$space_separated $REPLY") # $space_separated is equal to it plus the current character.
done <<< "$s" # Pass the string to the loop
result=($space_separated) # Split $space_separated into an array.
echo "${result[@]}" # Print all elements of $result.
Thanks to @cuonglm by it’s suggestion.
Effectively, you can use $REPLY that is the default varible where read reads the input.
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0