En bash, comment puis-je vérifier si une chaîne commence par une valeur?

Je voudrais vérifier si une chaîne commence par “node” par exemple “node001”. Quelque chose comme

if [ $HOST == user* ] then echo yes fi 

Comment puis-je le faire correctement?


Je dois en outre combiner des expressions pour vérifier si HOST est soit “user1” ou commence par “node”

 if [ [[ $HOST == user1 ]] -o [[ $HOST == node* ]] ]; then echo yes fi > > > -bash: [: too many arguments 

Comment le faire correctement?

Cet extrait du Guide de script avancé Bash dit:

 # The == comparison operator behaves differently within a double-brackets # test than within single brackets. [[ $a == z* ]] # True if $a starts with a "z" (wildcard matching). [[ $a == "z*" ]] # True if $a is equal to z* (literal matching). 

Donc, vous aviez presque raison; vous aviez besoin de doubles parenthèses, pas de crochets simples.


En ce qui concerne votre deuxième question, vous pouvez l’écrire de cette manière:

 HOST=user1 if [[ $HOST == user1 ]] || [[ $HOST == node* ]] ; then echo yes1 fi HOST=node001 if [[ $HOST == user1 ]] || [[ $HOST == node* ]] ; then echo yes2 fi 

Qui fera écho

 yes1 yes2 

Bash’s if syntaxe est difficile à utiliser (IMO).

Si vous utilisez un bash récent (v3 +), suggérez l’opérateur de comparaison bash regex =~ , c.-à-d.

 if [[ "$HOST" =~ ^user.* ]]; then echo "yes" fi 

Pour faire correspondre this or that dans une expression rationnelle | , c’est à dire

 if [[ "$HOST" =~ ^user.*|^host1 ]]; then echo "yes" fi 

Remarque: il s’agit d’une syntaxe d’expression régulière «correcte».

  • user* signifie use et zéro ou plus occurrences de r , donc use et userrrr correspondra.
  • user.* signifie que l’ user et zéro ou plusieurs occurrences de n’importe quel caractère, donc userX , userX correspondra.
  • ^user.* signifie correspondre à l’ user.* du pattern user.* au début de $ HOST.

Si vous n’êtes pas familier avec la syntaxe des expressions régulières, essayez de vous référer à cette ressource .

Remarque – il est préférable de poser chaque nouvelle question en tant que nouvelle question, de rendre plus ordonnée et plus utile le stackoverflow. Vous pouvez toujours inclure un lien vers une question précédente pour référence.

J’essaie toujours de restr avec POSIX sh au lieu d’utiliser des extensions bash, car la portabilité est l’un des principaux points de script. (Outre la connexion des programmes, ne pas les remplacer)

Dans sh, il existe un moyen facile de vérifier une condition “is-prefix”.

 case $HOST in node*) your code here esac 

Compte tenu de l’ancienneté, des arcanes et de la cruauté de sh (et bash n’est pas le remède: c’est plus compliqué, moins cohérent et moins portable), je voudrais souligner un aspect fonctionnel très intéressant: En, les constructions résultantes ne sont pas différentes de toutes les autres tâches. Ils peuvent être composés de la même manière:

 if case $HOST in node*) true;; *) false;; esac; then your code here fi 

Ou même plus court

 if case $HOST in node*) ;; *) false;; esac; then your code here fi 

Ou même plus court (juste pour présenter ! Comme élément linguistique – mais c’est mauvais style maintenant)

 if ! case $HOST in node*) false;; esac; then your code here fi 

Si vous aimez être explicite, créez votre propre élément linguistique:

 beginswith() { case $2 in "$1"*) true;; *) false;; esac; } 

N’est-ce pas vraiment bien?

 if beginswith node "$HOST"; then your code here fi 

Et comme sh est fondamentalement uniquement des jobs et des listes de chaînes (et des processus internes, à partir desquels des jobs sont composés), nous pouvons même maintenant faire de la functional programming légère:

 beginswith() { case $2 in "$1"*) true;; *) false;; esac; } checkresult() { if [ $? = 0 ]; then echo TRUE; else echo FALSE; fi; } all() { test=$1; shift for i in "$@"; do $test "$i" || return done } all "beginswith x" x xy xyz ; checkresult # prints TRUE all "beginswith x" x xy abc ; checkresult # prints FALSE 

