Meilleure façon de faire “echo $ x | sed… ”et“ echo $ x | grep… ”


14

Je trouve souvent cela dans les scripts (et, je dois l'admettre, je l'écris moi-même):

a=$(echo "$x" | sed "s/foo/bar/")

ou

if echo "$x" | grep -q foo
then
    ...
fi

Considérez "foo" pour inclure des trucs regex.

Je pense qu'il devrait y avoir - et très probablement est - une meilleure façon de formuler ce, qui ne comporte pas deux commandes et un tuyau , mais enveloppe la chose dans une expression plus compacte.

Je ne le trouve pas. N'importe qui?


Je m'attends à ce que cette expression soit fréquemment utilisée en raison d'une combinaison d'ignorance (ne pas connaître d'alternatives) et de maintenabilité (connaître des alternatives mais choisir celle-ci comme la plus simple à comprendre). Je peux dire en un coup d'œil ce que font vos exemples, mais j'ai besoin d'une référence shell pour trouver les alternatives dans les réponses de grawity et Dan McG.
— Quack Quichote

3
Soit dit en passant, la méthode préférée pour effectuer la substitution de commandes est $()plutôt que les raccourcis.
— pause jusqu'à nouvel ordre.

2
C'est aussi une bonne idée de citer des extensions pour que les espaces blancs soient protégés: a="$(echo "$x" | sed "s/foo/bar/")"et if echo "$x" | grep foo; ….
— Chris Johnsen

Bonnes remarques sur le $ () vs ``. Je vois que mes compétences de bash ne sont pas encore géniales.
— DevSolar

Réponses:


12

À moins que vous ne supposiez un shell spécifique, il n'y a pas de meilleur moyen de le faire que de "faire écho à l'outil" (ou simplement un "outil" lui-même comme expr ); c'est tout ce sur quoi vous pouvez vraiment compter avec le shell Bourne traditionnel et / ou le shell POSIX . Si vous envisagez d'autres coquilles, il existe d'autres possibilités intégrées.

ksh a

  • modèles supplémentaires: ?(pattern-list), *(pattern-list), {n}(pattern-list), {n,m}(pattern-list), @(pattern-list), !(pattern-list);
  • le spécificateur %P printf pour convertir une expression régulière étendue en motif (et %Rpour l'expression régulière étendue en motif);
  • l' expr == patternétat dans les [[ expr ]]tests;
  • l' ${param/pattern/replacement}expansion des paramètres.

bash a

  • l' extgloboption d'activer la plupart des modèles supplémentaires de ksh (non {n}et {n,m});
  • l' expr == patternétat (lors des [[ expr ]]tests);
  • l' ${param/pattern/replacement}expansion des paramètres;
  • (dans les versions plus récentes) la expr =~ extregexpcondition (dans les [[ expr ]]tests) qui peut correspondre aux expressions régulières étendues
    • avec des sous-expressions entre parenthèses et le BASH_REMATCHparamètre, des remplacements de style sed pourraient être effectués.

zsh a

  • ses propres modèles étendus avec l' EXTENDED_GLOBoption;
  • modèles étendus de type ksh avec l' KSH_GLOBoption;
  • l' expr == patternétat (lors des [[ expr ]]tests);
  • l' ${pattern/pattern/replacement}expansion des paramètres;
  • la expr =~ extregexpcondition (dans les [[ expr ]]tests) qui peut correspondre à des expressions régulières étendues,
    • il peut utiliser PCRE au lieu d'expressions régulières étendues simples si l'option RE_MATCH_PCRE est définie,
    • avec des sous-expressions entre parenthèses, le MATCHparamètre et le matchparamètre (ou BASH_REMATCHavec l' BASH_REMATCHensemble d'options), des remplacements de style sed pourraient être effectués;
  • le zsh/pcremodule qui offre pcre_compile, pcre_studyet les pcre_matchcommandes et la condition de -pcre-match test (dans les [[ expr ]]tests);
  • le zsh/regexmodule qui offre la condition de -regex-match test (en [[ expr ]]tests).

Sensationnel. Aussi complet que l'on pourrait souhaiter. Certainement un gagnant.
— DevSolar

6

Pour remplacer la ligne sed, faites quelque chose comme

${a/foo/bar} ou ${a//foo/bar}

Dans le premier formulaire, seule la première instance est remplacée. Le deuxième formulaire est une recherche globale et remplacer.

Dans votre cas, ce serait

Au lieu de:

if echo $x | grep foo
then
    ...
fi

Pensez à utiliser:

if [ $x =~ foo ]
then
    ...
fi

Où fooest une expression régulière.


Dans quels obus cela fonctionne-t-il?
— Peltier

1
if [ $x =~ foo ]donne un message d'erreur ici. if [[ $x =~ foo ]], cependant, fonctionne très bien. Merci!
— DevSolar

1
Ce sont tous des bashismes, ils ont besoin de bash. De plus, =~nécessite bash> = 3 iirc.
— ℝaphink

1
Iirc également, foo n'est pas une expression régulière (comme dans PCRE) dans ces exemples, mais utilise des caractères génériques. Il y a plus de ces qualités bash dans la page de manuel bash, section "Expansion des paramètres". J'apprécie particulièrement des choses comme ${a##foo}et ${a%%bar}.
— ℝaphink

3
L'opérateur de =~correspondance utilise des expressions régulières. C'est vrai, par exemple: [[ "abcdddde" =~ ^a.*d+.g* ]](c'est zéro ou plus de g plutôt que g-joker, par exemple).
— pause jusqu'à nouvel ordre.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.