Pourquoi le travail conditionnel ne l'utilise-t-il pas directement sans variable?

Cela me donne une erreur qui dit trop d'arguments:

if [ $( file -b $i ) == "directory" ] 

Mais quand j'ai essayé ça

 name=$( file -b $i ) if [ name == "directory" ] 

Cela semble fonctionner très bien.

Quelqu'un peut-il expliquer cela ou indiquer dans les documents une explication? Je suis nouveau à bash mais du sharepoint vue d'autres langages de programmation cela n'a aucun sens.

Quelques problèmes:

  • ] indique la fin des arguments pour [ ( test ), et il doit être le dernier argument; vous avez quelques ] s, ce qui est faux; vous pensiez probablement utiliser:

     if [ $( file -b $i ) == "directory" ] 
  • Si vous aviez utilisé ce qui précède, vous obtiendrez bash: [: too many arguments , parce que la division des mots se ferait sur la sortie de l'extension de variable ( $i ), puis la substitution de command, $() [ verra plusieurs mots avant = , conduisant au message d'erreur. Vous devez citer l'extension de variable et la substitution de command:

     [ "$(file -b "$1")" == "directory" ] 

Comme note de côté, vous devriez utiliser le mot-key bash [[ , au lieu de [ comme le premier traitera le fractionnement de mots (et l'extension de nom de path) pour vous.

 if [ $( file -b $i ) == "directory" ] 

Deux questions ici:

  • Utilisez single = pour la comparaison de strings. Voir man test pour une syntaxe correcte (notez que [ dans de nombreux cas, l'implémentation est spécifique à un shell, consultez la man page votre shell si vous n'avez pas de documentation pour le test ). Si vous avez absolument besoin == , utilisez [[ place, ce qui est caractéristique de beaucoup de shells comme Bourne, y compris bash, ksh, zsh. REMARQUE: while == existe dans bash depuis la version 2.0 , "= doit être utilisé avec la command de test pour la conformité POSIX." ( page de bash man ).

  • Mentionnez toutes vos variables comme "$()" . Spécifiquement d'intérêt est $i . Les noms de files avec espace vont casser $i en plusieurs mots en raison de l'expansion des mots du shell.

Exemple:

 bash-4.3$ mkdir with\ space bash-4.3$ i="./with space" bash-4.3$ set -x bash-4.3$ [ $( file -b $i ) == "directory" ] && echo "YES" ++ file -b ./with space + '[' cannot open '`./with'\''' '(No' such file or 'directory)' cannot open '`space'\''' '(No' such file or 'directory)' == directory ']' bash: [: too many arguments 

 name=$( file -b $i ) if [ name == "directory" ] 

Problèmes ici:

  • name n'est pas développé en variable, c'est juste une string "nom" ici. Vous avez besoin de "$name" et encore, single =

En outre, il ne peut pas avoir fonctionné, puisque le statut de sortie du test est renvoyé comme faux (état de sortie 1)

 $ name=$(file -b /etc) $ set -x $ [ name == "directory" ] + '[' name '==' directory ']' $ echo $? + echo 1 1 

Le testé ci-dessus sur les obus bash et mksh .

Il y a beaucoup de problèmes! Prenons cette partie qui "travaille":

  name=$( file -b $i ) if [ name == "directory" ] 

Cela affecte la sortie de la command file à la variable appelée name , mais ne l'utilise pas; à la place, il exécute la command [ avec 3 parameters: name , == , et directory . Accepter == est une extension bash.

Si cela a été corrigé pour utiliser $name plutôt que name vous obtiendrez à nouveau un problème d' too many arguments dans de nombreux cas. C'est parce que le file renvoie plusieurs résultats de mots comme ASCII text . Donc, après que la command a couru, vous obtenez

 if [ ASCII text == directory ] 

et maintenant il est évident que la command manque un certain groupement.

 if [ "$(file -b -- "$i")" = "directory" ] 

est probablement ce que vous voulez: = plutôt que == pour la portabilité, et en citant le résultat de la substitution de commands que vous voulez presque toujours faire .