ubuntuusers.de

Bash: Sinn vom then bei if-Anweisung?

Status: Gelöst | Ubuntu-Version: Ubuntu 11.04 (Natty Narwhal)
Antworten |

Unix_Samurai

Anmeldungsdatum:
10. Oktober 2008

Beiträge: 661

Hi.

Ich finde das then bei if Anweisungen in der Bash überflüssig. Liegt da irgendein Sinn hinter, warum es in Bash so umständlich ist, wenn es in C usw so schön effizienter geht?

MfG

redknight Team-Icon

Moderator & Supporter
Avatar von redknight

Anmeldungsdatum:
30. Oktober 2008

Beiträge: 21847

Wohnort: Lorchhausen im schönen Rheingau

Der Sinn ist, dass der Parser erkennen muss, was zum if-Zweig gehört. In C erkennt er es an den geschweiften Klammern, in python an der Einrückung, in der Bash halt am Codewort then

rklm Team-Icon

Projektleitung

Anmeldungsdatum:
16. Oktober 2011

Beiträge: 13205

Unix Samurai schrieb:

Ich finde das then bei if Anweisungen in der Bash überflüssig. Liegt da irgendein Sinn hinter, warum es in Bash so umständlich ist, wenn es in C usw so schön effizienter geht?

Der Begriff "effizienter" ist hier unpassend. Es geht ja nur um ein paar Zeichen, die man weniger tippen muss. Für die Laufzeiteffizienz macht das keinen Unterschied. Wenn überhaupt, geht es um Produktivität des Entwicklers.

redknight schrieb:

Der Sinn ist, dass der Parser erkennen muss, was zum if-Zweig gehört.

Nein, dafür braucht man es nicht. Ich denke, man wollte einfach die Lesbarkeit erhöhen. Sonst sähe das so aus:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
if [ -e "$f" ]
  echo "$f gefunden"
fi

if [ -e "$f" ]
  echo "$f gefunden"
else
  echo "$f NICHT gefunden"
fi

if [ -e "$f" ]; echo "$f gefunden"; fi
if [ -e "$f" ]; echo "$f gefunden"; else echo "$f NICHT gefunden"; fi

# Wenn die Bedingung nicht [ benutzt, wird es schlecht lesbar:
if grep -q foo bar; wc -l bar; else echo "kein foo"; fi

# vergleiche mit:
if grep -q foo bar; then wc -l bar; else echo "kein foo"; fi

Das lässt sich genau so eindeutig parsen. Möglicherweise war das mit den damaligen Tools einfacher zu machen ggf. hat es auch was damit zu tun, dass die Shell zeilenweise parst - oder es ging, wie gesagt, um die Lesbarkeit.

In C erkennt er es an den geschweiften Klammern,

Nein, denn die sind optional:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
$ gcc -c -Wall -ansi x.c
$ cat -n x.c
     1
     2  #include "stdio.h"
     3
     4  void foo() {
     5    if ( 1 > 0 )
     6      printf("ja\n");
     7
     8    if ( 1 > 0 )
     9      printf("ja\n");
    10    else
    11      printf("nein\n");
    12  }

Ciao

robert

redknight Team-Icon

Moderator & Supporter
Avatar von redknight

Anmeldungsdatum:
30. Oktober 2008

Beiträge: 21847

Wohnort: Lorchhausen im schönen Rheingau

rklm schrieb:

Das lässt sich genau so eindeutig parsen. Möglicherweise war das mit den damaligen Tools einfacher zu machen ggf. hat es auch was damit zu tun, dass die Shell zeilenweise parst

Glaube ich eher dran, kann ich aber nicht beweisen 😉

In C erkennt er es an den geschweiften Klammern,

Nein, denn die sind optional:

Aber nur, wenn der if-Zweig nur eine Zeile hat, oder?

diesch Team-Icon

Avatar von diesch

Anmeldungsdatum:
18. Februar 2009

Beiträge: 5072

Wohnort: Brandenburg an der Havel

rklm schrieb:

Nein, dafür braucht man es nicht. Ich denke, man wollte einfach die Lesbarkeit erhöhen. Sonst sähe das so aus:

1
2
3
if [ -e "$f" ]
  echo "$f gefunden"
fi

Das lässt sich genau so eindeutig parsen.

