Encontre a string enquanto conhece parte dela e retorne a string

9

Eu tenho uma string, por exemplo

"Icecream123 AirplaneBCD CompanyTL1 ComputerYU1"

Digamos que eu saiba que minha string conterá com certeza a substring IceCream, mas não sei o que segue.

Pode ser 123, como no meu exemplo, ou pode ser algo diferente.

Embora eu possa usar grep para detectar se a substring "Icecream" existe na minha string com o seguinte comando

echo $string | grep -oF 'Icecream';

Qual irá imprimir

Icecream

Eu quero com um comando para fazê-lo imprimir toda a substring, que no meu exemplo é

Icecream123

É claro que o sorvete a seguir é aleatório e desconhecido antes, então não posso fazer

$SUBSTRING=$(echo $string | grep -oF 'Icecream')
$SUBSTRINGTRAIL=123
echo $SUBSTRING$SUBSTRINGTRAIL
Sonamor
fonte
a substring é fixa / estática - sempre "Sorvete" ou é variável?
Jeff Schaller
um espaço indicará o fim do sufixo desejado?
Jeff Schaller
@JeffSchaller Infelizmente, eu não sei disso. Na verdade, estou recebendo uma saída multilinha de outro comando, que eu armazeno em uma variável, essa variável é minha string $, quando é exibida, ela exibe a saída multilinha como uma linha de sinalização com um espaço entre elas. Na verdade, não sei se esse é um espaço ou um caractere especial como LF. Eu pensei que é espaço.
Sonamor
Quero dizer, por exemplo, Icecream123 AirplaneBCDvocê quer parar às 123. Isso é porque existe um espaço depois do 3, ou algo mais?
Jeff Schaller
1
Se você não tiver certeza de quais são seus dados, é difícil escrever uma solução apropriada. Até agora, todas as respostas estão assumindo que seus dados estão em uma linha, como você mostrou. Eu estava tentando descobrir qual era o seu delimitador - onde a parte "à direita" deveria parar.
Jeff Schaller

Respostas:

15

Se você grepsuporta expressões regulares compatíveis com perl, você pode corresponder não avidamente ao limite da próxima palavra:

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

Caso contrário, corresponda à sequência mais longa de caracteres não em branco:

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

Ou mantenha tudo no shell e remova a maior sequência de caracteres à direita, começando com um espaço:

echo "${string%% *}"
chave de aço
fonte
2
Para o PCRE, eu usaria 'Icecream\S+'para alguns caracteres não em branco.
Glenn Jackman
Obrigado por seus comentários, infelizmente, parece que minha versão do grep não suporta perl regex. Você poderia adicionar mais alguns detalhes sobre sua terceira opção? Não tenho muita certeza de como implementá-lo.
Sonamor
Depois de mais alguns testes, parece que usando o eco "$ string" | grep -oP 'Sorvete. *? \ b' ou 'Sorvete \ S +' faz o trabalho. Obrigado
Sonamor
é realmente confuso que, embora sua variável $ string seja uma string, você ainda precise colocá-la entre aspas duplas!
Sonamor
@ Sonamor, neste caso, a citação não é estritamente necessária; no entanto, existem muitos casos em que é um bom hábito entrar. Veja, por exemplo, quando é necessária a citação dupla?
steeldriver
7

Usando um grepque sabe sobre -o:

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

O padrão \<Icecream[^[:blank:]]*corresponde à sequência Icecream(onde Ié precedida por um caractere que não é palavra ou o início da linha), seguida por zero ou mais espaços em branco (não espaços ou tabulações).


Usando awk:

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

O awkprograma divide a sequência em registros separados por espaço e testa cada um. Irá imprimir os que começam com a sequência Icecream.

Usando mawkou GNU awk, você também pode usar

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

pois eles se interpõem RScomo uma expressão regular se contiver mais de um caractere.


Com sed, de maneira semelhante a grep:

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

Usando /bin/sh:

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

Perl (com uma pequena ajuda de tr):

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

ou apenas

$ printf '%s\n' "$string" | perl -ne '/(Icecream\S*)/ && print $1, "\n"'
Icecream123
Kusalananda
fonte
Ou, dividida em linhas e combinar a chave:echo "$string" | grep -o '\S\+' | grep "Icecream"
Isaac
7

Desde que você marcou bash:

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

De maneira mais geral, para um termo de pesquisa em $search:

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

... ou com expansão de parâmetro:

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

# remove any trailing space onwards
result=$search${x%% *}
Jeff Schaller
fonte
2

Por exemplo, se você usar GNU grep:

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

Ele usa PCRE.

Arkadiusz Drabczyk
fonte
1

Um pouco mais simples, talvez, especialmente porque você diz que sua versão do grep não suporta perl regex:

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

O trdivide a sequência em linhas, substituindo todos os espaços por novas linhas. Então você pode usar grepfacilmente.

Você também pode escrever o seguinte para obter apenas o que segue a palavra que você está procurando:

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

Lei29
fonte