如果我们这样做:
VAR=100:200:300:400
我们可以做到:
echo ${VAR%%:*}
100
和
echo ${VAR##*:}
400
是否有任何等价物可以用来获取 200 和 300 的值?
例如,如果有超过 3 个冒号,是否有办法只获取第二个和第三个冒号之间的内容?
如果我们这样做:
VAR=100:200:300:400
我们可以做到:
echo ${VAR%%:*}
100
和
echo ${VAR##*:}
400
是否有任何等价物可以用来获取 200 和 300 的值?
例如,如果有超过 3 个冒号,是否有办法只获取第二个和第三个冒号之间的内容?
ksh 样式(现在由 POSIX 为 sh 指定)
${var#pattern}
和(以及带有和 的${var%pattern}
贪婪变体)仅从变量内容的开头和结尾分别删除文本。##
%%
要
200
摆脱100:200:300:400
这些操作符,您需要同时应用从开头${VAR#*:}
删除和从结尾删除。100:
${VAR%%:*}
:300:400
那将是
${${VAR#*:}%%:*}
,但虽然那可以在 zsh 中起作用,但在 bash 或 ksh 中不起作用,因为不允许链接参数扩展运算符。在中
zsh
,您宁愿使用$VAR[(ws[:])2]
来获取¹的2
第n个:
s
分隔的w
顺序$var
,或者使用${${(s[:])VAR}[2]}
先将变量拆分为数组,然后获取第二个元素。在 ksh93 中,您可以执行
${VAR/*:@(*):*:*/\1}
,但是虽然 bash(如 zsh²)复制了 ksh93 的${param/pattern/replacement}
操作符,但它并没有复制捕获和引用部分。在 bash 中(尽管存在种种限制,但由于它是 GNU shell,因此仍然被广泛使用,几乎预装在所有的 GNU/Linux 系统以及一些非 GNU 系统上),您可以通过两个步骤完成此操作:
bash 的唯一内置拆分运算符(除非您想考虑 bash 4.4+,
readarray -d
它更多地用于将记录从某些输入流读取到数组中;以及通过在其语法中分离出参数来进行的拆分类型)是 Bourne 风格(由 Korn 扩展)IFS 拆分,它是在未引用的扩展上执行的(您在echo ${VAR%%:*}
忘记引号的地方错误地使用了它),并且通过read
。read
只在一行上起作用,因此只能用于不包含换行符的变量。使用 split+glob(glob 是扩展名不加引号的另一个副作用)很麻烦,因为我们需要禁用 glob 部分,并更改全局$IFS
参数。在 bash 4.4+ 中,你可以这样做:
如果没有
''
,100::300:
则只会拆分为“100”、“”和“300”,因此,$#
即使变量包含 4 个:
分隔的字段,也会扩展为 3。但请注意,这意味着空变量会被拆分为 1 个空元素,而不是 0。对于
read
( 或readarray
) ,类似的解决方法是在输入末尾添加一个额外的分隔符。由于 bash 变量(与 zsh 相反)无论如何都不能包含 NUL 字符,因此对于read
任意变量值,您可以执行以下操作:(
- 1
因为read
从索引 0 而不是 1 开始填充数组;LC_ALL=C
解决了bash 版本 5.0 到 5.2 中未按用户编码编码的文本的一些错误)使用
readarray
(bash 4.4):再次,
:
在末尾添加以防止丢弃尾随的空元素(但再次意味着空输入会导致一个空元素)。¹ 不过请注意,它会拆分
::a:b::c:::
成a
,b
并且c
仅像 Bourne shell 中的 IFS 拆分那样(但在现代 Bourne 类 shell 中则不会,除非使用空格、制表符或换行符作为分隔符)。² zsh 支持它,但语法不同,并且需要
extendedglob
启用该选项:${VAR/(#b)*:(*):*:*/$match[1]}
我不会尝试对冒号分隔的字符串值使用替换语法。相反,我使用拆分将冒号之间的部分放入数组中,然后执行变量替换(甚至数组切片)以返回所需的数组元素:
产生输出:
如果原始值中的冒号之间也出现空格字符(您应该仔细测试这些内容),这可能不会产生您想要的精确效果,但您的示例中没有任何空格字符。
您可以使用 IFS 并设置来分离和访问所有四个:
这需要手动扩展大量的参数。你可以使用分隔符循环遍历,例如
输出:
loadable builtin
使用已调用该函数的 Bash 版本dsv
,可以像上面那样解析字符串cut
。您可以尝试以下操作:输出:
如果某些字段为空,如下所示:
该
-g
选项可用于跳过/删除它。在某些情况下,输入可以有如下所示的双引号字段。
解析理解并跳过双引号字符串。
输出:
bash
它不包含在内。根据
help dsv