在Bash脚本中返回正则表达式匹配项,而不是替换它。

34
我只是想在Bash脚本中匹配一些文本。我尝试使用sed,但似乎无法仅输出匹配项,而不是将其替换为其他内容。
echo -E "TestT100String" | sed 's/[0-9]+/dontReplace/g'

将输出TestTdontReplaceString

这不是我想要的,我希望它输出100

理想情况下,它会将所有匹配项放入一个数组中。

编辑:

文本输入以字符串形式输入:

newName()
{
 #Get input from function
 newNameTXT="$1"

 if [[ $newNameTXT ]]; then
 #Use code that im working on now, using the $newNameTXT string.

 fi
}
9个回答

58

你可以使用双方括号 [[ ]] 测试运算符,在 Bash 中纯粹地实现这一点,它会将结果存储在一个名为 BASH_REMATCH 的数组中:

[[ "TestT100String" =~ ([0-9]+) ]] && echo "${BASH_REMATCH[1]}"

11
这需要一个真正的猴子才能想明白。 - Tegra Detra
1
但是请参考https://dev59.com/QnVC5IYBdhLWcg3wqzLV,了解在不同的BASH版本中使用bash引用的问题。 - Jake Biesinger

41
echo "TestT100String" | sed 's/[^0-9]*\([0-9]\+\).*/\1/'

echo "TestT100String" | grep -o  '[0-9]\+'

将结果放入数组中的方法在一定程度上取决于实际数据的检索方式。您的问题中没有足够的信息来指导您,但是这里有一种方法:

index=0
while read -r line
do
    array[index++]=$(echo "$line" | grep -o  '[0-9]\+')
done < filename

以下是另一种方法:

array=($(grep -o '[0-9]\+' filename))

在原问题中添加了输入方法(其输入形式为字符串)。 - Mint

31

Bash实现。使用参数替换(无需额外进程和管道):

string="TestT100String"

echo ${string//[^[:digit:]]/}

去除所有非数字字符。


9

我知道这是一个旧话题,但我通过同样的搜索来到这里,并发现另一个很棒的选择是在字符串/变量上使用grep应用正则表达式:

# Simple
$(echo "TestT100String" | grep -Po "[0-9]{3}")
# More complex using lookaround
$(echo "TestT100String" | grep -Po "(?i)TestT\K[0-9]{3}(?=String)")

使用环视功能可以扩展搜索表达式以实现更好的匹配。其中(?i)表示搜索模式之前的模式(向前环视),\K表示实际搜索模式,(?=)包含搜索后面的模式(向后环视)。
给定的示例与PCRE正则表达式TestT([0-9]{3})String匹配相同。
链接:https://www.regular-expressions.info/lookaround.html

哇,真不敢相信人们在10年后仍然来到这里。当我提问时,我从未想过它会被这么多人查看。当时我以为只有我一个人不知道如何做。 - Mint
1
Bash太糟糕了,以至于有人一直在寻找这样的事情。 - i30817

4

使用grep命令。Sed是一种编辑器。如果您只想匹配正则表达式,那么grep就足够了。


SED不会写入源文件 - 唯一的方法是使用相同的文件名编写输出以覆盖文件。 - OMG Ponies
1
真的,但sed仍然是一个编辑器。它的名字甚至缩写为流编辑器。如果他只需要匹配,他可以使用grep。 - Mic
1
我不认为他想要匹配。他说他需要那100个数。 - ghostdog74
1
所以使用grep的-o参数应该可以完成任务。 - ghostdog74
是的,我需要那个100%的工作解决方案,感谢你们(尤其是Dennis)。 - Mint
1
我同意,只是应该说:SED已经足够了,而grep则是足够的 :) - Yuval

1
使用 awk
linux$ echo -E "TestT100String" | awk '{gsub(/[^0-9]/,"")}1'
100

1

我不知道为什么没有人使用expr:它是可移植且易于使用的。

newName()
{
 #Get input from function
 newNameTXT="$1"

 if num=`expr "$newNameTXT" : '[^0-9]*\([0-9]\+\)'`; then
  echo "contains $num"
 fi
}

0

嗯,使用 s/"pattern1"/"pattern2"/g 的 Sed 只是全局替换所有的 pattern1 为 pattern2。

除此之外,默认情况下,sed 会打印整行内容。我建议将指令传输到 cut 命令中,尝试提取您想要的数字:

如果您只想使用 sed,则使用 TRE:

sed -n 's/.*\(0-9\)\(0-9\)\(0-9\).*/\1,\2,\3/g'.

我没有尝试执行上面的命令,所以请确保语法正确。 希望这有所帮助。


-1

仅使用Bash shell

declare -a array
i=0
while read -r line
do
        case "$line" in
            *TestT*String* )
            while true
            do
                line=${line#*TestT}
                array[$i]=${line%%String*}
                line=${line#*String*}
                i=$((i+1))
                case "$line" in
                    *TestT*String* ) continue;;
                    *) break;;
                esac
            done
            esac
done <"file"
echo ${array[@]}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接