web-dev-qa-db-fra.com

Comment utiliser des modèles dans l'instruction case dans un script bash?

La page man indique que les instructions case utilisent "un modèle d'extension de nom de fichier correspondant".
Je veux généralement avoir des noms abrégés pour certains paramètres, alors je vais:

case $1 in
    req|reqs|requirements) TASK="Functional Requirements";;
    met|meet|meetings) TASK="Meetings with the client";;
esac

logTimeSpentIn "$TASK"

J'ai essayé des modèles tels que req* ou me{e,}t qui, à mon sens, se développeraient correctement pour correspondre à ces valeurs dans le contexte de l'expansion du nom de fichier, mais cela ne fonctionne pas.

57
Ramiro Rela

L'expansion d'accolade ne fonctionne pas, mais *, ? et [] le sont. Si vous définissez shopt -s extglob, vous pouvez également utiliser extended pattern matching :

  • ?() - zéro ou une occurrence de motif
  • *() - zéro ou plusieurs occurrences de modèle
  • +() - une ou plusieurs occurrences de modèle
  • @() - une occurrence de motif
  • !() - tout sauf le motif

Voici un exemple:

shopt -s extglob
for arg in Apple be cd meet o mississippi
do
    # call functions based on arguments
    case "$arg" in
        a*             ) foo;;    # matches anything starting with "a"
        b?             ) bar;;    # matches any two-character string starting with "b"
        c[de]          ) baz;;    # matches "cd" or "ce"
        me?(e)t        ) qux;;    # matches "met" or "meet"
        @(a|e|i|o|u)   ) fuzz;;   # matches one vowel
        m+(iss)?(ippi) ) fizz;;   # matches "miss" or "mississippi" or others
        *              ) bazinga;; # catchall, matches anything not matched above
    esac
done
115
Dennis Williamson

Je ne pense pas que vous puissiez utiliser des accolades.

Selon le manuel de Bash concernant le cas dans Constructions conditionnelles .

Chaque pattern subit un tilde expansion, expansion des paramètres, substitution de commande et arithmétique expansion.

Rien sur Brace Expansion malheureusement.

Il faudrait donc faire quelque chose comme ça:

case $1 in
    req*)
        ...
        ;;
    met*|meet*)
        ...
        ;;
    *)
        # You should have a default one too.
esac
35
plundra

if et grep -E solution plus portable

Pour la portabilité, je vous recommande d’utiliser uniquement les instructions if et grep -E qui prennent en charge les expressions régulières étendues , par exemple:

arg='abc'
if echo "$arg" | grep -Eq 'a.c|d.*'; then
  echo 'first'
Elif echo "$arg" | grep -Eq 'a{2,3}'; then
  echo 'second'
fi

POSIX 7

Bash semble suivre POSIX par défaut sans shopt comme mentionné par https://stackoverflow.com/a/4555979/895245

Voici la citation: http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_01 section "Case Conditional Construct":

Le cas de construction conditionnel doit exécuter la liste composée correspondant au premier de plusieurs modèles (voir Notation de correspondance de modèle) [...] Plusieurs modèles avec la même liste composée doivent être délimités par le caractère '|' symbole. [...]

Le format de la construction de cas est le suivant:

case Word in
     [(] pattern1 ) compound-list ;;
     [[(] pattern[ | pattern] ... ) compound-list ;;] ...
     [[(] pattern[ | pattern] ... ) compound-list]
  esac

et ensuite http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_13 section "2.13. Notation de correspondance de modèle" ne mentionne que ?, * et [].