【问题标题】:Bash and IFS: string split to an array with specific separator add an extra empty elementBash 和 IFS:字符串拆分为具有特定分隔符的数组添加一个额外的空元素
【发布时间】:2022-01-08 10:55:31
【问题描述】:

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

如果字符串中有空格怎么做分隔符,按照下面的帖子:

所以如果我使用:

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'

两种方法都按预期工作。

现在,如果字符串有不同于空格的东西如何分隔符,根据下面的帖子:

所以如果我使用:

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

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

【问题讨论】:

  • 分隔符有一个'before'字段和一个'after'字段;当 / 是分隔符时 - /home/human/scripts - 有 4 个字段...第一个 / 之前的空字符串,以及您知道的其他 3 个字段;如果输入是//home/human/scripts/,您将有 6 个字段... 2 个空字符串 + home + human + scripts + 1 个空字符串
  • 我也应该说,如果您在方法 1 中正确引用了数组,echo "${array[@]}" 将输出 `home human scripts, with the space separating the empty string from home` 可见。没有引号,echo 真的只得到三个参数;在分词期间未加引号的空字符串“消失”。
  • @markp-fuso 非常感谢您的解释。
  • fwiw,使用分隔符(例如,cutawk)或使用IFS 分割输入(例如,@ 987654340@ - 见 konsolebox 的例子)
  • 空字符串不等于空格。 echo "${array[@]}" 输出中的前导空格来自 echo 本身,而不是数组。

标签: arrays string bash shell split


【解决方案1】:

您的字符串分为 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#/}"

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

【讨论】:

  • 我使用了你的第二种方法。谢谢。你能扩展一下为什么会出现空元素的想法吗?
  • 因为它是您拆分的字符串的一个组成部分。仅仅因为字符串 starts/ 并不意味着初始 / 的处理方式不同。
  • 你能解释一下"${path#/}"的工作原理吗?特别是"#/ 部分。
  • @chepner 现在我明白了……很抱歉,意识到这一点很累。谢谢
  • 这是parameter expansion 方法之一。
【解决方案2】:

只是补充一下真正的格式化评论:

手册(3.5.7 Word Splitting)将 IFS 描述为“字段终结者”:

shell 将 $IFS 的每个字符视为分隔符,并将其他扩展的结果拆分为使用这些字符作为字段终止符的单词。

对于IFS=/ read -a fields &lt;&lt;&lt; "/home/user",第一个字段是由第一个斜杠终止的空字符串。

【讨论】:

    猜你喜欢
    • 2012-01-30
    • 1970-01-01
    • 2017-02-22
    • 1970-01-01
    • 2015-08-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多