Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

x"$foobar"

3 views
Skip to first unread message

Herbert Pophal

unread,
Apr 5, 2012, 6:16:54 AM4/5/12
to

Hai,

wer kann mir mal die Augen öffnen und mir sagen, was bei dem Konstrukt

if [ x"$foobar" = x ]; then
...
fi

die "x"e sollen, wenn man doch einfacher

if [ "$foobar" = "" ]; then
...
fi

oder

if [ -z "$foobar" ]; then
...
fi

schreiben könnte.

Sehe ich recht oft, hat sich mir aber noch nicht erschlossen.


Herbert

Martin Vaeth

unread,
Apr 5, 2012, 7:01:59 AM4/5/12
to
Herbert Pophal <pop...@tubit.tu-berlin.de> schrieb:
>
> if [ x"$foobar" = x ]; then
> ...
> fi
>
> die "x"e sollen

Das ist für einige buggy Nicht-POSIX-Shells notwendig, um zu
vermeiden, dass Werte wie foobar=-n oder foobar=! Ärger machen.
Falls im Test die (ebenfalls Nicht-POSIX) Optionen -a oder -o
benutzt werden, braucht man es in fast jedem Fall.
Einer der Hauptgründe, -a und -o konsequent zu meiden.

Sascha Hüdepohl

unread,
Apr 5, 2012, 7:04:54 AM4/5/12
to
Hallo

Herbert Pophal <pop...@tubit.tu-berlin.de> schrieb:

> wer kann mir mal die Augen öffnen und mir sagen, was bei dem Konstrukt
>
> if [ x"$foobar" = x ]; then
> ...
> fi
>
> die "x"e sollen, wenn man doch einfacher

Das wird gemacht, um die Sonderfälle zu berücksichtigen.
Was passiert wenn foobar nicht definiert ist?
Was passiert wenn foobar == "-n"?

