bash: Comment utiliser plusieurs manipulations de chaînes (expansion de paramètres) en une seule étape?

Aug 15 2020

J'ai string=substr1-substr2-substr3.substr4où les sous-chaînes sont de longueur variable. Je veux extraire substr3de stringet je pense à le faire en utilisant les ${string##pattern}et ${string%pattern}extensions de manipulation de chaînes. En utilisant cette approche, il est clair que je dois exécuter ${string##*-}et exécuter ${string%.*}l'extension résultante, ou vice versa. Mes questions sont:

  1. est-ce le meilleur choix?
  2. Si oui, comment exécuter les deux en une seule étape? Quand j'essaye de faire quelque chose comme ${string##*-${string%.*}}ou ${string%.*${string##*-}}je récupère juste la chaîne complète. Je me rends compte que je pourrais toujours faire l'extraction en deux étapes en attribuant une variable intermédiaire au résultat de la première étape, puis en la manipulant; mais je veux le faire en une seule étape. Comment dois-je procéder?

TIA!

Réponses

2 ilkkachu Aug 15 2020 at 20:39

Donné

string=substr1-substr2-substr3.substr4

${string%.*} est

substr1-substr2-substr3

alors, ${string##*-${string%.*}}est

${string##*-substr1-substr2-substr3}

ce qui signifie supprimer dès le début de stringtout ce qui va jusqu'à et y compris -substr1-substr2-substr3. Mais il n'y a pas de telle sous-chaîne string, car il n'y a pas de tiret devant substr1, vous obtenez donc la chaîne d'origine.

Ce que vous voulez probablement, c'est

string=substr1-substr2-substr3.substr4
result="${string%.*}" result="${result##*-}"

ce qui conduit à resultcontaing substr3.

Dans Zsh, vous pouvez le faire en une seule étape:, mais cela ne fonctionne pas dans Bash.result=${${string%.*}##*-}

Dans Bash, vous êtes limité à l'utilisation d'extensions sur le côté droit de #ou %, et cela ne vous aide pas ici car vous devez supprimer des parties à la fois du début et de la fin de la chaîne.


Sinon, si $stringne contient pas de caractères de nouvelle ligne, vous pouvez utiliser

IFS=.- read -r a b c d <<< "$string"

et lire substr3à partir de c.

Dans ce cas, en fonction du shell et de la taille de la chaîne, le contenu de $stringsera soit stocké dans un fichier temporaire, soit transmis via un tube qui readlira la première ligne et la divisera en fonction de $IFS.