2009-10-12 2 views
0

J'ai besoin de comprendre bash si les expressions. Bien sûr, j'ai utilisé Google. Je sais que cela se passe quelque chose comme ceci:Bash Impossible de faire fonctionner IF comme je veux

if [ expr operator expr ] 
then 
doSomeThing 
fi 

Cependant, je comprends que Bash n'a pas de type de données booléen. Je veux vérifier si le fichier passé en argument ($ 1) existe. La façon dont je ferais ce droit de mon esprit:

if [ -e $1 = true ] 
then 
echo "File exists." 
fḯ 

Ou peut-être comme:

if [ -e $1 ] #Assuming that this is true only if file in $1 exists. 

Aucun de ces travaux, et je ne suis pas sûr de ce que [] moyens. -e $ 1 semble être un choix judicieux, mais c'est toujours vrai? Il existe différents opérateurs pour les chaînes et les entiers. Et je ne peux pas utiliser de parenthèses pour regrouper des expressions. C'est tellement déroutant.

Quelqu'un at-il obtenu quelques indices? L'IF de bash ne fonctionne pas comme si j'avais essayé dans une autre langue.

Répondre

3

[...]

signifie que le programme est exécuté avec /usr/bin/test... les arguments et sa valeur de retour est cochée (0 signifie true et x != 0 signifie false (oui, 0 signifie vraiment true ici parce que 0 est le code de sortie OK dans UNIX)). Donc

if [ -e $1 ]; then 
    echo "ok" 
fi 

est correct. Il est le même que

if test -e $1; then 
    echo "ok" 
fi 

Le seul problème est que $1 pourrait contenir des espaces.Si c'est le cas /usr/bin/test devient confus, car il obtient 3 arguments ou plus. Le premier (-e) est un opérateur unaire (veut un argument). Puisque vous avez donné 2 ou plus (un argument /usr/bin/test est le -e lui-même), il se plaint comme ça:

...: binary operator expected 

, utilisez simplement

if [ -e "$1" ];then 
    echo "ok" 
fi 

Cela va même fonctionner si $1 contient des espaces. Une autre possibilité est d'utiliser

if [[ -e $1 ]]; then 
    echo "ok" 
fi 

Cela fera la même chose, mais il s'évalué par bash et aucun programme /usr/bin/test se fourchue.

Les composés sont comme d'habitude mais -a signifie and et -o signifie or. Alors

if [ -e /etc/fstab -a -e "$1" ]; then 
    echo "ok" 
fi 

fera écho ok si /etc/fstab et le fichier donné comme premier argument de ligne de commande existe.

+0

Que fait-il quand ajouter « » environ 1 $ => « $ 1 »? – Algific

+0

Il fera exactement UN argument pour/usr/bin/test, peu importe le nombre d'espaces. –

+0

Sauf que '[' et 'test' sont aussi des builtins Bash et en tant que tels sont exécutés avec une priorité supérieure à'/usr/bin/{[, test} ' –

0

le [] est un raccourci pour la commande de test bash http://ss64.com/bash/test.html

si l'opération des contrôles bash si le code de retour de l'utilisation de la commande pour le test est 0.

Vous pouvez vérifier l'état de retour d'une commande avec : echo $?

Par exemple, essayez ceci:

 
test -e myfile.txt 
echo $? 
[ -e myfile.txt ] 
echo ?$ 
0
  1. voir man test
  2. cela devrait fonctionner:

    function foo() { 
        if [ -e "$1" ] ; then 
        echo "$1 exists" 
        fi 
    } 
    
  3. là plusieurs façons d'écrire une des expressions composées: et:

    [ expr1 -a expr2 ] 
    

    ou:

    [ expr1 -o expr2 ] 
    

    Vous pouvez également utiliser la syntaxe [[ expr && expr || expr ]]

3

Comme d'autres l'ont mentionné, [ est en fait la commande test, donc ses arguments sont analysés selon la règle standard d'analyse des arguments, ce qui force une syntaxe plutôt gênante et déroutante. Par exemple, vous pouvez utiliser des parenthèses, <, et > dans les commandes de test, mais vous feriez mieux de leur échapper, sinon le shell les prendra pour signifier quelque chose de regrettable.

Il y a une bien meilleure solution: le conditional expression, qui ressemble beaucoup à la commande de test old-school, mais avec [[ ]] au lieu de [ ] autour de l'expression. Parce que ce ne sont pas analysées comme une commande, il a une syntaxe beaucoup plus naturel, et a aussi quelques fonctionnalités plus puissantes:

if [[ -e $1 && ! -d $1 ]]; then # if $1 exists but isn't a directory... 
    # note that quotes are not needed, since $1 will not undergo word splitting 
[[ $string == done ]] # string comparison 
[[ $string == a* ]] # glob-style pattern matching: does $string start with "a"? 
[[ $string == "*"* ]] # partial glob: does $string start with "*"? 
[[ $string =~ ^[[:upper:]] ]] # regex matching: does $string start with an upper-case letter? 
[[ $string < g ]] # string comparison: is $string alphabetically before "g" 
[[ $num -lt 5 ]] # numeric comparison: is $num numerically less than 5