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

Umgebungsvariablen implizite Werte LC_* nicht abrufbar, locale zeigt sie an

0 views
Skip to first unread message

Marco Moock

unread,
Oct 14, 2022, 4:17:02 AM10/14/22
to
Hallo zusammen,

ich versuche gerade die Variablen LC_CTYPE, LC_NUMERIC usw. in einem
Debian per echo abzurufen, die scheinen aber leer zu sein.
Der Befehl locale zeigt diese aber mit einem Wert in
Anführungszeichen an.

m@8200cmt:~$ locale
LANG=de_DE.UTF-8
LANGUAGE=
LC_CTYPE="de_DE.UTF-8"
LC_NUMERIC="de_DE.UTF-8"
LC_TIME="de_DE.UTF-8"
LC_COLLATE="de_DE.UTF-8"
LC_MONETARY="de_DE.UTF-8"
LC_MESSAGES="de_DE.UTF-8"
LC_PAPER="de_DE.UTF-8"
LC_NAME="de_DE.UTF-8"
LC_ADDRESS="de_DE.UTF-8"
LC_TELEPHONE="de_DE.UTF-8"
LC_MEASUREMENT="de_DE.UTF-8"
LC_IDENTIFICATION="de_DE.UTF-8"
LC_ALL=
m@8200cmt:~$ echo $LC_CTYPE

m@8200cmt:~$

env listet nur LANG, aber nicht die LC_*-Variablen.

Sind das spezielle Variablen oder wie funktionieren diese "impliziten
Werte" (Inhalt in Anführungszeichen laut Manpage)?
Für was sind die gut, wenn sie nicht als Umgebungsvariable genutzt
werden können?

--
Gruß
Marco

Michael Bäuerle

unread,
Oct 14, 2022, 5:51:55 AM10/14/22
to
Ja, sie gehören zum POSIX Locale-System:
<https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap07.html>

> oder wie funktionieren diese "impliziten
> Werte" (Inhalt in Anführungszeichen laut Manpage)?

Das ist hier beschrieben:
<https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html#tag_08_02>
Wenn LC_ALL gesetzt ist, dann wird für alle anderen LC_*-Variablen
dessen Wert verwendet.
Wenn LC_ALL nicht, aber LANG gesetzt ist, dann wird dessen Wert für alle
nicht gesetzten LC_*-Variablen (außer LC_ALL) als Default verwendet.

> Für was sind die gut, wenn sie nicht als Umgebungsvariable genutzt
> werden können?

Ein Programm kann die Funktion setlocale() aufrufen, dadurch werden die
LC_*-Variablen wie oben beschrieben ausgewertet:
<https://pubs.opengroup.org/onlinepubs/9699919799/functions/setlocale.html>

Sieghard Schicktanz

unread,
Oct 14, 2022, 4:14:29 PM10/14/22
to
Hallo Marco,

Du schriebst am Fri, 14 Oct 2022 10:17:01 +0200:

> ich versuche gerade die Variablen LC_CTYPE, LC_NUMERIC usw. in einem
> Debian per echo abzurufen, die scheinen aber leer zu sein.

Bzw. garnicht vorhanden, weil nicht gesetzt.

> Der Befehl locale zeigt diese aber mit einem Wert in
> Anführungszeichen an.

D.h. sie sind nicht gesetzt, und "locale" gibt dafür Voreinstellwerte
aus.

> env listet nur LANG, aber nicht die LC_*-Variablen.

Es müßte mindestens "LC_ALL" als _leer_ listen, und dau alle _explizit_
gesetzten LC_-Variablen. Schaut bei mir so aus:

$ locale
LANG=de_DE.UTF-8
LC_CTYPE="de_DE.UTF-8"
LC_NUMERIC="de_DE.UTF-8"
LC_TIME="de_DE.UTF-8"
LC_COLLATE=C
LC_MONETARY="de_DE.UTF-8"
LC_MESSAGES=C
LC_PAPER="de_DE.UTF-8"
LC_NAME="de_DE.UTF-8"
LC_ADDRESS="de_DE.UTF-8"
LC_TELEPHONE="de_DE.UTF-8"
LC_MEASUREMENT="de_DE.UTF-8"
LC_IDENTIFICATION="de_DE.UTF-8"
LC_ALL=
$ env | grep LC_
LC_MESSAGES=C
LC_ALL=
LC_COLLATE=C

