Je voudrais vérifier si une chaîne commence par "noeud" 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 l'hôte est "utilisateur1" ou commence par "nœud"
if [ [[ $Host == user1 ]] -o [[ $Host == node* ]] ];
then
echo yes
fi
> > > -bash: [: too many arguments
Comment le faire correctement?
Cet extrait de Guide de rédaction avancée de scripts 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 correct; vous aviez besoin de doubles crochets, pas de crochets simples.
En ce qui concerne votre deuxième question, vous pouvez l'écrire comme suit:
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
La syntaxe de if
de Bash est difficile à prendre en main (IMO).
Si vous utilisez un bash récent (v3 +), je suggère à l'opérateur de comparaison bash regex =~
, c'est-à-dire.
if [[ "$Host" =~ ^user.* ]]; then
echo "yes"
fi
Pour faire correspondre this or that
dans une expression rationnelle, utilisez |
, c.-à-d.
if [[ "$Host" =~ ^user.*|^Host1 ]]; then
echo "yes"
fi
Remarque - il s'agit de la syntaxe "correcte" des expressions régulières.
user*
signifie use
et aucune ou plusieurs occurrences de r
, de sorte que use
et userrrr
correspondent.user.*
signifie user
et aucune ou plusieurs occurrences de caractères, de sorte que user1
, userX
correspondra.^user.*
signifie correspondre au motif 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 comme une nouvelle question, cela rend le stackoverflow plus ordonné et plus utile. Vous pouvez toujours inclure un lien vers une question précédente pour référence.
J'essaie toujours de rester avec POSIX sh au lieu d'utiliser des extensions bash, car l'un des principaux points du script est la portabilité. (Outre connexion programmes, ne les remplace pas)
En sh, il existe un moyen simple de rechercher une condition "is-prefix".
case $Host in node*)
your code here
esac
Compte tenu de l'âge, du style mystérieux et cruel (et bash n'est pas le remède: c'est plus compliqué, moins cohérent et moins portable), j'aimerais souligner un aspect fonctionnel très agréable: alors que certains éléments syntaxiques comme case
sont intégrés, les constructions résultantes ne sont pas différentes de tout autre travail. 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 un élément de langage - mais c'est un mauvais style maintenant)
if ! case $Host in node*) false;; esac; then
your code here
fi
Si vous aimez être explicite, construisez votre propre élément de langage:
beginswith() { case $2 in "$1"*) true;; *) false;; esac; }
N'est-ce pas vraiment très gentil?
if beginswith node "$Host"; then
your code here
fi
Et comme sh n’est en gros que des emplois et des listes de chaînes (et des processus internes, à partir desquels les emplois sont composés), nous pouvons maintenant même faire de la programmation fonctionnelle 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 recommande l'utilisation de sh pour quelque chose de sérieux - cela casse trop vite pour répondre aux exigences du monde réel (pas de lambda, vous devez donc utiliser des chaînes. Mais les appels de fonctions imbriquées avec des chaînes ne sont pas possibles, les tuyaux 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 suivante, vous pouvez utiliser un OU :
if [[ $Host == user1 || $Host == node* ]]
Je préfère les autres méthodes déjà postées, mais certaines personnes aiment utiliser:
case "$Host" in
user1|node*)
echo "yes";;
*)
echo "no";;
esac
Edit:
J'ai ajouté vos suppléants à la déclaration de cas ci-dessus
Dans votre version modifiée, vous avez trop de crochets. Ça devrait ressembler à ça:
if [[ $Host == user1 || $Host == node* ]];
Bien que je trouve la plupart des réponses correctes, beaucoup d’entre elles contiennent des bashismes inutiles. expansion du paramètre POSIX vous donne tout ce dont vous avez besoin:
[ "${Host#user}" != "${Host}" ]
et
[ "${Host#node}" != "${Host}" ]
${var#expr}
supprime le plus petit préfixe correspondant à expr
de ${var}
et le renvoie. Par conséquent, si ${Host}
ne commence pas par user
(node
), ${Host#user}
(${Host#node}
) est identique à ${Host}
.
expr
permet fnmatch()
caractères génériques, donc ${Host#node??}
et amis fonctionnent également.
puisque # a une signification dans Bash, je suis arrivé à la solution suivante.
En outre, j'aime mieux emballer les chaînes avec "" pour surmonter les espaces, etc.
A="#sdfs"
if [[ "$A" == "#"* ]];then
echo "skip comment line"
fi
Ajouter un peu plus de détails de syntaxe à la réponse de rang le plus élevé 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 les guillemets, il sera interprété littéralement (c'est-à-dire pas comme un caractère générique).
@OP, vous pouvez utiliser case/esac pour vos deux questions
string="node001"
case "$string" 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 tous [, [[ et test reconnaît la même grammaire non récursive. voir la section EXPRESSIONS CONDITIONNELLES dans votre page de manuel bash.
En aparté, 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 première proposition. Des objections ont été soulevées selon lesquelles le problème réel est l’utilisation abusive de la commande test ([), et son insertion 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 de commande réservé au shell (!) sont suffisants.
Les tests nécessitant plusieurs tests peuvent être effectués au niveau du shell à l'aide d'appels individuels du test commande et logiques Shell, plutôt que d’utiliser le drapeau - o, sujet aux erreurs, de test .
vous auriez besoin de l'écrire de cette façon, mais test ne le prend pas en charge:
if [ $Host == user1 -o $Host == node* ];
then
echo yes
fi
test utilise = pour l'égalité des chaînes, plus important encore, il ne prend pas en charge correspondance de modèle.
case
/esac
supporte bien la correspondance des modèles:
case $Host in
user1|node*) echo yes ;;
esac
cela 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
grep
Oubliant les performances, voici POSIX et c'est plus joli que les solutions case
:
mystr="abcd"
if printf '%s' "$mystr" | grep -Eq '^ab'; then
echo matches
fi
Explication:
printf '%s'
pour empêcher printf
de développer les échappements de barre oblique inversée: chaîne textuelle texth de bash printfgrep -q
empêche l’écho des correspondances sur stdout: Comment vérifier si un fichier contient une chaîne spécifique en utilisant Bashgrep -E
active les expressions régulières étendues dont nous avons besoin pour le ^
J'ai modifié la réponse de @ markrushakoff pour en faire une fonction appelable:
function yesNo {
# prompts user with $1, returns true if response starts with y or Y or is empty string
read -e -p "
$1 [Y/n] " YN
[[ "$YN" == y* || "$YN" == Y* || "$YN" == "" ]]
}
Utilisez-le comme ceci:
$ if yesNo "asfd"; then echo "true"; else echo "false"; fi
asfd [Y/n] y
true
$ if yesNo "asfd"; then echo "true"; else echo "false"; fi
asfd [Y/n] Y
true
$ if yesNo "asfd"; then echo "true"; else echo "false"; fi
asfd [Y/n] yes
true
$ if yesNo "asfd"; then echo "true"; else echo "false"; fi
asfd [Y/n]
true
$ if yesNo "asfd"; then echo "true"; else echo "false"; fi
asfd [Y/n] n
false
$ if yesNo "asfd"; then echo "true"; else echo "false"; fi
asfd [Y/n] ddddd
false
Voici une version plus complexe qui fournit une valeur par défaut spécifiée:
function toLowerCase {
echo "$1" | tr '[:upper:]' '[:lower:]'
}
function yesNo {
# $1: user Prompt
# $2: default value (assumed to be Y if not specified)
# Prompts user with $1, using default value of $2, returns true if response starts with y or Y or is empty string
local DEFAULT=yes
if [ "$2" ]; then local DEFAULT="$( toLowerCase "$2" )"; fi
if [[ "$DEFAULT" == y* ]]; then
local Prompt="[Y/n]"
else
local Prompt="[y/N]"
fi
read -e -p "
$1 $Prompt " YN
YN="$( toLowerCase "$YN" )"
{ [ "$YN" == "" ] && [[ "$Prompt" = *Y* ]]; } || [[ "$YN" = y* ]]
}
Utilisez-le comme ceci:
$ if yesNo "asfd" n; then echo "true"; else echo "false"; fi
asfd [y/N]
false
$ if yesNo "asfd" n; then echo "true"; else echo "false"; fi
asfd [y/N] y
true
$ if yesNo "asfd" y; then echo "true"; else echo "false"; fi
asfd [Y/n] n
false