Shell: utilisation de la fonction avec des paramètres dans if

8

J'essaie d'exécuter le code ci-dessous mais lorsque j'essaie d'utiliser ma fonction dans l'instruction if, j'obtiens l' -bash: [: too many argumentserreur. Pourquoi cela se produit-il?

Merci d'avance!

notContainsElement () {
  local e match="$1"
  shift
  for e; do [[ "$e" == "$match" ]] && return 1; done
  return 0
}

list=( "pears" "apples" "bananas" "oranges" )
blacklist=( "oranges" "apples" )
docheck=1

for fruit in "${list[@]}"
do
    if [ notContainsElement "$fruit" "${blacklist[@]}" -a $docheck = 1 ]
    then
        echo $fruit
    fi
done
Andrea Silvestri
la source
1
Utilisez shellcheck.net (ou sa version hors ligne). Il trouve le problème mentionné dans les réponses avec une explication beaucoup moins détaillée et sans solution.
David Foerster

Réponses:

14

Lorsque if [ ... ]vous utilisez, vous utilisez réellement l' [utilitaire (qui est le même que testmais requiert que le dernier argument soit ]).

[ne comprend pas pour exécuter votre fonction, il attend des chaînes. Heureusement, vous n'avez pas besoin d'utiliser [du tout ici (pour la fonction au moins):

if [ "$docheck" -eq 1 ] && notContainsElement "$fruit" "${blacklist[@]}"; then
  ...
fi

Notez que je vérifie également d'abord l'entier, afin que nous puissions éviter d'appeler la fonction du tout si ce $docheckn'est pas 1.

Cela fonctionne car ifprend une commande arbitraire et décide quoi faire à partir du statut de sortie de cette commande. Ici, nous utilisons un [ ... ]test avec un appel à votre fonction, avec &&entre les deux, la création d'une commande composée. L'état de sortie de la commande composée serait vrai si à la fois le [ ... ]test et la fonction renvoyaient zéro comme état de sortie, signalant le succès.

Comme une note de style, je n'aurais pas le test de fonctionnement si le tableau ne pas contenir l'élément , mais que si ne contient l'élément, puis

if [ "$docheck" -eq 1 ] && ! contains "$fruit" "${blacklist[@]}"; then ...

Avoir un test de fonctionnement un désordre négatif volonté de la logique dans le cas où vous ne voulez tester si le tableau contient l'élément ( if ! notContainsElement ...).

Kusalananda
la source
Merci beaucoup pour la réponse et les autres conseils!
Andrea Silvestri
3

essayer

if notContainsElement "$fruit" "${blacklist[@]}" && test "$docheck" = 1
then
  • -al'option n'est ni un shell ni une testoption

ici, vous avez un test en deux parties

notContainsElement "$fruit" "${blacklist[@]}"
test $docheck = 1 ## or [ $docheck = 1 ]

vous liez ensuite en ifutilisant

if cmd1 && cmd2

comme indiqué -aest une option de test, mais ne peut être utilisée qu'avec une autre option de test, vous pouvez donc utiliser

if [ "$a" -lt "$b" -a "$a" -lt "$c" ]

pour tester qui $aest inférieur aux deux $bet $c, mais vous ne pouvez pas utiliser une autre commande dans la portée du test.

Archemar
la source
arg, @Kusalananda a de nouveau été l'arme la plus rapide du World Wild Web;)
Archemar
RSI est le prix que je paie pour cela.
Kusalananda
-aest une option de test , cela signifie ET.
hyde
@hyde Sauf qu'il a été marqué comme obsolète dans la norme POSIX.
Kusalananda
1
@Archemar, ... pensez à corriger les bogues de citations encore présents dans vos exemples (non cité $docheck, non cité $a/ $b/ etc dans le dernier exemple).
Charles Duffy
0

Voici une alternative que certaines personnes pourraient ne pas aimer. Convertissez votre tableau de liste noire en chaîne et voyez si la chaîne avec un fruit supprimé est la même. Modifié pour remplir les chaînes avec des espaces. Merci à Scott d'avoir signalé le problème pomme / ananas.

badlist=" ${blacklist[@]} "
for f in "${list[@]}"
do
    if [[ "${badlist/" $f "/}" == "$badlist" ]]
    then
        echo "$f"
    fi
done

Je pense que c'est plus simple, mais il manque la logique && que beaucoup préfèrent.

Gaspilleur
la source
(1) Cela échoue dans le cas où l'un des listfruits est contenu dans l' un des blacklistfruits. Par exemple, si nous passons blacklistà ( "oranges" "pineapples" ), la sortie de votre script ne change pas. … (Suite)
Scott
(Suite)… (2) Je ne comprends pas très bien ce que vous entendez par «je pense que c'est plus simple, mais il manque la logique && que beaucoup préfèrent.» Il est souvent plus facile de simplifier les choses en omettant la fonctionnalité. Comme Albert Einstein l'a peut-être dit ou non, "Tout devrait être aussi simple que possible, mais pas plus simple." Pourquoi avez-vous omis le &&? (3) Lorsque vous postez un code, veuillez le mettre en retrait de manière appropriée.
Scott
Eh bien, j'ai essayé d'utiliser le retrait à 4 espaces mais il semble que cela n'a pas fonctionné. Mais je vois ce que tu veux dire à propos des ananas.
Wastrel
Il ne peut pas non plus faire la distinction entre une seule entrée de liste two wordset deux éléments suivants, twoet words. Et si votre liste contenait *une entrée, elle correspondrait à tout. (Et parce que vous n'êtes pas en train de citer le $fdans ce qui devrait être echo "$f", si vous avez essayé de faire écho un tel élément, il serait remplacé par une liste de noms de fichiers dans le répertoire courant).
Charles Duffy
J'ai fait quelques modifications. Ce n'est pas anodin lorsque les données des tableaux sont arbitraires. Supposons que «pommes» figure dans la liste noire et «pommes Granny Smith» est un élément de l'autre tableau. Je pense que le code du PO a des problèmes similaires. Les tableaux doivent être constitués d'éléments qui "fonctionnent".
Wastrel