D.h. ich habe die beiden mit "C" beseetzten Werte explizit zugewiesen
(wobei "LC_COLLATE" eher ein Relikt von Experimenten ist), und die
werden dann auch beücksichtigt. Ich habe dann die voreingestellten
(englischen) Meldungsausgaben der Programme anstatt der meistens
kauderwelschen "deutschen".

> Sind das spezielle Variablen oder wie funktionieren diese "impliziten
> Werte" (Inhalt in Anführungszeichen laut Manpage)?

Sind das, die sind für andere Zwecke nicht recht brauchbar, weil sie
eben implizit von den "locale"-Funktionen benutzt werden.

> Für was sind die gut, wenn sie nicht als Umgebungsvariable genutzt
> werden können?

S.o. - sie _könn(t(en_ zwar für andere Zwecke benutzt werden, nur
"könnte" das ggfs. uner(warte|wünsch)te Nebenwirkungen haben...

--
(Weitergabe von Adressdaten, Telefonnummern u.ä. ohne Zustimmung
nicht gestattet, ebenso Zusendung von Werbung oder ähnlichem)
-----------------------------------------------------------
Mit freundlichen Grüßen, S. Schicktanz
-----------------------------------------------------------

Michael Bäuerle

unread,
Oct 15, 2022, 3:43:06 AM10/15/22
to
Sieghard Schicktanz wrote:
>
> Es müßte mindestens "LC_ALL" als _leer_ listen, und dau alle _explizit_
> gesetzten LC_-Variablen.

Wenn "LC_ALL" nicht definiert ist sollte das den gleichen Effekt haben:
<https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html#tag_08_01>
|
| The values of locale categories shall be determined by a precedence
| order; the first condition met below determines the value:
|
| 1. If the LC_ALL environment variable is defined and is not null,
| the value of LC_ALL shall be used.
| [...]

Aus dem vorherigen Text geht hervor, dass mit "null" das NUL-Byte am
Ende eines Strings gemeint ist. Hier sollte also der Wert LC_ALL="" den
gleichen Effekt haben wie eine nicht definierte Variable.
Das könnte möglicherweise undefinierte Effekte ergeben:
<https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap07.html#tag_07_01>
|
| [...]
| If different character sets are used by the locale categories, the
| results achieved by an application utilizing these categories are
| undefined.
| [...]

Bei dem HP-UX, auf dem ich diesen Artikel schreibe, gibt es mehrere
C-Locales:
|
| # locale -a
|
| C
| POSIX
| C.iso88591
| C.iso885915
| C.utf8
| [...]

Die Locale "C" verwendet auf diesem System nicht die Codierung UTF-8:
|
| # LC_ALL=C locale -k code_set_name
| code_set_name="roman8"
| # LC_ALL=C.utf8 locale -k code_set_name
| code_set_name="utf8"

LANG=de_DE.utf8
LC_MESSAGES=C

könnte auf meinem System demnach undefiniertes Verhalten ergeben (sofern
das System nicht ausdrücklich etwas anderes dokumentiert).


BTW: Das HP-UX ist etwas alt. Auf modernen Systemen sollte das so
auslesbar sein:
|
| $ LC_ALL=C locale -k charmap

Sieghard Schicktanz

unread,
Oct 15, 2022, 4:13:06 PM10/15/22
to
Hallo Michael,

Du schriebst am Sat, 15 Oct 2022 07:42:34 -0000:

> Wenn "LC_ALL" nicht definiert ist sollte das den gleichen Effekt
> haben:

De n gleichen Effekt WIE? Da fehlt der Bezug.

> |
> | The values of locale categories shall be determined by a precedence
> | order; the first condition met below determines the value:
> |
> | 1. If the LC_ALL environment variable is defined and is not
> | null, the value of LC_ALL shall be used.
> | [...]
>
> Aus dem vorherigen Text geht hervor, dass mit "null" das NUL-Byte am
> Ende eines Strings gemeint ist. Hier sollte also der Wert LC_ALL=""

Nein, das geht daraus _NICHT_ hervor. Was daraus hervorgeht, ist, daß
eine auf den _Leerstring_ gesetzte Variable äquivalent zu einer nicht
definierten ist.

> den gleichen Effekt haben wie eine nicht definierte Variable.

Das ist damit korrekt.

...
> > D.h. ich habe die beiden mit "C" beseetzten Werte explizit
...
> Das könnte möglicherweise undefinierte Effekte ergeben:

Das laß' dann mal durchaus meine Sorge sein.

> | [...]
> | If different character sets are used by the locale categories, the
> | results achieved by an application utilizing these categories are
> | undefined.
> | [...]

Ja, wenn Du z.B. kyrillisch und latin mischt ist das recht
wahrscheinlich. Nachdem ich aber eine "de"-locale benutze und "C" die
ur-amerikanische ASCII-locale mit nur 7-bit-Zeichencodes ist, ist
aufgrund der vollständigen Überlappung der Zeichencodes hier kein
Problem zu erwarten. (BTW, es sind auch "noch" keine aufgetreten.)

> Bei dem HP-UX, auf dem ich diesen Artikel schreibe, gibt es mehrere
> C-Locales:
...
> | C
...
> | C.iso88591
> | C.iso885915
> | C.utf8
> | [...]

Schön. Da hat also wer die dafür zulässigen Zeichencodes erweitert.

> Die Locale "C" verwendet auf diesem System nicht die Codierung UTF-8:

Aber die "Codierung" "UTF-8" benutzt für die Menge der ASCII-Zeichen
dieselben Zeichencodes.

> LANG=de_DE.utf8
> LC_MESSAGES=C
>
> könnte auf meinem System demnach undefiniertes Verhalten ergeben
> (sofern das System nicht ausdrücklich etwas anderes dokumentiert).

Nur, sofern eine der Definitionen _NICHT_ die originalen ASCII-Codes
1:1 enthält. Darfst Du gerne selber sicherstellen, ich mach' das jetzt
nicht auch noch.

Helmut Waitzmann

unread,
Oct 15, 2022, 5:26:38 PM10/15/22
to
Marco Moock <mo...@posteo.de>:

> ich versuche gerade die Variablen LC_CTYPE, LC_NUMERIC usw. in einem
> Debian per echo abzurufen, die scheinen aber leer zu sein.
> Der Befehl locale zeigt diese aber mit einem Wert in
> Anführungszeichen an.

Der Befehl «locale» zeigt nicht die Umgebungsvariablen an sondern
die Werte für die Locale‐Kategorien, die anhand der Belegung der
Umgebungsvariablen gemäß der Beschreibung in
<https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html#tag_08_02>
ermittelt worden sind.

> m@8200cmt:~$ locale
> LANG=de_DE.UTF-8
> LANGUAGE=
> LC_CTYPE="de_DE.UTF-8"
> LC_NUMERIC="de_DE.UTF-8"
> LC_TIME="de_DE.UTF-8"
> LC_COLLATE="de_DE.UTF-8"
> LC_MONETARY="de_DE.UTF-8"
> LC_MESSAGES="de_DE.UTF-8"
> LC_PAPER="de_DE.UTF-8"
> LC_NAME="de_DE.UTF-8"
> LC_ADDRESS="de_DE.UTF-8"
> LC_TELEPHONE="de_DE.UTF-8"
> LC_MEASUREMENT="de_DE.UTF-8"
> LC_IDENTIFICATION="de_DE.UTF-8"
> LC_ALL=

In Anführungszeichen stehen dabei die Werte der Locale‐Kategorien,
die nicht direkt von der Umgebungsvariablen gleichen Namens
sondern von den Umgebungsvariablen «LC_ALL» oder «LANG» herrühren.

> m@8200cmt:~$ echo $LC_CTYPE
>
> m@8200cmt:~$
>
> env listet nur LANG, aber nicht die LC_*-Variablen.
>

«env» zeigt die vorhandenen Umgebungsvariablen, nicht mehr und
nicht weniger.  Eine Interpretation der «LC_*»‐Umgebungsvariablen
nimmt es nicht vor.

> Sind das spezielle Variablen oder wie funktionieren diese "impliziten
> Werte" (Inhalt in Anführungszeichen laut Manpage)?

Es sind ganz normale Umgebungsvariable, speziell sind sie nicht. 
Speziell ist nur ihre Interpretation im Locale‐System.

Nebenbei:  Einfache Variablenauswertung im Shell ist nicht
geeignet, verlässlich das Vorhandensein einer Umgebungsvariablen
festzustellen, weil die Variablenauswertung im Shell auch die
Inhalte von Shell‐Variablen, die nicht gleichzeitig Teil der
Umgebungsvariablen sind, in Betracht zieht.

Um zu prüfen, ob eine Umgebungsvariable vorhanden ist, und dann
ihren Inhalt auszugeben, verwende das Programm «printenv»: 
Angewendet auf den Namen einer nicht vorhandenen
Umgebungsvariablen, liefert es einen Exit‐Status ungleich 0;
angewendet auf auf den Namen einer vorhandenen
Umgebungsvariablen, versucht es, deren Inhalt in die
Standardausgabe zu schreiben, und liefert bei Erfolg den
Exit‐Status 0.

Leider ist «printenv» nicht Teil des POSIX‐Standards.


Meines Wissens gibt es keine Möglichkeit, den Shell direkt danach
zu fragen, ob eine Shell‐Variable auch Teil der
Umgebungsvariablen – genauer: zum Export in die Umgebung
markiert – ist.

> Für was sind die gut, wenn sie nicht als Umgebungsvariable
> genutzt werden können?

Sie steuern das Locale‐System.  Ich rate davon ab, sie unabhängig
davon als Umgebungsvariable (für andere Zwecke) zu nutzen.

Marcel Logen

unread,
Oct 15, 2022, 6:15:57 PM10/15/22
to
Helmut Waitzmann in de.comp.os.unix.shell:

[...]

Danke für Deinen aufschlußreichen Artikel. Ich habe ihn hier
gleich mal gespeichert.

>Meines Wissens gibt es keine Möglichkeit, den Shell direkt danach zu
>fragen, ob eine Shell‐Variable auch Teil der Umgebungsvariablen –
>genauer: zum Export in die Umgebung markiert – ist.

In der bash: "declare -p" ("typeset -p")?

| user@debian:~$ declare -p | grep -e 'LANG' -e 'LC_'
| declare -x LANG="en_US.UTF-8"
| declare -x LANGUAGE=""
| user@debian:~$

Marcel asjb (356971)
--
──────╮ ╭─╮ ╭─────────────────╮ ╭───╮ ╭─╮ ╭─╮ ╭─
╰─╯ ╰──╮ ╰────╮ ╭─────╯ │ ╰───╯ ╰───╮ ╭───╯ │ ╭─╯
╭───╯ ╭──╮ ╰─╮ ╭─╯ │ │ ╭───╮ ╰─╮ │ │
╰─────╯ ╰────╯ ╰──────────╯ 59f36b ╰─╯ ╰────╯ ╰─╯

Christian Garbs

unread,
Oct 15, 2022, 6:31:39 PM10/15/22
to
Mahlzeit!

Helmut Waitzmann <nn.th...@xoxy.net> wrote:

> Um zu prüfen, ob eine Umgebungsvariable vorhanden ist, und dann
> ihren Inhalt auszugeben, verwende das Programm «printenv»: 
> Angewendet auf den Namen einer nicht vorhandenen
> Umgebungsvariablen, liefert es einen Exit‐Status ungleich 0;
> angewendet auf auf den Namen einer vorhandenen
> Umgebungsvariablen, versucht es, deren Inhalt in die
> Standardausgabe zu schreiben, und liefert bei Erfolg den
> Exit‐Status 0.

printenv schaut sich aber nur die exportierten Variablen an, oder?

$ A=y printenv A

gibt 'y' aus

$ A=x
$ printenv A

gibt den Exit-Status 1 zurück.

Geht das auch irgendwie für nicht-exportierte Variablen?

Ich hab's mit der Bash und der Expansion ${parameter:-word} probiert,
aber da werden "unset" und "null" genau gleich behandelt, das taugt
also nicht zur Unterscheidung.

'set -u' gefolgt von einem Zugriff auf die Variable währe wohl eine
Möglichkeit, das ist aber nicht gerade toll.

Gruß
Christian
--
....Christian.Garbs....................................https://www.cgarbs.de
The Heineken Uncertainty Principle:
You can never be sure how many beers you had last night.

Helmut Waitzmann

unread,
Oct 16, 2022, 1:36:06 AM10/16/22
to
Marcel Logen <33320000...@ybtra.de>:
> Helmut Waitzmann in de.comp.os.unix.shell:
>
>> Meines Wissens gibt es keine Möglichkeit, den Shell direkt
>> danach zu fragen, ob eine Shell‐Variable auch Teil der
>> Umgebungsvariablen – genauer: zum Export in die Umgebung
>> markiert – ist.
>
> In der bash: "declare -p" ("typeset -p")?
>
> | user@debian:~$ declare -p | grep -e 'LANG' -e 'LC_'
> | declare -x LANG="en_US.UTF-8"
> | declare -x LANGUAGE=""
> | user@debian:~$

Das funktioniert auch und ist ebenso wenig wie «printenv» im
POSIX‐Standard enthalten.  «printenv» hat nach meinem Bauchgefühl
den Vorteil, dass mir noch kein Unix‐System, weder HP-UX, weder
Solaris noch Linux, unter die Augen gekommen ist, wo es nicht
enthalten gewesen wäre.  Wie sieht es in anderen Unixen aus?

Ich habe keine Ahnung, warum «printenv» es nicht in den
POSIX‐Standard geschafft hat.

Als selbständiges Programm funktioniert «printenv» mit jedem
Shell.  Im Gegensatz dazu gibt es im «dash» (Debian Almquist
Shell) weder «declare» noch «typeset».

Helmut Waitzmann

unread,
Oct 16, 2022, 1:36:07 AM10/16/22
to
Christian Garbs <mi...@cgarbs.de>:
> Helmut Waitzmann <nn.th...@xoxy.net> wrote:
>
>> Um zu prüfen, ob eine Umgebungsvariable vorhanden ist, und dann
>> ihren Inhalt auszugeben, verwende das Programm «printenv»: 
>> Angewendet auf den Namen einer nicht vorhandenen
>> Umgebungsvariablen, liefert es einen Exit‐Status ungleich 0;
>> angewendet auf auf den Namen einer vorhandenen
>> Umgebungsvariablen, versucht es, deren Inhalt in die
>> Standardausgabe zu schreiben, und liefert bei Erfolg den
>> Exit‐Status 0.
>
> printenv schaut sich aber nur die exportierten Variablen an,
> oder?

Ja, genau:  Es schaut nur in seinen eigenen Umgebungsvariablen
(die es beim Start vom Shell erhalten hat) nach.  (Und das war ja
auch der Grund, weshalb ich es zur Verwendung vorgeschlagen
habe.)

> Geht das auch irgendwie für nicht-exportierte Variablen?
>

Du meinst, zu prüfen, ob es eine Variable gibt oder nicht?  Ja,
das geht.

> Ich hab's mit der Bash und der Expansion ${parameter:-word}
> probiert,

Fast richtig, und du bist nah dran:  Schau dir im Shell‐Handbuch
auch die anderen Varianten der «${parameter…}»‐Expansionen an;
da ist die richtige mit dabei.

> aber da werden "unset" und "null" genau gleich behandelt, das
> taugt also nicht zur Unterscheidung.

Ja, die Gleichbehandlung folgt direkt aus dem Doppelpunkt hinter
dem Namen des Parameters.

Nimm statt «${parameter:-word}» «${parameter+word}» (mit Absicht
ohne Doppelpunkt nach dem Parameter‐Namen), und für «word» nimm
«:»:

${parameter+:} false

Das bedeutet:  Falls es den Shell‐Parameter (Shell‐Variablen
gehören auch zu den Shell‐Parametern) «parameter» gibt (egal,
welchen Inhalt er hat!), liefere das, was hinter dem Pluszeichen
steht, als Ergebnis der Auswertung.  Falls es den Shell‐Parameter
nicht gibt, liefere zunächst die leere Zeichenkette, die aber,
weil der Ausdruck nicht in Anführungszeichen steht, im Verlauf
des word splittings zu buchstäblich nichts zerfällt.

Daraus ergeben sich die beiden folgenden Fälle:


Gibt es den Parameter, entsteht das simple command


: false


Gibt es den Parameter nicht, entsteht das simple command


false


«:» ist ein in den Shell eingebautes Kommando, das, wenn es
gestartet wird, nichts anderes macht, als mit Exit‐Status 0 zu
Ende zu kommen, egal, ob es irgendwelche Parameter (in diesem
Fall den Parameter «false») erhalten hat.

«false» ist ein (meistens in den Shell eingebautes) Kommando, das
keine Parameter erhalten soll und, wenn es gestartet wird, nichts
anderes macht, als mit einem Exit‐Status ungleich 0 zu Ende zu
kommen.


=> Der Exit‐Status von


${parameter+:} false

gibt Auskunft darüber, ob es den Shell‐Parameter «parameter» gibt
(Exit‐Status 0) oder nicht (Exit‐Status ungleich 0).


Anwendung:

if ${parameter+:} false
then
printf \
'Der Parameter %s hat den Inhalt %s.\n' \
parameter "$parameter"
else
printf \
'Den Parameter %s gibt es nicht.\n' \
parameter
fi


Als Variante kann man noch im Hinterkopf behalten (für den Fall,
dass man es mal brauchen sollte):


${parameter:+:} false

prüft, ob es den Parameter «parameter» gibt und er einen
nicht‐leeren Inhalt hat.

Die Parameter‐Expansionen «${parameter+word}»,
«${parameter:+word}», «${parameter-word}», und
«${parameter:-word}» sind im POSIX‐Standard enthalten.

Marcel Logen

unread,
Oct 16, 2022, 6:10:40 AM10/16/22
to
Helmut Waitzmann in de.comp.os.unix.shell:

>Marcel Logen <33320000...@ybtra.de>:

>>In der bash: "declare -p" ("typeset -p")?
[...]

>Das funktioniert auch und ist ebenso wenig wie «printenv» im
>POSIX‐Standard enthalten.  «printenv» hat nach meinem Bauchgefühl den
>Vorteil, dass mir noch kein Unix‐System, weder HP-UX, weder Solaris noch
>Linux, unter die Augen gekommen ist, wo es nicht enthalten gewesen
>wäre.  Wie sieht es in anderen Unixen aus?

Bei meinem OpenBSD ist "printenv" als Programm dabei.

| t20$ type printenv
| printenv is /usr/bin/printenv
| t20$

Die mitgelieferte ksh (@(#)PD KSH v5.2.14 99/07/13.2) hat
"typeset" eingebaut.

Aus "man ksh", Abschnitt "typeset":

| Display or set parameter attributes. With no name arguments,
| parameter attributes are displayed; if no options are used, the
| current attributes of all parameters are printed as typeset
| commands; [...]

Marcel bsch (389521)
--
╭────╮ ╭───────╮ ╭─╮ ╭─────────────╮
╰──╮ ╰─╮ ╭───╮ ╭─╮ ╭─────╮ ╰─────╮ ╰─╯ ╰──╮ ╰───────╮ ╰
╮ ╭─╯ ╰─╯ ╰─╮ ╭─╯ │ ╰──╮ ╰─╮ ╰─╮ ╭─╯ ╭───╮ ╭──╯
╰─╯ ╰─╯ ╰──────────╯ ╰────────╯ ╰───╯ ╰─╯ 9a3ad3

Christian Weisgerber

unread,
Oct 16, 2022, 8:30:05 AM10/16/22
to
On 2022-10-16, Helmut Waitzmann <nn.th...@xoxy.net> wrote:

> Das funktioniert auch und ist ebenso wenig wie «printenv» im
> POSIX‐Standard enthalten.  «printenv» hat nach meinem Bauchgefühl
> den Vorteil, dass mir noch kein Unix‐System, weder HP-UX, weder
> Solaris noch Linux, unter die Augen gekommen ist, wo es nicht
> enthalten gewesen wäre.  Wie sieht es in anderen Unixen aus?

Historisch ist es von BSD; hat sich wohl zusammen mit vi(1) und
csh(1) verbreitet.

/*
* printenv
*
* Bill Joy, UCB
* February, 1979
*/

https://github.com/jonathangray/csrg/commit/6c96ff650a07bc8d0111f269ea68f03161b46f2e

--
Christian "naddy" Weisgerber na...@mips.inka.de

Christian Garbs

unread,
Oct 16, 2022, 11:41:02 AM10/16/22
to
Mahlzeit!

Helmut Waitzmann <nn.th...@xoxy.net> wrote:
> Christian Garbs <mi...@cgarbs.de>:

[Prüfung auf das Vorhandensein nicht exportierter Variablen]

>> Ich hab's mit der Bash und der Expansion ${parameter:-word}
>> probiert,
>
> Fast richtig, und du bist nah dran:  Schau dir im Shell‐Handbuch
> auch die anderen Varianten der «${parameter…}»‐Expansionen an;
> da ist die richtige mit dabei.

Ist sie nicht, jedenfall nicht in der Liste :-)

Dein Hinweis hat mich aber dazu gebracht, nochmal den ganzen Abschnitt
durchzulesen. Die Varianten ohne Doppelpunkt sind _nicht_ explizit
aufgeführt, stattdessen steht folgender Absatz obendrüber:

| When not performing substring expansion, using the forms documented
| below (e.g., :-), bash tests for a parameter that is unset or null.
| Omitting the colon results in a test only for a parameter that is
| unset.


> ${parameter+:} false

Ah, der Trick. Danke!
Den sah ich schon mal, hab ich aber noch nicht in meinem aktiven
Wortschatz.


> Als Variante kann man noch im Hinterkopf behalten (für den Fall,
> dass man es mal brauchen sollte):
>
>
> ${parameter:+:} false
>
> prüft, ob es den Parameter «parameter» gibt und er einen
> nicht‐leeren Inhalt hat.

Das ist dann doch aber nur eine kompliziertere Schreibweise von

[ "$parameter" ]

oder gibt es da noch Randbedingungen, die mir gerade entgehen?


Grüße!
Christian
--
....Christian.Garbs....................................https://www.cgarbs.de
A farmer is a man outstanding in his field.

Helmut Waitzmann

unread,
Oct 16, 2022, 7:35:08 PM10/16/22
to
Christian Garbs <mi...@cgarbs.de>:
> Helmut Waitzmann <nn.th...@xoxy.net> wrote:

>> Als Variante kann man noch im Hinterkopf behalten (für den Fall,
>> dass man es mal brauchen sollte):
>>
>>
>> ${parameter:+:} false
>>
>> prüft, ob es den Parameter «parameter» gibt und er einen
>> nicht‐leeren Inhalt hat.
>
> Das ist dann doch aber nur eine kompliziertere Schreibweise von
>
>
> [ "$parameter" ]
>
> oder gibt es da noch Randbedingungen, die mir gerade entgehen?
>

Gemäß dem POSIX‐Standard liefert das dasselbe Ergebnis, wenn die
Shell‐Option «-u» («Betrachte den Versuch, einen
nicht‐vorhandenen Parameter zu expandieren, als Fehler, der den
Kommando‐Start verhindert.») ausgeschaltet ist.

Daher müsste das Kommando also, um von der Stellung der
Shell‐Option «-u» unabhängig zu sein, so aussehen:

[ "${parameter-}" ]


Ich sehe aber zwei Gründe, die mich das andere Verfahren
vorziehen lassen:

Erstens traue ich trotz des POSIX‐Standards nicht so recht, was
das Kommando «[» (was nur ein zweiter Name für das Kommando
«test» ist, s. u.) tut, wenn «"$parameter"» beispielsweise zu
«!», «(» oder «)» expandiert.  Sven Mascheck hat dazu
Untersuchungen mit verschiedenen (historischen) Implementationen
angestellt (<https://www.in-ulm.de/~mascheck/various/test/>) und
vom POSIX‐Standard abweichendes Verhalten gefunden.

Um diese Unterschiede zu umgehen, würde ich also das Kommando
abändern und lieber so schreiben:

[ "${parameter:+vorhanden_und_nicht_leer}" ]

Das liefert im Fall, dass der Parameter einen nicht‐leeren Inhalt
hat, den auch für «[» (oder «test») ungefährlichen Aufruf

[ 'vorhanden_und_nicht_leer' ]

und im Fall, dass der Parameter nicht vorhanden oder zwar
vorhanden, aber leer ist, den Aufruf

[ '' ]


Wegen «"${parameter:-vorhanden_und_nicht_leer}"» schaut sich
bereits der Shell an, ob es den Parameter gibt und er einen
nicht‐leeren Inhalt hat und liefert, wenn das der Fall ist, den
Ersatzwert «vorhanden_und_nicht_leer», ansonsten den Ersatzwert
«».  Damit werden beide Tests: das Vorhandensein und das
Nicht‐leer‐Sein des Parameters bereits vom Shell erledigt.

Dann aber ist es, wenn man es sich genau überlegt, unsinnig, den
Shell dem Kommando «[» bzw. «test» einen Parameter übergeben zu
lassen, von dem er den Inhalt bereits kennt und von dem er daher
auch bereits wissen könnte, was «[» als Exit‐Status liefern
wird.


Im Gegensatz dazu nutzt das Kommando


${parameter:+:} false

das aus:  Der Shell weiß bereits, ehe er das Kommando
zusammenstellt, über das Vorhandensein und den Inhalt des
Parameters bescheid und entscheidet dann, ob er das (interne)
Kommando

: false


oder das möglicherweise externe Kommando


false

aufruft.  Weil das Aufrufen eines externen Kommandos im Vergleich
zu dem, was der Shell intern rechnen muss, sehr viel aufwendiger
ist, kann man, wenn man will, sich noch eine Shell‐Funktion mit
Namen «false» definieren (wenn der Shell kein eingebautes
Kommando «false» kennt), um das Starten des externen Programms
«false» zu verhindern:

false()
{
! :
}


Anmerkung:  Man fällt leicht darauf herein, im Kommando


[ "${parameter:+vorhanden_und_nicht_leer}" ]

die eckigen Klammern für Teil der Shell‐Grammatik zu halten.  Das
entspricht aber nicht der Wirklichkeit:  «[» ist wie
beispielsweise «test», «echo» oder «ls» ein simple command, nur
mit dem Unterschied zu «test», dass «[» als letzten Parameter
noch «]» verlangt, damit der Kommando‐Aufruf «schön aussieht»
(und dem Anwender ein X für ein U vormacht); während «test» auf
solchen Firlefanz verzichtet.

Dass es sich bei «[ … ]» wirklich nicht um Shell‐Syntax handelt,
kann man sehen, wenn man dem Shell die beiden folgenden
Kommandozeilen vorlegt und seine Reaktion darauf vergleicht:

{
( true ; printf 'Exit-Status: %s\n' "$?"
}

{
[ true ; printf 'Exit-Status: %s\n' "$?"
}

Christian Weisgerber

unread,
Oct 18, 2022, 2:30:05 PM10/18/22
to
On 2022-10-16, Helmut Waitzmann <nn.th...@xoxy.net> wrote:

>> Das ist dann doch aber nur eine kompliziertere Schreibweise von
>>
>> [ "$parameter" ]
>
> Erstens traue ich trotz des POSIX‐Standards nicht so recht, was
> das Kommando «[» (was nur ein zweiter Name für das Kommando
> «test» ist, s. u.) tut, wenn «"$parameter"» beispielsweise zu
> «!», «(» oder «)» expandiert.

Oder zu irgendeinem test(1)-Operator, weshalb ich schon

[ -n "$parameter" ]

nehme.

Helmut Waitzmann

unread,
Oct 18, 2022, 5:32:16 PM10/18/22
to
Christian Weisgerber <na...@mips.inka.de>:
> On 2022-10-16, Helmut Waitzmann <nn.th...@xoxy.net> wrote:
>
>
>>> Das ist dann doch aber nur eine kompliziertere Schreibweise
>>> von
>>>
>>> [ "$parameter" ]
>>
>> Erstens traue ich trotz des POSIX‐Standards nicht so recht,
>> was das Kommando «[» (was nur ein zweiter Name für das
>> Kommando «test» ist, s. u.) tut, wenn «"$parameter"»
>> beispielsweise zu «!», «(» oder «)» expandiert.
>
> Oder zu irgendeinem test(1)-Operator, weshalb ich schon
>
>
> [ -n "$parameter" ]
>
> nehme.

Ja, dafür ist das Prädikat «-n» gedacht.  Sven Maschecks Tabelle
zeigt aber leider auch Fälle mit «-n», die nicht so funktionieren,
wie sie sollten.
0 new messages