在知道字符串的一部分的情况下查找字符串并返回字符串


9

例如,我有一个字符串

"Icecream123 AirplaneBCD CompanyTL1 ComputerYU1"

假设我知道我的字符串肯定包含子字符串IceCream,但我不知道它后面是什么。

在我的示例中,它可能是123,或者可能有所不同。

虽然我可以使用grep通过以下命令来检测字符串中是否存在“ Icecream”子字符串

echo $string | grep -oF 'Icecream';

哪个会打印

Icecream

我想要一个命令来打印整个子字符串,在我的示例中是

Icecream123

当然,冰淇淋发生后的情况是随机的,并且事先未知,所以我不能做

$SUBSTRING=$(echo $string | grep -oF 'Icecream')
$SUBSTRINGTRAIL=123
echo $SUBSTRING$SUBSTRINGTRAIL

子字符串是固定的还是静态的-始终是“ Icecream”,还是可变的?
杰夫·谢勒

空格会指示所需后缀的结尾吗?
杰夫·谢勒

@JeffSchaller可悲的是,我不知道。我实际上是从另一个命令获取多行输出,该命令存储在一个变量中,该变量是我的$ string,当它被回显时,它将多行输出显示为标线,它们之间有一个空格。我实际上不知道这是空格还是LF等特殊字符。我以为是空间。
Sonamor

我的意思是,例如,Icecream123 AirplaneBCD您想在停留123。是因为3后面有空格,还是其他?
杰夫·

1
如果不确定数据是什么,很难编写适当的解决方案。到目前为止,所有答案都假设您的数据在一行上,就像您显示的一样。我试图弄清楚您的分隔符是什么,即“尾随”部分应在哪里停止。
杰夫·谢勒

Answers:


15

如果您grep支持与perl兼容的正则表达式,则可以非贪婪地匹配到下一个单词边界:

echo "$string" | grep -oP 'Icecream.*?\b'

否则,请匹配最长的非空白字符序列:

echo "$string" | grep -o 'Icecream[^[:blank:]]*'

或者将所有内容保留在外壳中,并删除以空格开头的最长尾随字符序列:

echo "${string%% *}"

2
对于PCRE,我将使用'Icecream\S+'一些非空白字符。
格伦·杰克曼(Glenn jackman)

感谢您的评论,可悲的是,我的grep版本似乎不支持perl regex。您能否添加有关第三个选项的更多详细信息?我不太确定如何实施。
Sonamor

经过更多测试后,似乎可以使用echo“ $ string” | grep -oP'Icecream。*?\ b'或'Icecream \ S +'即可完成工作。谢谢
Sonamor

确实令人困惑,尽管$ string变量是一个字符串,但仍然必须将其放在双引号之间!
Sonamor

在这种情况下,@ Sonamor并非必须引用;但是,在很多情况下,这一个很好的习惯。例如参见何时需要双引号?
steeldriver

7

使用grep会知道-o

$ printf '%s\n' "$string" | grep -o '\<Icecream[^[:blank:]]*'
Icecream123

图案\<Icecream[^[:blank:]]*匹配字符串Icecream(其中I由非文字字符,或行的开始之前),接着是零个或多个非空白(不空格或制表符)。


使用awk

$ printf '%s\n' "$string" | awk -v RS=' ' '/^Icecream/'       
Icecream123

awk程序将字符串分成以空格分隔的记录,并测试每个记录。它将打印以字符串开头的字符串Icecream

使用mawk或GNU awk,您也可以使用

printf '%s\n' "$string" | awk -v RS='[[:blank:]]' '/^Icecream/'

因为它们RS包含多个字符,所以它们作为正则表达式交织在一起。


sed,使用方式类似grep

$ printf '%s\n' "$string" | sed 's/.*\(\<Icecream[^[:blank:]]*\).*/\1/'
Icecream123

使用/bin/sh

set -- Icecream123 AirplaneBCD CompanyTL1 ComputerYU1
for string; do
    case $string in
        Icecream*)
            printf '%s\n' "$string"
            break
    esac
done

Perl(在的帮助下tr):

$ printf '%s\n' "$string" | tr ' ' '\n' | perl -ne '/Icecream\S*/ && print'
Icecream123

要不就

$ printf '%s\n' "$string" | perl -ne '/(Icecream\S*)/ && print $1, "\n"'
Icecream123

或者,分成几行并匹配密钥:echo "$string" | grep -o '\S\+' | grep "Icecream"
艾萨克(Isaac)

7

由于您标记了bash:

[[ $string =~ (Icecream[^ ]*) ]] && result=${BASH_REMATCH[1]}

更一般而言,对于以下搜索字词$search

[[ $string =~ ($search[^ ]*) ]] && result=${BASH_REMATCH[1]}

...或使用参数扩展:

# remove any leading text up to -and through- the search text:
x=${string##*$search}

# remove any trailing space onwards
result=$search${x%% *}

2

例如,如果您使用GNU grep

$ echo "Icecream123 AirplaneBCD CompanyTL1 ComputerYU1" | grep -oP '\bIcecream.*?(\s|$)' --color

它使用PCRE


1

也许更简单一些,尤其是因为您说您的grep版本不支持perl regex:

$ echo $string | tr ' ' '\n' | grep 'Icecream' Icecream123

tr分裂与换行符替换所有的空格串入行。然后,您可以grep轻松使用。

您还可以编写以下代码,以仅获取要查找的单词之后的内容:

$ echo $string | tr ' ' '\n' | sed -n 's/Icecream//p' 123

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.