[ ist kein Teil der Bash-Syntax, sondern ein Programm-Aufruf, und da kann auch ein beliebiger anderer, auch zusammengesetzter, Befehl stehen.

Ohne then könnte der Parser diese beiden Fälle nicht unterscheiden:

1
if a; b; then echo 'Bla'; fi
1
if a; then b; echo 'Bla'; fi

Interessant ist so eine Syntax eher für einen elif oder else-Zweig, weil man den ersten Befehl nicht so einfach aus der Bedingung raus nehmen kann, aber es ist natürlich sinnvoll, da eine konsistente Syntax zu haben.

Und es ist natürlich auch einfacher, nicht eine eigene Gruppe von zusammengesetzten Befehlen einführen zu müssen, die bei if erlaubt sind, sondern dort einfach alle zusammengesetzten Befehle zu erlauben.

MisterIgo

Anmeldungsdatum:
23. April 2009

Beiträge: 947

redknight schrieb:

Nein, denn die sind optional:

Aber nur, wenn der if-Zweig nur eine Zeile hat, oder?

Ja, denn sonst kann der Parser/Compiler wieder nicht mehr vernünftig parsen, vgl.:

void foo(){
    int i = 0;
    int j = 0;
    if (i > 0)
        i++;
        j++;
}

vs.

void foo(){
    int i = 0;
    int j = 0;
    if (i > 0)
        i++;
    j++;
}

Wenn j++ zur Bedingung gehören soll, müssen Klammern gesetzt werden. Die beiden Beispiele sind für den Compiler beidesmal dasselbe.

@UnixSamurai Wenn du if nicht magst, kann man das mit && umgehen

if foo; then bar; fi
liefert dasselbe wie
foo && bar
if foo; then bar; else bor; fi
liefert dasselbe wie
foo && bar || bor

rklm Team-Icon

Projektleitung

Anmeldungsdatum:
16. Oktober 2011

Beiträge: 13205

diesch schrieb:

[ ist kein Teil der Bash-Syntax, sondern ein Programm-Aufruf, und da kann auch ein beliebiger anderer, auch zusammengesetzter, Befehl stehen.

Ohne then könnte der Parser diese beiden Fälle nicht unterscheiden:

1
if a; b; then echo 'Bla'; fi
1
if a; then b; echo 'Bla'; fi

Guter Punkt! Mir war gar nicht bewusst, dass an der Stelle eine "List" erlaubt ist. Ist aber völlig logisch, denn mit "&&" und "||" verknüpfte Kommandos sind es ja auch. Und die Manpage sagt es ja auch:

if list; then list; [ elif list; then list; ] ... [ else list; ] fi

Also, das ist auf jeden Fall der Grund.

Und es ist natürlich auch einfacher, nicht eine eigene Gruppe von zusammengesetzten Befehlen einführen zu müssen, die bei if erlaubt sind, sondern dort einfach alle zusammengesetzten Befehle zu erlauben.

Das hätte man nicht gebraucht, denn diese Gruppierung gibt es ja schon: sie wird durch geschweifte Klammern gebildet. Wenn man unbedingt auf "if", "then" etc. verzichten will und das mit "&&" und "||" machen will, wie Du vorschlägst, braucht man das auch:

1
2
3
4
5
6
7
8
9
test -r "$f" && { echo "$f gefunden:"; wc -l "$f"; } || { echo "$f fehlt, es gibt nur:" >&2; ls -l $(dirname "$f"); }

test -r "$f" && 
{ echo "$f gefunden:"; wc -l "$f"; } || 
{ echo "$f fehlt, es gibt nur:" >&2; ls -l $(dirname "$f"); }

test -r "$f" \
&& { echo "$f gefunden:"; wc -l "$f"; } \
|| { echo "$f fehlt, es gibt nur:" >&2; ls -l $(dirname "$f"); }

Ciao

robert

diesch Team-Icon

Avatar von diesch

Anmeldungsdatum:
18. Februar 2009

Beiträge: 5072

Wohnort: Brandenburg an der Havel

rklm schrieb:

Das hätte man nicht gebraucht, denn diese Gruppierung gibt es ja schon: sie wird durch geschweifte Klammern gebildet. Wenn man unbedingt auf "if", "then" etc. verzichten will und das mit "&&" und "||" machen will, wie Du vorschlägst, braucht man das auch:

Man könnte das if ohne then definieren, wenn man in der Bedingung keine mit ; oder Zeilenumbruch getrennte Liste erlauben würde. Dazu müsste man aber eben sowohl im Parser als auch in der Doku von "Liste, die nicht durch ... getrennt ist" reden

Antworten |