C’est élégant. Non pas que je préconise l’utilisation de sh pour quelque chose de grave – cela casse trop vite les exigences du monde réel (pas de lambda, donc il faut utiliser des chaînes. Mais les appels de fonction d’imbrication avec des chaînes ne sont pas possibles,

Vous pouvez sélectionner uniquement la partie de la chaîne que vous souhaitez vérifier:

 if [ ${HOST:0:4} = user ] 

Pour votre question complémentaire, vous pouvez utiliser un OU :

 if [[ $HOST == user1 || $HOST == node* ]] 

Je préfère les autres méthodes déjà affichées, mais certaines personnes aiment utiliser:

 case "$HOST" in user1|node*) echo "yes";; *) echo "no";; esac 

Modifier:

J’ai ajouté vos remplaçants à la déclaration de cas ci-dessus

Dans votre version éditée, vous avez trop de crochets. Ça devrait ressembler à ça:

 if [[ $HOST == user1 || $HOST == node* ]]; 

puisque # a un sens dans bash je suis arrivé à la solution suivante.
De plus, j’aime mieux emballer les chaînes avec “” pour surmonter les espaces, etc.

 A="#sdfs" if [[ "$A" == "#"* ]];then echo "skip comment line" fi 

Bien que la plupart des réponses me semblent correctes, beaucoup contiennent des bases inutiles. L’extension des parameters POSIX vous offre tout ce dont vous avez besoin:

 [ "${host#user}" != "${host}" ] 

et

 [ "${host#node}" != "${host}" ] 

${var#expr} élimine le plus petit préfixe correspondant à expr de ${var} et le retourne. Donc si ${host} ne commence pas par user ( node ), ${host#user} ( ${host#node} ) est identique à ${host} .

expr autorise les caractères génériques fnmatch() , donc ${host#node??} et les amis fonctionnent également.

@OP, pour vos deux questions, vous pouvez utiliser le cas / esac

 ssortingng="node001" case "$ssortingng" in node*) echo "found";; * ) echo "no node";; esac 

deuxième question

 case "$HOST" in node*) echo "ok";; user) echo "ok";; esac case "$HOST" in node*|user) echo "ok";; esac 

OU Bash 4.0

 case "$HOST" in user) ;& node*) echo "ok";; esac 
 if [ [[ $HOST == user1 ]] -o [[ $HOST == node* ]] ]; then echo yes fi 

ne fonctionne pas, car tout [ , [[ et test] reconnaissent la même grammaire non récursive. voir la section EXPRESSIONS CONDITIONNELLES dans votre page de manuel bash.

En passant, le SUSv3 dit

La commande conditionnelle dérivée de KornShell (double crochet [[]] ) a été supprimée de la description du langage de commande shell dans une proposition antérieure. Des objections ont été émises sur le fait que le véritable problème est la mauvaise utilisation de la commande de test ( [ ), et que le placer dans le shell est la mauvaise façon de résoudre le problème. Au lieu de cela, une documentation appropriée et un nouveau mot réservé au shell ( ! ) Suffisent.

Les tests qui nécessitent plusieurs opérations de test peuvent être effectués au niveau du shell en utilisant des appels individuels de la commande de test et des logiques de shell, plutôt que d’utiliser l’indicateur -o du test, sujet à des erreurs.

vous devez l’écrire de cette façon, mais le test ne le prend pas en charge:

 if [ $HOST == user1 -o $HOST == node* ]; then echo yes fi 

test utilise = pour une égalité de chaîne, plus important encore, il ne prend pas en charge la correspondance de modèle.

case / esac prend bien en charge la correspondance de motif:

 case $HOST in user1|node*) echo yes ;; esac 

il a l’avantage supplémentaire de ne pas dépendre de bash, la syntaxe est portable. à partir de la spécification Single Unix, le langage de commande Shell:

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

Ajouter un tout petit peu plus de détails syntaxiques à la réponse la plus élevée de Mark Rushakoff.

L’expression

 $HOST == node* 

Peut aussi être écrit comme

 $HOST == "node"* 

L’effet est le même. Assurez-vous simplement que le caractère générique est en dehors du texte cité. Si le caractère générique est à l’ intérieur des guillemets, il sera interprété littéralement (c.-à-d. Pas comme un joker).

Une autre chose que vous pouvez faire est de cat ce que vous faites écho et tuyau avec inline cut -c 1-1