使用IFS将Bash字符串转换为数组

8

我在使用IFS将字符串转换为数组时遇到了问题。这是我的字符串:

"Jun01 Jun02 Jun03 Jun04 Jun05 ..." #in that format, separated by spaces

以下是我尝试的代码:

在这里展示了我尝试过的代码:

IFS=" " #set it to space character
DATES_ARRAY=($DATES_STRING) #from above
echo ${DATES_ARRAY[0]} #output is empty

然而,当我去掉IFS这一行时,它就可以工作了。但是,我使用了几行代码来打印出它的默认ASCII值,我得到了'32',这意味着空格字符。作为一个强迫症程序员,我想自己设置以确保安全...但我不知道它如何在先验上预设!那么,为什么手动将IFS设置为空格符号会失效呢?

1
你的代码在bash v3.2.25上运行成功了,你使用的是哪个locale? - bobah
1
对我来说,适用于GNU bash版本4.2.29。尝试像“”这样放置空格,看看是否有任何区别。 - Jite
刚刚几分钟前回答了类似的问题:https://dev59.com/pmXWa4cB1Zd3GeqPRvHn#11416230 - smocking
1
@YoungMoney,它与预期行为有何不同之处?对我来说它是有效的:string="a b c d e"; tokens=(${string}); echo "Third token: ${tokens[2]}" 输出 Third token: c,正如我所期望的那样。 - smocking
@YoungMoney,运行_locale_和_bash --version_ - bobah
显示剩余3条评论
3个回答

12
它确实有效,但是根据默认情况,在IFS中保证了空格,因此无论如何都不需要手动设置它。这样做可能会导致问题。
基本上,永远不要在Bash中使用单词分割。如果只能使用POSIX sh并且非常小心地使用,则有时需要咬紧牙关使用它。如果你要设置IFS,请将其设置为仅在几个具有某些影响的命令的环境中,或者最多只在本地函数中设置。
你永远不需要使用这个,所以我不会解释所有内容:
$ printf -v str '%s ' Jun{01..10}
$ set -f
$ IFS=' ' declare -a 'arr=($str)'
$ declare -p arr
declare -a arr='([0]="Jun01" [1]="Jun02" [2]="Jun03" [3]="Jun04" [4]="Jun05" [5]="Jun06" [6]="Jun07" [7]="Jun08" [8]="Jun09" [9]="Jun10")'

这里将IFS设置为空格只是为了冗余展示它的工作方式。

从字符串转换为数组最正确的方法可能是使用read。 这里有许多例子:http://mywiki.wooledge.org/BashFAQ/001

规范的方法是:

read -ra arr <<<"$str"

如果环境中设置了 IFS,并且它不是空格,那么它可选地被设置为 read 的分隔符。


7

建议不要单独使用$IFS来将字符串分割成数组,因为设置和还原$IFS非常麻烦。可以使用如下的方法:

DATES_STRING='Jun01 Jun02 Jun03 Jun04 Jun05'

IFS=' ' read -a DATES_ARRAY <<< "$DATES_STRING"

我建议在read的环境变量中明确设置$IFS,这样你就可以确定它的值了。


4
那会不会改变IFS的任何方式? - Tegra Detra

2
默认情况下,$IFS 使用空格作为令牌分隔符,包括制表符和换行符。
尝试一下这个:
echo "$IFS" | cat -vte

如果您没有更改$IFS,输出应该是:
 ^I$
$

这里有一个空格,后面跟着一个制表符:^I,然后是一个换行符 - 请注意cat将任何换行符打印为$

因此,您的脚本摘录应该可以在不触及$IFS的情况下运行。


1
好的,但我不明白为什么尝试自己将其设置为空格不起作用。虽然知道默认值还是很好的。 - JDS
cat -te 相当于 cat -vTE,因此您可以跳过 -v - Todd A. Jacobs

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