Signification de l'erreur «[: trop d'arguments» de if [] (crochets)

212

Je n'ai trouvé aucune ressource simple et simple expliquant la signification et la correction de l'erreur de shell BASH suivante, donc je poste ce que j'ai trouvé après l'avoir recherché.

L'erreur:

-bash: [: too many arguments

Version par Google: bash open square bracket colon too many arguments .

Contexte: une condition if entre crochets simples avec un opérateur de comparaison simple comme égal, supérieur à etc., par exemple:

VARIABLE=$(/some/command);
if [ $VARIABLE == 0 ]; then
  # some action
fi 
user56reinstatemonica8
la source
1
Où est le code qui a produit cette erreur spécifique?
Anderson Green

Réponses:

354

Si votre $VARIABLEest une chaîne contenant des espaces ou d'autres caractères spéciaux et que des crochets simples sont utilisés (qui est un raccourci pour la testcommande), la chaîne peut être divisée en plusieurs mots. Chacun d'eux est traité comme un argument distinct.

Donc, une variable est divisée en plusieurs arguments :

VARIABLE=$(/some/command);  
# returns "hello world"

if [ $VARIABLE == 0 ]; then
  # fails as if you wrote:
  # if [ hello world == 0 ]
fi 

La même chose sera vraie pour tout appel de fonction qui met une chaîne contenant des espaces ou d'autres caractères spéciaux.


Solution facile

Enveloppez la sortie variable entre guillemets doubles, en la forçant à rester comme une chaîne (donc un argument). Par exemple,

VARIABLE=$(/some/command);
if [ "$VARIABLE" == 0 ]; then
  # some action
fi 

Aussi simple que cela. Mais passez à "Attention aussi ..." ci-dessous si vous ne pouvez pas non plus garantir que votre variable ne sera pas une chaîne vide ou une chaîne qui ne contient que des espaces.


Ou, une solution alternative consiste à utiliser des crochets doubles (qui est un raccourci pour la new testcommande).

Cela n'existe cependant qu'en bash (et apparemment korn et zsh), et peut donc ne pas être compatible avec les shells par défaut appelés par /bin/shetc.

Cela signifie que sur certains systèmes, cela peut fonctionner à partir de la console, mais pas lorsqu'il est appelé ailleurs, comme à partir decron , selon la façon dont tout est configuré.

Cela ressemblerait à ceci:

VARIABLE=$(/some/command);
if [[ $VARIABLE == 0 ]]; then
  # some action
fi 

Si votre commande contient des crochets doubles comme celui-ci et que vous obtenez des erreurs dans les journaux mais que cela fonctionne à partir de la console, essayez d'échanger le [[pour une alternative suggérée ici, ou assurez-vous que tout ce qui exécute votre script utilise un shell qui prend en charge [[aka new test.


Attention également à l' [: unary operator expectederreur

Si vous voyez l'erreur "trop ​​d'arguments", il y a de fortes chances que vous obteniez une chaîne d'une fonction avec une sortie imprévisible. S'il est également possible d'obtenir une chaîne vide (ou toutes les chaînes d'espaces blancs), cela serait traité comme un argument zéro même avec la "solution rapide" ci-dessus, et échouerait avec[: unary operator expected

Il en va de même si vous êtes habitué à d'autres langues - vous ne vous attendez pas à ce que le contenu d'une variable soit effectivement imprimé dans le code comme celui-ci avant d'être évalué.

Voici un exemple qui empêche à la fois les erreurs [: too many argumentset les [: unary operator expectederreurs: remplacer la sortie par une valeur par défaut si elle est vide (dans cet exemple, 0), avec des guillemets doubles entourant le tout:

VARIABLE=$(/some/command);
if [ "${VARIABLE:-0}" == 0 ]; then
  # some action
fi 

(ici, l'action se produira si $ VARIABLE est 0 ou vide. Naturellement, vous devez changer le 0 (la valeur par défaut) en une valeur par défaut différente si un comportement différent est souhaité)


Remarque finale: puisqu'il [s'agit d'un raccourci pour test, tout ce qui précède est également vrai pour l'erreur test: too many arguments(et aussi test: unary operator expected)

user56reinstatemonica8
la source
Une façon encore meilleure esti=$(some_command); i=$((i)); if [ "$i" == 0 ] ...
Jo So
1
J'ai rencontré un problème où un Shellscript utilisant BASH comme interprète, lorsqu'il était exécuté via le terminal, allait bien, mais lorsqu'il était exécuté via Crontab, avait des échecs comme celui-ci et envoyait un courrier électronique local via Postfix, informant cette erreur et j'ai compris qu'il y avait un IF pour une variable qui avait des caractères spéciaux. Les guillemets doubles m'ont sauvé la vie. Je vous remercie :)!
ivanleoncz
13

Je suis juste tombé sur ce message, en obtenant la même erreur, en essayant de tester si deux variables sont toutes les deux vides (ou non vides). Cela s'avère être une comparaison composée - 7.3. Autres opérateurs de comparaison - Guide de script Bash avancé ; et j'ai pensé que je devrais noter ce qui suit:

  • J'ai utilisé en -epensant que cela signifie "vide" au début; mais cela signifie que "le fichier existe" - à utiliser -zpour tester une variable vide (chaîne)
  • Les variables de chaîne doivent être entre guillemets
  • Pour la comparaison ET logique composée, soit:
    • utilisez deux tests et &&eux:[ ... ] && [ ... ]
    • ou utilisez l' -aopérateur en un seul test:[ ... -a ... ]

Voici une commande de travail (recherche dans tous les fichiers txt dans un répertoire et vidage de ceux qui greptrouvent contiennent les deux mots):

find /usr/share/doc -name '*.txt' | while read file; do \
  a1=$(grep -H "description" $file); \
  a2=$(grep -H "changes" $file); \
  [ ! -z "$a1" -a ! -z "$a2"  ] && echo -e "$a1 \n $a2" ; \
done

Edit 12 août 2013: note de problème connexe:

Notez que lors de la vérification de l'égalité des chaînes avec classique test(simple crochet [), vous DEVEZ avoir un espace entre l'opérateur "est égal", qui dans ce cas est un seul =signe "égal" (bien que deux signes égaux ==semblent être acceptés comme égalité) opérateur aussi). Ainsi, cela échoue (en silence):

$ if [ "1"=="" ] ; then echo A; else echo B; fi 
A
$ if [ "1"="" ] ; then echo A; else echo B; fi 
A
$ if [ "1"="" ] && [ "1"="1" ] ; then echo A; else echo B; fi 
A
$ if [ "1"=="" ] && [ "1"=="1" ] ; then echo A; else echo B; fi 
A

... mais ajoutez de l'espace - et tout a l'air bien:

$ if [ "1" = "" ] ; then echo A; else echo B; fi 
B
$ if [ "1" == "" ] ; then echo A; else echo B; fi 
B
$ if [ "1" = "" -a "1" = "1" ] ; then echo A; else echo B; fi 
B
$ if [ "1" == "" -a "1" == "1" ] ; then echo A; else echo B; fi 
B
sdaau
la source
Pourriez-vous fournir un exemple de shell bash ((A || B) && C)?
jww
veuillez consulter les questions 3826425 et 14964805
splaisan
Ce n'est vraiment pas utile d'une réponse car elle ne vous montre pas comment contenir la commande complètement entre crochets, ce qui est nécessaire s'il y a une boucle, par exemple.
Timothy Swan
5

Vous pouvez également obtenir les erreurs [: too many argumentsor [: a: binary operator expectedsi vous essayez de tester tous les arguments"$@"

if [ -z "$@" ]
then
    echo "Argument required."
fi

Cela fonctionne correctement si vous appelez foo.shou foo.sh arg1. Mais si vous passez plusieurs arguments comme foo.sh arg1 arg2, vous obtiendrez des erreurs. C'est parce qu'il est étendu à[ -z arg1 arg2 ] , ce qui n'est pas une syntaxe valide.

La bonne façon de vérifier l'existence d'arguments est [ "$#" -eq 0 ]. ( $#est le nombre d'arguments).

wisbucky
la source
2

Parfois Si vous touchez accidentellement le clavier et que vous supprimez un espace.

if [ "$myvar" = "something"]; then
    do something
fi

Déclenche ce message d'erreur. Notez que l'espace avant «]» est requis.

Kemin Zhou
la source
1
Je pense que cela entraîne une erreur de syntaxe différente, telle que: ligne 21: [: manquant `] '
Joe Holloway
1

J'ai eu le même problème avec mes scripts. Mais quand j'ai fait quelques modifications, cela a fonctionné pour moi. J'ai aimé ça: -

export k=$(date "+%k");
if [ $k -ge 16 ] 
    then exit 0; 
else 
    echo "good job for nothing"; 
fi;

de cette façon, j'ai résolu mon problème. J'espère que cela vous aidera aussi.

Kidane
la source