如何从 Bash 中的字符串右侧按索引 trim 一个字段?

How to trim a field by index from the right of a string in Bash?

我想从以下字符串中删除“(字段 5)”:

test_string="[field 1 (field 2)] field 3 (field 4) (field 5) (field 6)"

问题:

到目前为止唯一的方法很脏:

$ first_fields="$(printf "${test_string[@]}" | cut -d'(' -f -2)"

$ echo $first_field
> [field 1 (field 2)] field 3

$ last_field="$(printf "(${test_string##*\(}")"

$ echo "$last_field"
> (field 6)

问题在这里:

问题:如何从字符串的右端开始计算字段数? 或者我是否超出了 Unix shell 功能的限制?

我尝试了以下方法,但我总是只得到一个字段,即整个字符串本身:

IFS="("
for i in "${test_string[@]}";
do
    echo "field is: $i"
done
> [field 1 (field 2)] field 3 (field 4) (field 5) (field 6)

注意:字段总是在括号之间并且每次都包含完全随机的字符(更糟糕的是,它们是用 unicode 编码的外语)。

您可以使用锚定到末尾的正则表达式。

#!/bin/bash
test_string="[field 1 (field 2)] field 3 (field 4) (field 5) (field 6)"
rgx_field="[(].*[)]"
rgx_space="[[:space:]]*"
if
  [[ $test_string =~ (.*)$rgx_field$rgx_space($rgx_field)$rgx_space$ ]]
then
  result="${BASH_REMATCH[1]}${BASH_REMATCH[2]}" # Removed
else
  result=$test_string # No match... Buggy data?
fi
echo "$result"

这假设字段括在括号中,就像您的示例代码一样。

关键行是这样的:

[[ $test_string =~ (.*)$rgx_field$rgx_space($rgx_field)$rgx_space$ ]]

=~ 运算符尝试将左侧的字符串与右侧的扩展正则表达式相匹配。括号内的行部分是正则表达式匹配引擎对 "remember" 这些部分的说明(然后在 BASH_REMATCH 数组中可用)。尾随 $ 表示此正则表达式必须匹配字符串的末尾,以便它从最后一个字段开始工作 "backwards"。前导字段均由初始 (.*).

匹配

您可以使用 sed:

$> test_string="[field 1 (field 2)] field 3 (field 4) (field 5) (field 6)"
$> sed -E 's/^(.*)\([^)]*\) (\([^)]*\))$//' <<< "$test_string"
[field 1 (field 2)] field 3 (field 4) (field 6)

$> test_string="[field 1 (field 2)] field 3 (field 5) (field 6)"
$> sed -E 's/^(.*)\([^)]*\) (\([^)]*\))$//' <<< "$test_string"
[field 1 (field 2)] field 3 (field 6)

sed 命令使用正则表达式从输入中删除第 (last -1) 个 (...) 值。