将字符串拆分为数组

7

我想要将字符串拆分并构建数组。我尝试了以下代码:

myString="first column:second column:third column"
set -A myArray `echo $myString | awk 'BEGIN{FS=":"}{for (i=1; i<=NF; i++) print $i}'`
# Following is just to make sure that array is constructed properly
i=0
while [ $i -lt ${#myArray[@]} ]
do
echo "Element $i:${myArray[$i]}"
(( i=i+1 ))
done
exit 0

It produces the following result:
Element 0:first
Element 1:column
Element 2:second
Element 3:column
Element 4:third
Element 5:column

This is not what I want it to be. When I construct the array, I want that array to contain only three elements.
Element 0:first column
Element 1:second column
Element 2:third column

你能否提供建议?


我找到了以下代码的解决方案: var='word1#word2|word3/word4|word5.word6|word7_word8|word9 word10|word11|word12'OIFS=$IFS; IFS='|' set -A arr $var IFS=$OIFS - user176125
你可以通过以下更改来删除for循环: awk 'BEGIN{FS=":"}{for (i=1; i<=NF; i++) print $i}'。只需将其保留为awk 'BEGIN{RS=":"}{print}'。 - Vijay
我的系统上的Bash(4.0.33(5)-release)没有set命令的-A选项。你使用的是哪个版本? - outis
5个回答

15

以下是我解决这个问题的方法:使用IFS变量告诉shell(bash)你想要将字符串拆分成以冒号分隔的标记。

$ cat split.sh
#!/bin/sh

# Script to split fields into tokens

# Here is the string where tokens separated by colons
s="first column:second column:third column"

IFS=":"     # Set the field separator
set $s      # Breaks the string into $1, $2, ...
i=0
for item    # A for loop by default loop through $1, $2, ...
do
    echo "Element $i: $item"
    ((i++))
done

运行它:

$ ./split.sh
Element 0: first column
Element 1: second column
Element 2: third column

1
这仅适用于最多有9列的字符串/行。尝试回显$11,您将获得附加'1'的$1的值。 - Dennis
2
@Dennis - 你需要使用不同的符号表示超过9个位置参数。 ${10} , ${11}... http://wiki.bash-hackers.org/scripting/posparams - Cheeso
@Dennis:我已经验证了我的代码,即使是超过10列的行也可以正常工作。你也可以自己验证一下。 - Hai Vu
3
@HaiVu 好主意!你教会了我一些东西,我很感激。我之前不知道这种替代语法。我在此谢过你并表示谦卑。 :-) - Dennis
1
@mat:请确保:a)您没有打错任何字,b)您使用的是bash shell,而不是旧版的bourne shell。 - Hai Vu
@Hai Vu:抱歉,是我的错。我使用了错误的shell :S - bash正常工作!我删除了我的旧评论。 - mat

5
如果你一定要在Bash中使用数组,可以尝试以下方法。
$ myString="first column:second column:third column"
$ myString="${myString//:/ }" #remove all the colons
$ echo "${myString}"
first column second column third column
$ read -a myArr <<<$myString
$ echo ${myArr[@]}
first column second column third column
$ echo ${myArr[1]}
column
$ echo ${myArr[2]}
second

否则,“更好”的方法是完全使用awk。

1
为了保留所有值,可以使用以下命令:IFS=: read -a myArr <<<$myString,不要去掉冒号。 - Christophe Drevet

4
请注意,保存和恢复IFS常在这些解决方案中看到,其副作用是如果IFS未设置,则最终更改为空字符串,这会导致后续分割出现奇怪的问题。
这是我基于Anton Olsen的扩展提出的解决方案,可处理由冒号分隔的超过2个值。它可以正确处理列表中具有空格的值,不会在空格处分割。
colon_list=${1}  # colon-separate list to split
while true ; do
    part=${colon_list%%:*}  # Delete longest substring match from back
    colon_list=${colon_list#*:}  # Delete shortest substring match from front
    parts[i++]=$part
    # We are done when there is no more colon
    if test "$colon_list" = "$part" ; then
        break
    fi
done
# Show we've split the list
for part in "${parts[@]}"; do
    echo $part
done

3
Ksh或Bash
#! /bin/sh
myString="first column:second column:third column"
IFS=: A=( $myString )

echo ${A[0]}
echo ${A[1]}

2

看起来你已经找到了解决方案,但请注意你可以完全不使用awk:

myString="first column:second column:third column"
OIFS="$IFS"
IFS=':'
myArray=($myString)
IFS=$OIFS
i=0
while [ $i -lt ${#myArray[@]} ]
do
    echo "Element $i:${myArray[$i]}"
    (( i=i+1 ))
done

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接