Bash 和 IFS:字符串拆分为具有特定分隔符的数组添加一个额外的空元素

Bash and IFS: string split to an array with specific separator add an extra empty element

关于将字符串拆分成数组我们有两种场景:

如果字符串中有空spaces怎么分隔符,按照下面的post:

所以如果我使用:

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

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

输出为:

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

两种方法都按预期工作。

现在,如果字符串有不同于空的东西 space 如何分隔符,根据以下 post:

所以如果我使用:

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

它打印:

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

为什么会出现那个空元素?如何修复命令以避免这种情况?

您的字符串分为 4 个部分:一个空部分和三个单词。

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

输出:

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

有很多方法可以修复它。一种是删除空值。另一种是在拆分之前排除开头的斜线。

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

或者

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

第一个适用于路径形式,斜杠不仅在开头重复。

只是为了补充真正格式化的评论:

手册(在 3.5.7 Word Splitting 中)将 IFS 描述为“字段 终止符”:

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.

对于IFS=/ read -a fields <<< "/home/user",第一个字段是以第一个斜杠结尾的空字符串。