web-dev-qa-db-fra.com

Rechercher une chaîne tout en en connaissant une partie et renvoyer

J'ai une chaîne, par exemple

"Icecream123 AirplaneBCD CompanyTL1 ComputerYU1"

Disons que je sais que ma chaîne contiendra à coup sûr la sous-chaîne IceCream mais je ne sais pas ce qui la suit.

Ce pourrait être 123 comme dans mon exemple ou ce pourrait être quelque chose de différent.

Bien que je puisse utiliser grep pour détecter si la sous-chaîne "Icecream" existe dans ma chaîne avec la commande suivante

echo $string | grep -oF 'Icecream';

Qui va imprimer

Icecream

Je veux avec une commande pour l'obtenir pour imprimer la sous-chaîne entière, qui dans mon exemple est

Icecream123

Bien sûr, ce qui suit Icecream est aléatoire et n'est pas connu à l'avance, donc je ne peux pas simplement faire

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

Si votre grep prend en charge les expressions régulières compatibles Perl, vous pouvez faire correspondre sans avidité jusqu'à la prochaine limite de Word:

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

Sinon, faites correspondre la séquence la plus longue de caractères non vides:

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

Ou conservez tout dans le Shell et supprimez la séquence de caractères la plus longue commençant par un espace:

echo "${string%% *}"
15
steeldriver

Utilisation d'un grep qui connaît -o:

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

Le motif \<Icecream[^[:blank:]]* correspond à la chaîne Icecream (où I est précédé d'un caractère non Word ou du début de la ligne) suivi de zéro ou plusieurs espaces non (pas d'espaces ni de tabulations) .


Utilisation de awk:

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

Le programme awk divise la chaîne en enregistrements séparés par des espaces et teste chacun d'eux. Il affichera ceux qui commencent par la chaîne Icecream.

En utilisant mawk ou GNU awk, vous pouvez également utiliser

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

car ils interprètent RS comme une expression régulière si elle contient plusieurs caractères.


Avec sed, de la même manière qu'avec grep:

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

En utilisant /bin/sh:

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

Perl (avec un peu d'aide de tr):

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

ou juste

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

Depuis que vous avez marqué bash:

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

Plus généralement, pour un terme de recherche dans $search:

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

... ou avec extension des paramètres:

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

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

Par exemple, si vous utilisez GNU grep:

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

Il utilise PCRE.

2

Un peu plus simple peut-être, d'autant plus que vous dites que votre version de grep ne prend pas en charge l'expression régulière Perl:

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

tr divise la chaîne en lignes en remplaçant tous les espaces par des retours à la ligne. Ensuite, vous pouvez facilement utiliser grep.

Vous pouvez également écrire ce qui suit pour obtenir uniquement ce qui suit le mot que vous recherchez:

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

1
Law29