Vielleicht in dem Zusammenhang auch interessant:
Heute
$ echo $SHELL
/bin/bash
gilt zwar wohl meistens:
$ type [
[ is a shell builtin
aber es gibt eben auch:
$ which [
/usr/bin/[
was von der Funktion
$ which test
/usr/bin/test
entsprechen dürfte,
für das aber auch gilt:
$ type test
test is a shell builtin

Was wollte ich damit sagen? Vergessen.

Ich benutze heute immer [[. Da gibt es diese Probleme meines Wissens
nicht.

HTH
Sascha

Herbert Pophal

unread,
Apr 5, 2012, 7:33:00 AM4/5/12
to


On 04/05/2012 01:04 PM, Sascha Hüdepohl wrote:
> Hallo
>
> Herbert Pophal <pop...@tubit.tu-berlin.de> schrieb:
>
>> wer kann mir mal die Augen öffnen und mir sagen, was bei dem Konstrukt
>>
>> if [ x"$foobar" = x ]; then
>> ...
>> fi
>>
>> die "x"e sollen, wenn man doch einfacher
>
> Das wird gemacht, um die Sonderfälle zu berücksichtigen.
> Was passiert wenn foobar nicht definiert ist?

Das funktioniert doch aber auch ohne "x", wenn gequotet wird. Damit
hatte ich bislang jedenfalls keine Schwierigkeiten.

> Was passiert wenn foobar == "-n"?

OK. Hatte ich übersehen, weil mir noch nie untergekommen. Danke auch an
Martin für den Hinweis.

>
> [type, which, test]

Bekannt.

> Was wollte ich damit sagen? Vergessen.
>
> Ich benutze heute immer [[. Da gibt es diese Probleme meines Wissens
> nicht.
>
Das bringt mich zu der unangesprochenen zweiten Frage. Trotz
wiederholten Lesens von bash(1) ist es mir noch nicht gelungen, den
grundsätzlichen Unterschied von [ und [[ herauszufinden. Any hints?


Herbert

Sascha Hüdepohl

unread,
Apr 5, 2012, 7:42:41 AM4/5/12
to
Herbert Pophal <pop...@tubit.tu-berlin.de> schrieb:

> Das bringt mich zu der unangesprochenen zweiten Frage. Trotz
> wiederholten Lesens von bash(1) ist es mir noch nicht gelungen, den
> grundsätzlichen Unterschied von [ und [[ herauszufinden. Any hints?

[[ ist auf jeden Fall ein Shell builtin und bietet bei der Bash einige
zusätzliche Möglichkeiten.
Z.B. Regexp:
if [[ ! "$chars" =~ ^[0-9]+$ ]]

Ob und in welchem Umfang es [[ in anderen Shells gibt weiß ich nicht.
Und das dürfte der wichtigste Unterschied sein. Bedeutet: will man
portabel bleiben und nur für sich skripten.

Gruß
Sascha

Sascha Hüdepohl

unread,
Apr 5, 2012, 7:44:11 AM4/5/12
to
Sascha Hüdepohl <sas...@ravenworks.de> schrieb:

> Und das dürfte der wichtigste Unterschied sein. Bedeutet: will man
> portabel bleiben und nur für sich skripten.

s/und/oder/

Martin Vaeth

unread,
Apr 5, 2012, 8:08:55 AM4/5/12
to
Sascha Hüdepohl <sas...@ravenworks.de> wrote:
> Herbert Pophal <pop...@tubit.tu-berlin.de> schrieb:
>
>> Das bringt mich zu der unangesprochenen zweiten Frage. Trotz
>> wiederholten Lesens von bash(1) ist es mir noch nicht gelungen, den
>> grundsätzlichen Unterschied von [ und [[ herauszufinden. Any hints?
>
> [[ ist auf jeden Fall ein Shell builtin

Der Hauptunterschied ist, dass es als Teil der Syntax der Shell
implementiert ist und sich nicht wie ein externes Programm verhält.

Beispielsweise braucht man kein Quoting der Variablen und -
mehr noch - Variablenwerte wie "!" oder "-n" werden keinesfalls
als Tests sondern immer als Werte interpretiert - so etwas wie
[ a "$b" b ]
mit b='!=' ist bei [[ nicht möglich: Das != muss fest im
Quelltext stehen.

> und bietet bei der Bash einige zusätzliche Möglichkeiten.
> Z.B. Regexp:
> if [[ ! "$chars" =~ ^[0-9]+$ ]]

Gerade das Regexp-Beispiel zeigt, dass man [[ meiden sollte,
zumindest bei Bash: Bash hat nämlich die Details von Version
zu Version geändert. Mal wirkt "=" als Regexp-Operator, mal nicht,
dann kommt es darauf an, ob das Argument gequotet ist oder nicht.
Auch für eigene Scripte hat sich Bash damit disqualifiziert.
Aber wenn man mächtigere Funktionen in einer Shell-Sprache
braucht, nimmt man ohnehin besser zsh:
Dort war beispielsweise ein mächtigeres [[ schon lange vor
Bash ohne ständiges Herumdoktorn implementiert.

Herbert Pophal

unread,
Apr 5, 2012, 8:09:03 AM4/5/12
to


On 04/05/2012 01:42 PM, Sascha Hüdepohl wrote:
> Herbert Pophal <pop...@tubit.tu-berlin.de> schrieb:
>
>> Das bringt mich zu der unangesprochenen zweiten Frage. Trotz
>> wiederholten Lesens von bash(1) ist es mir noch nicht gelungen, den
>> grundsätzlichen Unterschied von [ und [[ herauszufinden. Any hints?
>
> [[ ist auf jeden Fall ein Shell builtin und bietet bei der Bash einige
> zusätzliche Möglichkeiten.
> Z.B. Regexp:
> if [[ ! "$chars" =~ ^[0-9]+$ ]]

Ah ja. Das ist mir entgangen. Muss ich mir doch noch mal anschauen.
Anscheinen tritt beim Lesen solcher Sachen immer so ein Ermüdungseffekt
ein...

>
> Ob und in welchem Umfang es [[ in anderen Shells gibt weiß ich nicht.

Ich kenne es noch von der ksh, die mir bislang aber wohl nur unter AIX
zu Gesicht kam, und das ist lange her.

> Und das dürfte der wichtigste Unterschied sein. Bedeutet: will man
> portabel bleiben und nur für sich skripten.

Ja. Portabel bleiben: Also POSIX skripten. Funktioniert auch nicht immer.


Danke.
Herbert

Herbert Pophal

unread,
Apr 5, 2012, 8:19:08 AM4/5/12
to


On 04/05/2012 02:08 PM, Martin Vaeth wrote:
> Sascha Hüdepohl <sas...@ravenworks.de> wrote:
>> Herbert Pophal <pop...@tubit.tu-berlin.de> schrieb:
>>
>>> Das bringt mich zu der unangesprochenen zweiten Frage. Trotz
>>> wiederholten Lesens von bash(1) ist es mir noch nicht gelungen, den
>>> grundsätzlichen Unterschied von [ und [[ herauszufinden. Any hints?
>>
>> [[ ist auf jeden Fall ein Shell builtin
>
> Der Hauptunterschied ist, dass es als Teil der Syntax der Shell
> implementiert ist und sich nicht wie ein externes Programm verhält.

Willst du damit sagen, dass sich der builtin [ wie ein externes Programm
verhält? Oder auch: Was heißt "sich wie ein externes Programm verhalten"?
>
> Beispielsweise braucht man kein Quoting der Variablen und -
> mehr noch - Variablenwerte wie "!" oder "-n" werden keinesfalls

Kann es sein, dass die Auswertung der Arguemnte für [ etwas schlampig ist?

> als Tests sondern immer als Werte interpretiert - so etwas wie
> [ a "$b" b ]
> mit b='!=' ist bei [[ nicht möglich: Das != muss fest im
> Quelltext stehen.

IMHO ein Beispiel für unleserliches Skripting, Operatoren als Variable.

>
>> und bietet bei der Bash einige zusätzliche Möglichkeiten.
>> Z.B. Regexp:
>> if [[ ! "$chars" =~ ^[0-9]+$ ]]
>
> Gerade das Regexp-Beispiel zeigt, dass man [[ meiden sollte,
> zumindest bei Bash: Bash hat nämlich die Details von Version
> zu Version geändert. Mal wirkt "=" als Regexp-Operator, mal nicht,
> dann kommt es darauf an, ob das Argument gequotet ist oder nicht.

WWG. Aber bislang hatte ich [[ ja auch noch nicht verwendet.


Herbert

Juergen P. Meier

unread,
Apr 5, 2012, 8:38:10 AM4/5/12
to
Herbert Pophal <pop...@tubit.tu-berlin.de>:
>
>
> On 04/05/2012 02:08 PM, Martin Vaeth wrote:
>> Sascha Hüdepohl <sas...@ravenworks.de> wrote:
>>> Herbert Pophal <pop...@tubit.tu-berlin.de> schrieb:
>>>
>>>> Das bringt mich zu der unangesprochenen zweiten Frage. Trotz
>>>> wiederholten Lesens von bash(1) ist es mir noch nicht gelungen, den
>>>> grundsätzlichen Unterschied von [ und [[ herauszufinden. Any hints?
>>>
>>> [[ ist auf jeden Fall ein Shell builtin
>>
>> Der Hauptunterschied ist, dass es als Teil der Syntax der Shell
>> implementiert ist und sich nicht wie ein externes Programm verhält.
>
> Willst du damit sagen, dass sich der builtin [ wie ein externes Programm
> verhält? Oder auch: Was heißt "sich wie ein externes Programm verhalten"?

Ja, denn [ ist als externes Programm spezifiziert, und jede
Spezifikationskonforme Shell muss das auch bei Built-in wie ein
externes Programm behandeln (auch wenn es ein Built-in ist).

Das macht sogar die Bash richtig.

>> Beispielsweise braucht man kein Quoting der Variablen und -
>> mehr noch - Variablenwerte wie "!" oder "-n" werden keinesfalls
>
> Kann es sein, dass die Auswertung der Arguemnte für [ etwas schlampig ist?

Nein. Im Gegensatz zu [[ ist die Auswertung der Argumente fuer [ klar
definiert und aendert sich auch von Unterversion der Shell zu
Unterversion nicht (ist also auch von System zu System nicht
unterschiedlich).

>> als Tests sondern immer als Werte interpretiert - so etwas wie
>> [ a "$b" b ]
>> mit b='!=' ist bei [[ nicht möglich: Das != muss fest im
>> Quelltext stehen.
>
> IMHO ein Beispiel für unleserliches Skripting, Operatoren als Variable.

Haha. Versuch doch mal mit [[ den Variablen-Inhalt mit einem
Ausrufezeichen zu vergleichen (!). Probiere es einfach mal aus.

>> Gerade das Regexp-Beispiel zeigt, dass man [[ meiden sollte,
>> zumindest bei Bash: Bash hat nämlich die Details von Version
>> zu Version geändert. Mal wirkt "=" als Regexp-Operator, mal nicht,
>> dann kommt es darauf an, ob das Argument gequotet ist oder nicht.
>
> WWG. Aber bislang hatte ich [[ ja auch noch nicht verwendet.

Gut so, man sollte dieses Konstruckt auch ausserhalb expliziter
Bash-Programmierung (fuer ganz bestimmte Versionen) meiden.

Juergen
--
Juergen P. Meier - "This World is about to be Destroyed!"
end
If you think technology can solve your problems you don't understand
technology and you don't understand your problems. (Bruce Schneier)

Herbert Pophal

unread,
Apr 5, 2012, 9:21:52 AM4/5/12
to


On 04/05/2012 02:38 PM, Juergen P. Meier wrote:
> Herbert Pophal <pop...@tubit.tu-berlin.de>:
>>
>>
>> On 04/05/2012 02:08 PM, Martin Vaeth wrote:
>>> als Tests sondern immer als Werte interpretiert - so etwas wie
>>> [ a "$b" b ]
>>> mit b='!=' ist bei [[ nicht möglich: Das != muss fest im
>>> Quelltext stehen.
>>
>> IMHO ein Beispiel für unleserliches Skripting, Operatoren als Variable.
>
> Haha. Versuch doch mal mit [[ den Variablen-Inhalt mit einem
> Ausrufezeichen zu vergleichen (!). Probiere es einfach mal aus.

Habe ich getan. Und?

Herbert

Sven Mascheck

unread,
Apr 5, 2012, 1:47:29 PM4/5/12
to
Martin Vaeth wrote:
> Das ist für einige buggy Nicht-POSIX-Shells notwendig, um zu
> vermeiden, dass Werte wie foobar=-n oder foobar=! Ärger machen.

Für foobar=! gilt das übrigens auch für ksh88.
Das Problem ist ansonsten typisch für traditionelle Bourne Shells.

Für Neugierige: hier gibt's eine halbautomatisch erstellte
Übersicht über so einige denkbare Variationen.
http://www.in-ulm.de/~mascheck/various/test/
(Da sieht man auch gut, wie knifflig -a und -o sind.)

Alex Schuster

unread,
Apr 9, 2012, 1:48:00 PM4/9/12
to
Herbert Pophal schreibt:

> Das bringt mich zu der unangesprochenen zweiten Frage. Trotz
> wiederholten Lesens von bash(1) ist es mir noch nicht gelungen, den
> grundsätzlichen Unterschied von [ und [[ herauszufinden. Any hints?

Bei [[ ist Quoten nicht notwendig, für a="x x" liefert [ $a ] einen
Fehler. [[ erlaubt auch Dinge wie Regexp-Vergleiche mit =~, oder
Konstrukte wie [[ $a == x || $a == y ]].

Wonko

Martin Vaeth

unread,
Apr 9, 2012, 2:02:48 PM4/9/12
to
Alex Schuster <wo...@wonkology.org> schrieb:
Wobei man dazu sagen sollte, dass sich das alles auch auf kompatible
Art erledigen lässt: Man muss halt Variablen quoten und auf -a und -o
verzichten; letztere kann man durch das Shell-interne || und && ersetzen,
etwa
[ "$a" -eq 5 ] && [ "$b" = ' ' ] || ! test -e "$c"
(ich bevorzuge "test" für File-Tests, aber das ist Geschmacksache).
Für reguläre Ausdrücke gibt es keinen Ersatz, aber i.d.R. genügen
Konstrukte mit "case". Statt [[ $a =~ /^[0-9]*$/ ]] etwa
case $a in
*[!0-9]*) printf '%s ist keine Zahl\n' "$a";;
esac
0 new messages