web-dev-qa-db-fra.com

Supprimer un préfixe / suffixe fixe d'une chaîne dans Bash

Dans mon script bash, j'ai une chaîne et son préfixe/suffixe. Je dois supprimer le préfixe/suffixe de la chaîne d'origine.

Par exemple, supposons que j'ai les valeurs suivantes:

string="hello-world"
prefix="hell"
suffix="ld"

Comment puis-je arriver au résultat suivant?

result="o-wor"
405
$ foo=${string#"$prefix"}
$ foo=${foo%"$suffix"}
$ echo "${foo}"
o-wor
593

Utilisation de sed:

_$ echo "$string" | sed -e "s/^$prefix//" -e "s/$suffix$//"
o-wor
_

Dans la commande sed, le caractère _^_ correspond au texte commençant par _$prefix_, et le point final _$_ correspond au texte se terminant par _$suffix_.

Adrian Frühwirth fait quelques bons points dans les commentaires ci-dessous, mais sed peut être très utile à cet effet. Le fait que sed interprète les contenus de $ prefix et $ suffix peut être bon OR mauvais- tant que vous y prêtez attention, tout va bien. La beauté est, vous pouvez faire quelque chose comme ça:

_$ prefix='^.*ll'
$ suffix='ld$'
$ echo "$string" | sed -e "s/^$prefix//" -e "s/$suffix$//"
o-wor
_

ce qui peut être ce que vous voulez, et est à la fois plus sophistiqué et plus puissant que la substitution variable bash. Si vous vous souvenez que, avec un grand pouvoir, de grandes responsabilités (comme le dit Spiderman), ça devrait aller.

Vous trouverez une brève introduction à sed à l’adresse http://evc-cit.info/cit052/sed_tutorial.html

Une note concernant le Shell et son utilisation de chaînes:

Pour l'exemple donné, les éléments suivants fonctionneraient également:

_$ echo $string | sed -e s/^$prefix// -e s/$suffix$//
_

... mais uniquement parce que:

  1. echo ne se soucie pas du nombre de chaînes dans sa liste d'arguments, et
  2. Il n'y a pas d'espaces dans $ prefix et $ suffix

Il est généralement recommandé de citer une chaîne sur la ligne de commande, car même si elle contient des espaces, elle sera présentée à la commande sous la forme d'un argument unique. Nous citons $ prefix et $ suffix pour la même raison: chaque commande de modification à sed sera transmise sous la forme d'une chaîne. Nous utilisons des guillemets doubles car ils permettent une interpolation variable; Si nous avions utilisé des guillemets simples, la commande sed aurait obtenu les valeurs littérales _$prefix_ et _$suffix_, ce qui n'est certainement pas ce que nous voulions.

Remarquez aussi mon utilisation de guillemets simples lors de la définition des variables prefix et suffix. Nous ne voulons certainement pas que les chaînes soient interprétées. Nous les citons donc seules afin d'éviter toute interpolation. Encore une fois, cela n’est peut-être pas nécessaire dans cet exemple, mais c’est une très bonne habitude à prendre.

76
Chris Kolodin

Connaissez-vous la longueur de votre préfixe et suffixe? Dans ton cas:

result=$(echo $string | cut -c5- | rev | cut -c3- | rev)

Ou plus général:

result=$(echo $string | cut -c$((${#prefix}+1))- | rev | cut -c$((${#suffix}+1))- | rev)

Mais le solution d'Adrian Frühwirth est vraiment cool! Je ne savais pas à ce sujet!

15
tommy.carstensen

J'utilise grep pour supprimer les préfixes des chemins (qui ne sont pas bien gérés par sed):

echo "$input" | grep -oP "^$prefix\K.*"

\K supprime de la correspondance tous les caractères précédents.

14
$ string="hello-world"
$ prefix="hell"
$ suffix="ld"

$ #remove "hell" from "hello-world" if "hell" is found at the beginning.
$ prefix_removed_string=${string/#$prefix}

$ #remove "ld" from "o-world" if "ld" is found at the end.
$ suffix_removed_String=${prefix_removed_string/%$suffix}
$ echo $suffix_removed_String
o-wor

Remarques:

# $ préfixe: ajouter # permet de s'assurer que la sous-chaîne "hell" est supprimée uniquement si elle est trouvée au début. % $ suffixe: ajouter% permet de s'assurer que la sous-chaîne "ld" est supprimée uniquement si elle se trouve dans end.

Sans cela, les sous-chaînes "hell" et "ld" seront supprimées partout, même si elles se trouvent au milieu.

7
Vijay Vat

Solution petite et universelle:

expr "$string" : "$prefix\(.*\)$suffix"
6
Tosi Do

Utilisation de l'opérateur =~) :

$ string="hello-world"
$ prefix="hell"
$ suffix="ld"
$ [[ "$string" =~ ^$prefix(.*)$suffix$ ]] && echo "${BASH_REMATCH[1]}"
o-wor
5

En utilisant @Adrian Frühwirth, répondez:

function strip {
    local STRING=${1#$"$2"}
    echo ${STRING%$"$2"}
}

l'utiliser comme ça

HELLO=":hello:"
HELLO=$(strip "$HELLO" ":")
echo $HELLO # hello
5
math2001