2

I am trying to convert string for example string=11111001 to array which I will be able to access by calling respective array index like

arr[0]=1, arr[1]=0

I am new to shell scripting and from what I read, it doesn't have a separator I am stuck.

Can someone help me?

New contributor
Sneha Patil is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.
2
5

bash already has a form of this by way of string slicing:

$ word="word"
$ printf "%s\n" "${word:0:1}
w
$ printf "%s\n" "${word:1:1}
o

The syntax for this is ${variable:start:length}, and will return the next length characters starting at the start ᵗʰ character (zero-indexed).

$ printf "%s\n" "${word:2:2}
rd
1
  • The manual uses the term "offset" in place of "start". Nevertheless, great advice. – glenn jackman 20 hours ago
3

You could split the string on individual characters:

string=11111001
echo "$string" | grep -o .

and read them back as an array:

readarray -t arr <<<"$(grep -o . <<<"$string")"

Then, of course, each character would be at each index of the arr array.

$ declare -p arr
declare -a arr=([0]="1" [1]="1" [2]="1" [3]="1" [4]="1" [5]="0" [6]="0" [7]="1")

But why create a new array if bash could access each individual character directly as this:

$ string=11111001
echo "${string:5:1}" "${string:7:1}"
0 1

Read about ${parameter:offset:length} in man bash.

3

A more verbose way to read a string one character at a time:

string=11111001
arr=()

while IFS= read -r -d "" -n 1 char; do
    arr+=("$char")
done < <(printf '%s' "$string")

declare -p arr

outputs

declare -a arr=([0]="1" [1]="1" [2]="1" [3]="1" [4]="1" [5]="0" [6]="0" [7]="1")
2
string=11111001
read -a array <<< $(echo "$string" | sed 's/./& /g')

sed to split the string by spaces separated.

1
  • @Isaac Thank you. – GAD3R 17 hours ago
2

For completeness, with zsh, to split a string into:

its character constituents:

chars=( ${(s[])string} )

(if $string contains bytes not forming parts of valid characters, each of those will still be stored as separate elements)

its byte constituents

you can do the same but after having unset the multibyte option, for instance locally in an anonymous function:

(){ set -o localoptions +o multibyte
  bytes=( ${(s[])string} )
}

its grapheme cluster constituents.

You can use PCRE's ability to match them with \X:

zmodload zsh/pcre
(){
  graphemes=()
  local rest=$string match
  pcre_compile -s '(\X)\K.*'
  while pcre_match -v rest -- "$rest"; do
    graphemes+=($match[1])
  done
}

(that one assumes the input contains text properly encoded in the locale's charmap).


With string=$'Ste\u0301phane', those give:

chars=( S t e ́ p h a n e )
bytes=( S t e $'\M-L' $'\M-\C-A' p h a n e )
graphemes=( S t é p h a n e )

As the e + U+0301 grapheme cluster (which display devices usually represent the same as the é U+00E9 precomposed equivalent) is made up of 2 characters (U+0065 and U+0301) where in locales using UTF-8 as their charmap, the first one is encoded on one byte (0x65), and the second on two bytes (0xcc 0x81, also known as Meta-L and Meta-Ctrl-A).

For strings made up only of ASCII characters like your 11111001, all three will be equivalent.

Note that in zsh like in all other shells except ksh/bash, array indices start at 1, not 0.

1

Another sed based solution

string=11111001
array=($(sed 's/./& /g' <<<"$string"))

echo "${array[@]}"
1 1 1 1 1 0 0 1

Your Answer

Sneha Patil is a new contributor. Be nice, and check out our Code of Conduct.

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.