web-dev-qa-db-fra.com

Signification de "[: too many arguments" "de if [] (crochets)

Je ne pouvais trouver aucune ressource simple expliquant la signification de l'erreur BASH Shell suivante, alors je publie ce que j'ai trouvé après une recherche.

L'erreur:

-bash: [: too many arguments

version compatible avec Google:bash open square bracket colon too many arguments.

Contexte: une condition if entre crochets simples avec un opérateur de comparaison simple, tel qu'égaux, supérieur à etc, par exemple:

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

Si votre $VARIABLE est une chaîne contenant des espaces ou d'autres caractères spéciaux, et des crochets simples sont utilisés (qui est un raccourci pour la commande test), alors la chaîne peut être divisé en plusieurs mots. Chacun de ceux-ci est traité comme un argument séparé.

Pour que une variable soit 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 

Il en ira de même pour tout appel de fonction établissant une chaîne contenant des espaces ou d'autres caractères spéciaux.


Solution facile

Enveloppez la sortie de variable entre guillemets, en la forçant à rester sous la forme d'une chaîne (donc d'un argument). Par exemple,

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

Aussi simple que cela. Mais passez à "Méfiez-vous également ..." 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 bien, un correctif alternatif consiste à utiliser des crochets doubles (ce qui est un raccourci pour la commande new test).

Ceci n’existe que dans bash (et apparemment korn et zsh) et peut donc ne pas être compatible avec les shells par défaut appelés par /bin/sh etc. Cela signifie que sur certains systèmes, par exemple, cela peut fonctionner à partir de la console mais pas à partir de. cron, en fonction de la configuration de tout.

Cela ressemblerait à ceci:

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

Méfiez-vous également de l'erreur [: unary operator expected

Si vous voyez l'erreur "Trop d'arguments", il est probable 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 toute chaîne d'espacement), cela sera traité comme un argument nul, même avec le "correctif 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 avant d'être évalué.

Voici un exemple qui empêche les erreurs [: too many arguments et [: unary operator expected: remplacer la sortie par une valeur par défaut si elle est vide (dans cet exemple, 0), avec des guillemets doubles la totalité:

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

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


Note finale: Puisque [ est 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)

308
user568458

Je viens de tomber dans ce post, en obtenant la même erreur, en essayant de vérifier si deux variables sont les deux vides (ou non vides). Cela se révèle être un comparaison composée - 7.3. Autres opérateurs de comparaison - Guide de scripts Bash avancés ; et j'ai pensé que je devrais noter ce qui suit:

  • J'ai utilisé -e en pensant que cela signifie "vide" au début; mais cela signifie "fichier existe" - utilisez -z pour tester vide variable (chaîne)
  • Les variables de chaîne doivent être citées
  • Pour la comparaison logique ET composée, soit:
    • utilisez deux tests et && les: [ ... ] && [ ... ]
    • ou utilisez l'opérateur -a dans un seul test: [ ... -a ... ]

Voici une commande de travail (rechercher dans tous les fichiers txt d'un répertoire et vider ceux que grep trouve contient 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

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

notez que lors de la vérification de l’égalité des chaînes avec classic test (crochet unique [), vous DEVEZ avoir un espace entre l'opérateur "est égal", qui dans ce cas est un signe "est égal à" = signe (bien que les deux signes égaux == semblent également être acceptés comme opérateur d'égalité). Ainsi, cela échoue (silencieusement):

$ 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 est beau:

$ 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
10
sdaau

Quelques fois Si vous touchez le clavier accidentellement et supprimez un espace.

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

Va déclencher ce message d'erreur. Notez que l'espace avant ']' est requis.

2
Kemin Zhou

Si vous essayez de tester tous les arguments [: too many arguments, vous pouvez également obtenir les erreurs [: a: binary operator expected ou "$@".

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

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

La méthode correcte pour vérifier l'existence d'arguments est [ "$#" -eq 0 ]. ($# est le nombre d'arguments).

1
wisbucky

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 fait comme ç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.

1
Kidane