Convertir un script bash en utilisant des expressions rationnelles pour sh

J’ai vraiment du mal à écrire un script shell Bourne. Fondamentalement, j’ai trois formats d’entrée pour une variable appelée “ref” que j’essaie de détecter:

  1. ref = “refs / head /.*” (c’est à dire commence par “refs / head /” Je suis intéressé par le bit à la fin, après la barre oblique)
  2. ref = “refs / tags /.*” (c’est à dire commence par “refs / tags /” Je suis intéressé par le bit à la fin, après la barre oblique)
  3. tout le rest (c’est-à-dire ignorer tout ce qui ne commence pas par “refs / head /” ou “refs / tags /”)

Par exemple,

Si ref = “refs / head / master”, définissez TAG = “master”

Si ref = “refs / tags / 0.2.4”, définissez TAG = “0.2.4”

Pour tout le rest, définissez TAG = “”

Maintenant, j’ai écrit quelque chose dans shell bash, mais j’ai vraiment du mal à le convertir en Bourne (#! / Bin / sh):

#!/bin/bash # #This works! # TAG="" re='^refs/head/.*' #regex: begins with refs/head/, ends with anything re2='^refs/tags/.*' #regex: begins with refs/tags/, ends with anything if [[ $ref =~ $re ]]; then #do nothing - OK true #NOP else #check if it's a tag update if [[ $ref =~ $re2 ]]; then TAG=${$ref##*/} #looks worse that it is: http://stackoverflow.com/questions/3162385/how-to-split-a-ssortingng-in-shell-and-get-the-last-field fi exit 0 fi echo $TAG 

Il m’a fallu des années pour: a) écrire ce programme et b) découvrir pourquoi mon programme devenait fou – il s’est avéré que j’avais besoin de #! / Bin / sh et non #! / Bin / bash

Comment puis-je convertir cela en sh? Peut-être que quelqu’un d’autre a une solution plus élégante à ma gymnastique regex?


Mettre à jour:

Merci pour les réponses sofar (surtout @gboffi). Je pense que je suis presque là.

Tout ce dont j’ai besoin maintenant, c’est de savoir si $ TAG provient de “refs / head /”, “refs / tags /” ou ni l’un ni l’autre. J’ai essayé de modifier certaines des réponses, mais j’ai vraiment du mal avec sh. Je dois partir et en apprendre plus sur sh à partir des premiers principes au lieu d’essayer de le pirater.

Mise à jour 2:

Donc, après une nuit de sumil, j’ai compris en 20 minutes environ. Voici ma solution:

 #!/bin/sh ref="refs/asdf/master" TAG="" TAG="${ref#refs/heads/}" if [ "$ref" != "${ref#refs/heads/}" ]; then echo "heads" echo $TAG else TAG="${ref#refs/tags/}" if [ "$ref" != "${ref#refs/tags/}" ]; then echo "heads" echo $TAG else TAG="" fi fi echo "--->$TAG" 

Je suis sûr qu’il existe une solution beaucoup plus élégante. mais je n’ai tout simplement pas le temps!

Vous pouvez utiliser rev-parse pour cela, voici quelques exemples provenant de l’un de mes référentiels. Notez que le dernier ne produit aucune sortie, comme vous le souhaitez.

 $ git rev-parse --abbrev-ref refs / chefs / maitre
 maîsortingser

 $ git rev-parse --abbrev-ref refs / tags / 5
 5

 $ git rev-parse --abbrev-ref @ ^

Ici c’est une fonction, définie en dash (la version Linux de sh )

 % dash $ tag() { > TAG="" > [ "$1" != "${1#refs/head/}" ] && TAG="${1#refs/head/}" > [ "$1" != "${1#refs/tags/}" ] && TAG="${1#refs/tags/}" > echo "$TAG" >} $ tag poldo $ tag refs/head/poldo poldo $ tag refs/tags/pippo pippo $ tag to093u0refs/head/poldo $exit % 

Le moyen le plus idiomatique de gérer cela est d’utiliser une déclaration de cas et une correspondance de modèle:

 #!/bin/sh case $ref in refs/head/*) true ;; # original behavior: no output, success refs/tags/*) printf '%s\n' "${ref##*/}" ;; # original behavior: emit output *) false # exit with an error # original code didn't specify behavior esac 

La raison pour laquelle je quitte avec une erreur dans le cas où ni refs/head/* ni refs/tags/* correspond est que si vous voulez quitter avec succès dans ce cas, vous pouvez omettre complètement le test refs/head/* .

Après avoir lu votre description de la fonction souhaitée, il semble que cela se résume à ceci:

  1. vérifiez l’argument d’entrée. Si cela commence par refs / head ou refs / master, continuez, sinon arrêtez.
  2. prenez la partie terminale de l’information et définissez la variable TAG sur celle-ci.

ainsi, en supposant que votre entrée est dans la variable REF,

 TAG="" echo $REF | egrep -q 'refs/head|refs/master' if [ $? -eq 0 ] then TAG=`echo $REF | sed "s/.*\///"` fi 

doit le faire.

(Note latérale pour les têtes de shell: basename est-il une meilleure solution que sed dans ce cas particulier?)