可能在 BASH 3 及更高版本中最简单、最安全的方法是:
var="string to split"
read -ra arr <<<"$var"
(其中arr 是获取字符串拆分部分的数组)或者,如果输入中可能有换行符并且您想要的不仅仅是第一行:
var="string to split"
read -ra arr -d '' <<<"$var"
(请注意-d '' 中的空格;不能省略),但这可能会给您带来来自<<<"$var" 的意外换行符(因为这会在末尾隐式添加一个LF)。
例子:
touch NOPE
var="* a *"
read -ra arr <<<"$var"
for a in "${arr[@]}"; do echo "[$a]"; done
输出预期
[*]
[a]
[*]
因为此解决方案(与此处所有以前的解决方案相比)不易出现意外且通常无法控制的 shell globbing。
这也为您提供了您可能想要的 IFS 的全部功能:
例子:
IFS=: read -ra arr < <(grep "^$USER:" /etc/passwd)
for a in "${arr[@]}"; do echo "[$a]"; done
输出类似:
[tino]
[x]
[1000]
[1000]
[Valentin Hilbig]
[/home/tino]
[/bin/bash]
如您所见,这样也可以保留空格:
IFS=: read -ra arr <<<' split : this '
for a in "${arr[@]}"; do echo "[$a]"; done
输出
[ split ]
[ this ]
请注意,在 BASH 中对 IFS 的处理本身就是一个主题,因此请进行测试;一些有趣的话题:
-
unset IFS:忽略 SPC、TAB、NL 的运行以及在线开始和结束
-
IFS='': 没有字段分离,只读取所有内容
-
IFS=' ':SPC 运行(和仅 SPC)
一些最后的例子:
var=$'\n\nthis is\n\n\na test\n\n'
IFS=$'\n' read -ra arr -d '' <<<"$var"
i=0; for a in "${arr[@]}"; do let i++; echo "$i [$a]"; done
输出
1 [this is]
2 [a test]
同时
unset IFS
var=$'\n\nthis is\n\n\na test\n\n'
read -ra arr -d '' <<<"$var"
i=0; for a in "${arr[@]}"; do let i++; echo "$i [$a]"; done
输出
1 [this]
2 [is]
3 [a]
4 [test]
顺便说一句:
第二个问题:
要测试字符串中的某些内容,我通常坚持使用case,因为这可以一次检查多个案例(注意:案例只执行第一个匹配项,如果您需要通过使用多个case 语句),并且这种需求经常出现(双关语):
case "$var" in
'') empty_var;; # variable is empty
*' '*) have_space "$var";; # have SPC
*[[:space:]]*) have_whitespace "$var";; # have whitespaces like TAB
*[^-+.,A-Za-z0-9]*) have_nonalnum "$var";; # non-alphanum-chars found
*[-+.,]*) have_punctuation "$var";; # some punctuation chars found
*) default_case "$var";; # if all above does not match
esac
所以你可以像这样设置返回值来检查 SPC:
case "$var" in (*' '*) true;; (*) false;; esac
为什么是case?因为它通常比正则表达式序列更具可读性,并且由于 Shell 元字符,它可以很好地处理 99% 的所有需求。