0

About split a string into an array we have two scenarios:

if the string has empty spaces how a separator, according with the following post:

So If I use:

string="Hello Unix World"
array1=($string)
echo ${array1[@]}
echo "size: '${#array1[@]}'"

read -a array2 <<< $string
echo ${array2[@]}
echo "size: '${#array2[@]}'"

The output is:

Hello Unix World
size: '3'
Hello Unix World
size: '3'

Both approaches works as expected.

Now, if the string has something different than an empty space how a separator, according with the following post:

So If I use:

path="/home/human/scripts"
IFS='/' read -r -a array <<< "$path"

echo "Approach 1"
echo ${array[@]}
echo "size: '${#array[@]}'"

echo "Approach 2"
for i in "${array[@]}"; do
   echo "$i"
done

echo "Approach 3"
for (( i=0; i < ${#array[@]}; ++i )); do
    echo "$i: ${array[$i]}"
done

It prints:

Approach 1
home human scripts    <--- apparently all is ok, but see the line just below!
size: '4'
Approach 2
                      <--- an empty element
home
human
scripts
Approach 3
0:                    <--- confirmed, the empty element
1: home
2: human
3: scripts

Why appears that empty element? How fix the command to avoid this situation?

12
  • 2
    a delimiter has a 'before' field and an 'after' field; when / is the delimiter this - /home/human/scripts - has 4x fields ... the empty string before the first /, and the other 3 fields that you know about; if the input was //home/human/scripts/ you'd have 6 fields ... 2 empty strings + home + human + scripts + 1 empty string Commented Jan 7, 2022 at 23:20
  • 1
    I should say, too, that if you had proper quoted the array in approach 1, echo "${array[@]}" would have output ` home human scripts, with the space separating the empty string from home` visible. Without quotes, echo really does only get three arguments; the unquoted empty string "vanishes" during word-splitting. Commented Jan 7, 2022 at 23:25
  • 1
    @markp-fuso huge thanks for explanation. Commented Jan 7, 2022 at 23:39
  • 1
    fwiw, you'll see the same behavior with other tools/commands that use delimiters (eg, cut and awk) or that use IFS to split the input (eg, read - see konsolebox's example) Commented Jan 7, 2022 at 23:42
  • 1
    The empty string is not the same as a space. The leading space in the output of echo "${array[@]}" comes from echo itself, not the array. Commented Jan 8, 2022 at 1:14

2 Answers 2

1

Your string split into 4 parts: an empty one, and the three words.

path="/home/human/scripts"
IFS='/' read -r -a array <<< "$path"
declare -p array

Output:

declare -a array=([0]="" [1]="home" [2]="human" [3]="scripts")

There are many ways to fix it. One is to delete the empty values. Another is to exclude the beginning slash before splitting.

for i in "${!array[@]}"; do
    [[ ${array[i]} ]] || unset 'array[i]'
done

Or

IFS='/' read -r -a array <<< "${path#/}"

The first one is adaptable to path forms were slashes are repeated not only in the beginning.

Sign up to request clarification or add additional context in comments.

5 Comments

I used your second approach. Thanks. Can you expand the idea about why appeared the empty element?
Because it's a component of the string you split. Just because the strings starts with / doesn't mean the initial / is treated differently.
Can you explain how works "${path#/}"? specially the "#/ part.
@chepner now I see ... sorry very tired to realise about that. Thanks
It's one of those parameter expansion methods.
1

Just to pile on with what is really a formatted comment:

The manual (in 3.5.7 Word Splitting) describes IFS as a "field terminator":

The shell treats each character of $IFS as a delimiter, and splits the results of the other expansions into words using these characters as field terminators.

For IFS=/ read -a fields <<< "/home/user", the first field is the empty string terminated by the first slash.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.