AGa*_*yer 19 shell string shell-script
split()在 JavaScript 中很容易使用将字符串分解为数组。
shell脚本呢?
说我想这样做:
$ script.sh var1_var2_var3
当用户将这样的字符串提供var1_var2_var3给 script.sh 时,在脚本内部,它会将字符串转换为一个数组,如
array=( var1 var2 var3 )
for name in ${array[@]}; do
# some code
done
Run Code Online (Sandbox Code Playgroud)
Sté*_*las 25
类似 Bourne/POSIX 的 shell 有一个 split+glob 运算符,每次在列表上下文中不加引号地保留参数扩展 ( $var, $-... )、命令替换 ( $(...)) 或算术扩展 ( $((...)))时都会调用它。
实际上,您在执行for name in ${array[@]}而不是for name in "${array[@]}". (实际上,您应该注意,错误地调用该运算符是许多错误和安全漏洞的来源)。
该运算符配置了$IFS特殊参数(以告知要拆分的字符(尽管要注意空格、制表符和换行符在那里接受特殊处理))以及-f禁用 ( set -f) 或启用 ( set +f)glob部分的选项。
另请注意,虽然Sin$IFS最初(在 Bourne shell 中$IFS)用于S分隔符,但在 POSIX shell 中, in 字符$IFS应该被视为分隔符或终止符(请参见下面的示例)。
所以要拆分_:
string='var1_var2_var3'
IFS=_ # delimit on _
set -f # disable the glob part
array=($string) # invoke the split+glob operator
for i in "${array[@]}"; do # loop over the array elements.
Run Code Online (Sandbox Code Playgroud)
要查看separator和delimiter之间的区别,请尝试:
string='var1_var2_'
Run Code Online (Sandbox Code Playgroud)
这将把它分成var1和var2只(没有额外的空元素)。
因此,要使其类似于 JavaScript 的split(),您需要一个额外的步骤:
string='var1_var2_var3'
IFS=_ # delimit on _
set -f # disable the glob part
temp=${string}_ # add an extra delimiter
array=($temp) # invoke the split+glob operator
Run Code Online (Sandbox Code Playgroud)
(请注意,它会将一个空元素拆分$string为1 个(而不是0 个)元素,就像 JavaScript 的split())。
要查看特殊处理选项卡、空格和换行符接收,请比较:
IFS=' '; string=' var1 var2 '
Run Code Online (Sandbox Code Playgroud)
(你得到的地方var1和var2)与
IFS='_'; string='_var1__var2__'
Run Code Online (Sandbox Code Playgroud)
你在哪里得到:'', var1, '', var2, ''。
请注意,zsh除非 insh或kshemulation ,否则 shell 不会像那样隐式调用 split+glob 运算符。在那里,您必须明确地调用它。$=string对于拆分部分,$~string对于 glob 部分($=~string对于两者),它还有一个拆分运算符,您可以在其中指定分隔符:
array=(${(s:_:)string})
Run Code Online (Sandbox Code Playgroud)
或保留空元素:
array=("${(@s:_:)string}")
Run Code Online (Sandbox Code Playgroud)
请注意,这里s用于拆分,而不是分隔(还有$IFS,已知的 POSIX 不一致性zsh)。它与 JavaScript 的不同之处split()在于,空字符串被拆分为 0 个(而不是 1 个)元素。
与$IFS-splitting 的一个显着区别是${(s:abc:)string}在abc字符串上拆分,而 withIFS=abc将在a,b或上拆分c。
使用zsh和ksh93,空格、制表符或换行符的特殊处理可以通过将它们在$IFS.
作为历史记录,Bourne shell(祖先或现代 POSIX shell)总是剥离空元素。它还存在许多与 $@ 的非默认值的拆分和扩展相关的错误$IFS。例如,IFS=_; set -f; set -- $@将不等同于IFS=_; set -f; set -- $1 $2 $3....
现在,对于split()可以拆分正则表达式的更接近 JavaScript 的东西,您需要依赖外部实用程序。
在 POSIX 工具箱中,awk有一个split可以拆分扩展正则表达式的运算符(它们或多或少是 JavaScript 支持的类 Perl 正则表达式的子集)。
split() {
awk -v q="'" '
function quote(s) {
gsub(q, q "\\" q q, s)
return q s q
}
BEGIN {
n = split(ARGV[1], a, ARGV[2])
for (i = 1; i <= n; i++) printf " %s", quote(a[i])
exit
}' "$@"
}
string=a__b_+c
eval "array=($(split "$string" '[_+]+'))"
Run Code Online (Sandbox Code Playgroud)
该zsh外壳具有内建的Perl兼容的正则表达式(其支持zsh/pcre模块),但用它来分割字符串,但可能是比较麻烦的。
是的,使用IFS并将其设置为_. 然后用于read -a存储到数组中(-r关闭反斜杠扩展)。请注意,这是特定于 bash 的;ksh 和 zsh 具有相似的功能,但语法略有不同,而普通的 sh 根本没有数组变量。
$ r="var1_var2_var3"
$ IFS='_' read -r -a array <<< "$r"
$ for name in "${array[@]}"; do echo "+ $name"; done
+ var1
+ var2
+ var3
Run Code Online (Sandbox Code Playgroud)
来自man bash:
读
-一个名字
这些词被分配给数组变量 aname 的顺序索引,从 0 开始。在分配任何新值之前取消设置 aname。其他名称参数将被忽略。
国际金融中心
内部字段分隔符,用于在扩展后进行分词,并使用 read 内置命令将行拆分为单词。默认值为“”。
请注意,read在第一个换行符处停止。传递-d ''到read以避免这种情况,但在这种情况下,由于<<<运算符的原因,最后会有一个额外的换行符。您可以手动删除它:
IFS='_' read -r -d '' -a array <<< "$r"
array[$((${#array[@]}-1))]=${array[$((${#array[@]}-1))]%?}
Run Code Online (Sandbox Code Playgroud)