# Bash: A && B || C is not if-then-else

**URL:** <https://www.debian-fr.org/t/bash-a-b-c-is-not-if-then-else/91598>\
**Category:** Programmation\
**Created:** [Octobre 5, 2025, 9:54 UTC](https://www.debian-fr.org/t/bash-a-b-c-is-not-if-then-else/91598 "2025-10-05T09:54:01Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![josephtux](https://www.debian-fr.org/user_avatar/www.debian-fr.org/josephtux/32/3985_2.png) [@josephtux](https://www.debian-fr.org/u/josephtux)\
**Post date:** [Octobre 5, 2025, 9:54 UTC](https://www.debian-fr.org/t/bash-a-b-c-is-not-if-then-else/91598/1 "2025-10-05T09:54:01Z")

</div>

`A && B || C is not if-then-else. C may run when A is true`

Je comprends bien le message, mais je ne suis pas sur de comprendre pourquoi (quand, Comment) C peut être exécuté quand A est vrai.

Je suppose que cette mise en garde peut signifier que C teste le résultat de B et non de A comme le ferait if-the-else.

Lorsque B est echo " $Foo", même si Foo n’existe pas, la valeur de retour reste vraie.

Mais je suppose que si B est une commande qui se termine par faux (valeur \> 0), dans ce cas C s’exécuterait?

Jusqu’ici, j’ai toujours eu la chance de ne pas rencontrer ce problème. Sans doute car cette forme n’est utilisée que pour une commande simple comme «echo».

Est-ce bien l’explication de cette mise en garde (de _shellcheck_) ?

---

<div class="post-metadata">

**Author:** ![Verner](https://www.debian-fr.org/letter_avatar_proxy/v4/letter/v/34f0e0/32.png) [@Verner](https://www.debian-fr.org/u/Verner)\
**Post date:** [Octobre 5, 2025, 10:11 UTC](https://www.debian-fr.org/t/bash-a-b-c-is-not-if-then-else/91598/2 "2025-10-05T10:11:16Z")

</div>

> [@josephtux](#):
>
> `A && B || C`

Il s’agit d’une ambiguïté non POSIX a impérativement éviter d’un shell à l’autre, car peut vouloir traduire deux conditions différentes:

Soit:  
**Si** A et B sont vraies, ou bien seulement **si** C est vrai, alors …  
`{ A && B ;} || C ` est correct et portable.

ou:  
**Si** A est vrai, et **si** B ou C est vraie , alors…  
`A && { B || C ;} ` est correct et portable.

---

<div class="post-metadata">

**Author:** ![fran.b](https://www.debian-fr.org/letter_avatar_proxy/v4/letter/f/d78d45/32.png) [@fran.b](https://www.debian-fr.org/u/fran.b)\
**Post date:** [Octobre 5, 2025, 10:17 UTC](https://www.debian-fr.org/t/bash-a-b-c-is-not-if-then-else/91598/3 "2025-10-05T10:17:25Z")

</div>

> [@josephtux](#):
>
> `A && B || C is not if-then-else. C may run when A is true`

Imagine A vrai et B faux.  
Si c’est parenthésé comme (A && B) || C , tu auras A executé puis comme il est vrai B aussi et donc comme B faux, (A && B) faux et donc C est exécuté  
Si c’est parenthésé comme A && (B || C) tu as le même enchainement:  
A est executé, étant vrai B || C est executé, donc B et comme B est faux C

En fait en bash si tu fais A && B || C il est impératif que B (pour moi C aussi) ne renvoit pas de code d’erreur.

---

<div class="post-metadata">

**Author:** ![josephtux](https://www.debian-fr.org/user_avatar/www.debian-fr.org/josephtux/32/3985_2.png) [@josephtux](https://www.debian-fr.org/u/josephtux)\
**Post date:** [Octobre 5, 2025, 10:23 UTC](https://www.debian-fr.org/t/bash-a-b-c-is-not-if-then-else/91598/4 "2025-10-05T10:23:06Z")

</div>

> [@fran.b](#):
>
> si tu fais A && B || C il est impératif que B (pour moi C aussi) ne renvoit pas de code d’erreur.

C’est bien ce que j’imaginais.  
Les exemples parenthésés sont intéressants, et donc utilisables.

Merci à tous les deux.

---

<div class="post-metadata">

**Author:** ![Verner](https://www.debian-fr.org/letter_avatar_proxy/v4/letter/v/34f0e0/32.png) [@Verner](https://www.debian-fr.org/u/Verner)\
**Post date:** [Octobre 5, 2025, 10:30 UTC](https://www.debian-fr.org/t/bash-a-b-c-is-not-if-then-else/91598/5 "2025-10-05T10:30:04Z")

</div>

Attention à la confusion courante entre l’usage de { ou ( : **ce n’est pas un effet de style**.  
«&nbsp; **{** &nbsp;» teste la condition dans le process en cours (donc plus rapide).  
«&nbsp;**(**&nbsp;» ouvre un **sous-process** , qui isole le test: attention au passage de variables d’un process à l’autre (piège courant).

---

<div class="post-metadata">

**Author:** ![josephtux](https://www.debian-fr.org/user_avatar/www.debian-fr.org/josephtux/32/3985_2.png) [@josephtux](https://www.debian-fr.org/u/josephtux)\
**Post date:** [Octobre 5, 2025, 10:42 UTC](https://www.debian-fr.org/t/bash-a-b-c-is-not-if-then-else/91598/6 "2025-10-05T10:42:10Z")

</div>

Ah oui, en effet j’avais mal vu (mal compris donc!)

---

<div class="post-metadata">

**Author:** ![Verner](https://www.debian-fr.org/letter_avatar_proxy/v4/letter/v/34f0e0/32.png) [@Verner](https://www.debian-fr.org/u/Verner)\
**Post date:** [Octobre 5, 2025, 12:23 UTC](https://www.debian-fr.org/t/bash-a-b-c-is-not-if-then-else/91598/7 "2025-10-05T12:23:49Z")

</div>

Pour illustrer la confusion courante entre «&nbsp;**(**&nbsp;» et «&nbsp; **{** &nbsp;»

```auto
A=0 ; { A=1 ;} ; echo $A
1

A=0 ; ( A=1 ) ; echo $A
0

```

Pour éviter les surprises et bugs obscurs, un test ne doit être isolé dans un sous-process que si justifié seulement.

---

<div class="post-metadata">

**Author:** ![AnonymousCoward](https://www.debian-fr.org/letter_avatar_proxy/v4/letter/a/f9ae1b/32.png) [@AnonymousCoward](https://www.debian-fr.org/u/AnonymousCoward)\
**Post date:** [Octobre 5, 2025, 6:56 UTC](https://www.debian-fr.org/t/bash-a-b-c-is-not-if-then-else/91598/8 "2025-10-05T18:56:53Z")

</div>

> [@Verner](#):
>
> > [@josephtux](#):
> >
> > `A && B || C`
> 
> Il s’agit d’une ambiguïté non POSIX a impérativement éviter d’un shell à l’autre, car peut vouloir traduire deux conditions différentes:

J’ai vérifié et, apparemment, c’est POSIX.

Et non, ce n’est pas une ambiguïté.

D’après la [page de man bash](https://manpages.debian.org/trixie/manpages-fr/bash.1.fr.html#Listes) , l’associativité à gauche fait que  
`A && B || C`  
équivaut à  
`( A && B ) || C`

Prenons l’exemple de l’explication fournie par [shellcheck.net](http://shellcheck.net) , [SC2015](https://www.shellcheck.net/wiki/SC2015) :  
`[[$dryrun]] && echo "Would delete file" || rm file`

Si un petit malin redirige la sortie standard vers `/dev/full` , la commande `echo` renverrait une erreur et le `rm` serait exécuté.

–  
AnonymousCoward

---

<div class="post-metadata">

**Author:** ![Verner](https://www.debian-fr.org/letter_avatar_proxy/v4/letter/v/34f0e0/32.png) [@Verner](https://www.debian-fr.org/u/Verner)\
**Post date:** [Octobre 5, 2025, 7:55 UTC](https://www.debian-fr.org/t/bash-a-b-c-is-not-if-then-else/91598/9 "2025-10-05T19:55:22Z")

</div>

> [@AnonymousCoward](#):
>
> **apparemment** , c’est POSIX.  
> D’après la page de **man bash** , l’associativité à gauche fait que

Le problème est dans l’apparence.  
**B** ash n’est pas POSIX. **D** ash est POSIX.  
Est-ce que **zsh** aura aussi le même comportement selon les versions ?  
Absolument aucune garantie.  
Maintenant, il n’est pas interdit d’utiliser des formulations ambigües, particulièrement si’il n’y a que **3** conditions à tester, mais c’est jouer au poker et complexifier la recherche de bugs.  
Ce n’est pas par hasard que **le problème est signalé** , car parfaitement identifié.  
Prendre de mauvaises habitudes n’est pas une bonne habitude, mais chacun fait fait fait ce qui lui plait plait plait.

---

<div class="post-metadata">

**Author:** ![AnonymousCoward](https://www.debian-fr.org/letter_avatar_proxy/v4/letter/a/f9ae1b/32.png) [@AnonymousCoward](https://www.debian-fr.org/u/AnonymousCoward)\
**Post date:** [Octobre 5, 2025, 8:11 UTC](https://www.debian-fr.org/t/bash-a-b-c-is-not-if-then-else/91598/10 "2025-10-05T20:11:37Z")

</div>

> [@Verner](#):
>
> Le problème est dans l’apparence.  
> **B** ash n’est pas POSIX. **D** ash est POSIX.

J’ai testé avec l’option `--posix` de bash ainsi qu’avec dash et l’expression `A && B || C` est valide dans les deux cas, a le même fonctionnement.

> [@Verner](#):
>
> Maintenant, il n’est pas interdit d’utiliser des formulations ambigües,

Cela n’a rien d’ambigu.

Mais oui, c’est une bonne habitude que d’utiliser systématiquement if-then-else plutôt que `&&` et `||` .

–  
AnonymousCoward

---

<div class="post-metadata">

**Author:** ![Verner](https://www.debian-fr.org/letter_avatar_proxy/v4/letter/v/34f0e0/32.png) [@Verner](https://www.debian-fr.org/u/Verner)\
**Post date:** [Octobre 5, 2025, 8:21 UTC](https://www.debian-fr.org/t/bash-a-b-c-is-not-if-then-else/91598/11 "2025-10-05T20:21:25Z")

</div>

Une option ‹&nbsp;–posix&nbsp;› que ce soit de bash ou autre commande non posix n’est pas une garantie de ‹&nbsp;posixité&nbsp;› absolue, sachant qu’il a POSIX et POSIX selon la version. Problème aussi rencontré avec awk / gawk.

On peut rajouter qu’on ne trouvera **jamais** ce genre d’ambiguïté ’`A && B || C` ’ dans **aucun** script POSIX dans un paquet Debian par exemple.  
Ceux qui écrivent ces scripts connaissent bien ce problème.  
C’est en pratiquant des tests plus complexes, en testant leur portabilité qu’on est sensibilisé à ce genre de problématique.

---

<div class="post-metadata">

**Author:** ![littlejohn75](https://www.debian-fr.org/user_avatar/www.debian-fr.org/littlejohn75/32/3840_2.png) [@littlejohn75](https://www.debian-fr.org/u/littlejohn75)\
**Post date:** [Octobre 12, 2025, 10:39 UTC](https://www.debian-fr.org/t/bash-a-b-c-is-not-if-then-else/91598/12 "2025-10-12T22:39:27Z")

</div>

Exemple  
•••false is not true && écho bien sûr || écho Quel et le con qui a codé $(command -v false) ?

Désolé pour les fautes de frappe, je galère à taper sur un vieil iPhone.
