J'ai appris à bash cette semaine et j'ai rencontré un hic.
#!/bin/sh
if [ false ]; then
echo "True"
else
echo "False"
fi
Cela produira toujours True même si la condition semble indiquer le contraire. Si je supprime les crochets, []
cela fonctionne, mais je ne comprends pas pourquoi.
bash
conditional-operator
dix milles
la source
la source
#!/bin/sh
n'est pas un script bash - c'est un script POSIX sh. Même si l'interpréteur POSIX sh sur votre système est fourni par bash, il désactive un tas d'extensions. Si vous souhaitez écrire des scripts bash, utilisez#!/bin/bash
ou son équivalent localement approprié (#!/usr/bin/env bash
pour utiliser le premier interpréteur bash dans le PATH).[[ false ]]
aussi.Réponses:
Vous exécutez la commande
[
(akatest
) avec l'argument "false", sans exécuter la commandefalse
. Puisque "false" est une chaîne non vide, latest
commande réussit toujours. Pour exécuter réellement la commande, supprimez la[
commande.la source
bash
n'a pas de type de données booléen, et donc aucun mot-clé représentant vrai et faux. L'if
instruction vérifie simplement si la commande que vous lui donnez réussit ou échoue. Latest
commande prend une expression et réussit si l'expression est vraie; une chaîne non vide est une expression évaluée comme vraie, comme dans la plupart des autres langages de programmation.false
est une commande qui échoue toujours. (Par analogie,true
est une commande qui réussit toujours.)if [[ false ]];
renvoie vrai aussi. Comme le faitif [[ 0 ]];
. Etif [[ /usr/bin/false ]];
ne saute pas non plus le bloc. Comment false ou 0 peut-il être non nul? Merde, c'est frustrant. Si cela compte, OS X 10.8; Bash 3.false
pour une constante booléenne ou0
pour un littéral entier; les deux ne sont que des chaînes ordinaires.[[ x ]]
équivaut à[[ -n x ]]
pour toute chaînex
qui ne commence pas par un trait d'union.bash
n'a pas de constantes booléennes dans aucun contexte. Les chaînes qui ressemblent à des entiers sont traitées comme telles à l'intérieur(( ... ))
ou avec des opérateurs tels que-eq
ou à l'-lt
intérieur[[ ... ]]
.if $predicate
peut facilement être abusé pour exécuter du code hostile d'une manière quiif [[ $predicate ]]
ne le peut pas.Un aperçu booléen rapide pour Bash
La
if
déclaration prend une commande comme argument (comme le font&&
,||
etc.). Le code de résultat entier de la commande est interprété comme un booléen (0 / null = true, 1 / else = false).L'
test
instruction prend des opérateurs et des opérandes comme arguments et renvoie un code de résultat au même format queif
. Un alias de l'test
instruction est[
, qui est souvent utilisé avecif
pour effectuer des comparaisons plus complexes.Les instructions
true
etfalse
ne font rien et renvoient un code de résultat (0 et 1, respectivement). Ils peuvent donc être utilisés comme littéraux booléens dans Bash. Mais si vous placez les instructions dans un endroit où elles sont interprétées comme des chaînes, vous rencontrerez des problèmes. Dans ton cas:Alors:
Ceci est similaire à faire quelque chose comme
echo '$foo'
contreecho "$foo"
.Lors de l'utilisation de l'
test
instruction, le résultat dépend des opérateurs utilisés.En bref , si vous voulez juste tester quelque chose comme réussite / échec (aka "vrai" / "faux"), alors passez une commande à votre instruction
if
ou&&
etc., sans crochets. Pour des comparaisons complexes, utilisez des parenthèses avec les opérateurs appropriés.Et oui, je suis conscient qu'il n'y a pas de type booléen natif dans Bash, et que
if
et[
ettrue
sont techniquement des "commandes" et non des "instructions"; ce n'est qu'une explication fonctionnelle très basique.la source
if (( $x )); then echo "Hello"; fi
affiche le message pourx=1
mais pas pourx=0
oux=
(non défini).J'ai trouvé que je peux faire une logique de base en exécutant quelque chose comme:
la source
( $A && $B )
est une opération étonnamment inefficace - vous créez un sous-processus en appelantfork()
, puis en divisant par chaîne le contenu de$A
pour générer une liste d'éléments (dans ce cas de taille un), et en évaluant chaque élément comme un glob (dans ce cas, un qui s'évalue par lui-même), puis exécutez le résultat sous forme de commande (dans ce cas, une commande intégrée).true
etfalse
proviennent d'ailleurs, il y a un risque qu'elles contiennent en fait des contenus autres quetrue
oufalse
, et vous pourriez avoir un comportement inattendu jusqu'à et y compris l'exécution de commandes arbitraires.A=1; B=1
etif (( A && B ))
- de les traiter comme numériques - ou[[ $A && $B ]]
, qui traite une chaîne vide comme fausse et une chaîne non vide comme vraie.L'utilisation de vrai / faux supprime un certain encombrement de parenthèses ...
la source
[[ "$0" =~ "bash" ]]
le script fonctionne pour moi.