bash 4:通过任意分隔符通用访问字符串的子字符串 (n)?

bash 4: Generic access to substring (n) of string by arbitrary delimiter?

假设我有以下字符串:x="number 1;number 2;number 3".

通过 ${x%%";"*} 成功访问 first 子字符串,通过 [=14= 访问 last 子字符串]:

$ x="number 1;number 2;number 3"
$ echo "front : ${x%%";"*}"  #front-most-part
number 1
$ echo "back  : ${x##*";"}"  #back-most-part
number 3
$

如何访问中间部分:(例如number 2)?
如果我有(很多...)更多的部分然后只有三个,有没有更好的方法来做到这一点?
换句话说:是否有一种通用的方法来访问字符串yyy[=42=的第n号子串], 由字符串分隔 xxx 其中 xxx 是一个任意值 string/delimiter?


我已阅读 How do I split a string on a delimiter in Bash?,但我特别不想遍历字符串,而是直接访问给定的子字符串。

这里具体不是问或拆分成数组,而是拆分成子串。

固定索引:

x="number 1;number 2;number 3"

# Split input into fields by ';' and read the 2nd field into $f2
# Note the need for the *2nd* `unused`, otherwise f2 would 
# receive the 2nd field *plus the remainder of the line*.
IFS=';' read -r unused f2 unused <<<"$x"

echo "$f2"

一般来说,使用数组:

x="number 1;number 2;number 3"

# Split input int fields by ';' and read all resulting fields
# into an *array* (-a).
IFS=';' read -r -a fields <<<"$x"

# Access the desired field.
ndx=1
echo "${fields[ndx]}"

约束:

使用IFS,指定I内部F字段的特殊变量S分隔符,总是表示:

  • 只有单个,文字字符可以作为字段分隔符。

    • 但是,您可以指定 多个 个字符,在这种情况下,其中 任何 个字符将被视为分隔符。
  • 默认的分隔符是$' \t\n'——即space、制表符和换行符,以及 运行s 其中(多个连续实例)始终被视为 单个 分隔符;例如,'a b'2 个字段 - 多个 space 算作一个分隔符。

  • 相比之下,与任何其他字符,一个运行中的字符被单独考虑,因此分隔 字段;例如,'a;;b'3 个字段 - 每个 ; 都是它自己的分隔符,因此 ;;.

    [ 之间有一个空字段=82=]

read -r -a ... <<<... 技术 通常效果很好,只要 :

  • 输入是单行
  • 您不担心 尾随的空白字段被丢弃

如果您需要一个完全通用、强大的解决方案来解决上述问题, 使用以下变体,在 @gniourf_gniourf answer here:

中进行了解释
sep=';' 
IFS="$sep" read -r -d '' -a fields < <(printf "%s${sep}[=12=]" "$x")    

注意需要使用 -d '' 一次读取多行输入,并且需要用另一个分隔符实例终止输入以保留尾随的空字段;需要尾随 [=21=] 以确保 read 的退出代码是 0.

不要使用:

创建一个数组,分隔符为;:

x="number 1;number 2;number 3"
_IFS=$IFS; IFS=';'
arr=($x)
IFS=$_IFS

echo ${arr[0]} # number 1
echo ${arr[1]} # number 2
echo ${arr[2]} # number 3