expertenaustausch > comp.os.* > comp.os.unix.shell

Helmut Waitzmann (31.05.2020, 10:03)
Marc Haber <mh+usenetspam1118>:

>Ich frage nur, weil Debian /bin/sh früher als bash hatte, heute
>als dash. Da sind die Leute reihenweise auf die Nase gefallen:
>Die dash ist zwar massiv schneller, hat aber weniger bashismen.


Dem Dash fehlt vor allem die Fähigkeit, mit UTF-8 umzugehen:

Wer nicht will, dass der Shell UTF-8?Codepoints in Bytes zerlegt,
ist gut beraten, in Debian Buster «dash» nicht zu benutzen: 

Wenn man in Debian Buster in einem UTF-8?Locale das Shell?Kommando

(
for shell in bash dash
do
bash -c -- 'set -x && "$@"' bash \
exec -a sh -- "$shell" -c -- 'printf %s\\n "${#1}"' sh ä
done
)

laufen lässt, erhält man folgende Ausgabe:

+ exec -a sh -- bash -c -- 'printf %s\\n "${#1}"' sh ä
1
+ exec -a sh -- dash -c -- 'printf %s\\n "${#1}"' sh ä
2

Beobachtung:

Der als «sh» gestartete Bash (d.?h. in POSIX?Betriebsart) sieht
das UTF-8?Zeichen «ä» als 1 Codepoint, während der als «sh»
gestartete Dash dasselbe «ä» als 2 Bytes sieht. 

Folgerung:

Dash erfasst in einem UTF-8?Locale UTF-8?Zeichen nicht als
Codepoints sondern als Byte?Folge. 

Folgerung für mich:  Vor die Entscheidung gestellt, ob ich lieber
einen schnellen nicht utf-8?fähigen Shell (Dash) oder lieber einen
langsamen utf-8?fähigen Shell (Bash) laufen lasse, entscheide ich
mich für den langsamen Shell, weil ich ein UTF-8?Locale betreiben
will. 

Erklärung zum oben angeführten Bash?Kommando: 

exec -a sh -- bash -c -- 'printf %s\\n "${#1}"' sh ä

ruft einen «bash» unter dem Namen «sh» auf, ähnlich, wie wenn
beispielsweise «/bin/sh» ein symbolic link auf «bash» wäre. 

Entsprechend ruft

exec -a sh -- dash -c -- 'printf %s\\n "${#1}"' sh ä

einen «dash» als «sh» auf, ähnlich, als wäre «/bin/sh» ein
symbolic link auf «dash». 

Vorschlag: Crosspost & Followup-To: de.comp.os.unix.shell
Juergen Ilse (31.05.2020, 18:01)
Hallo,

In de.comp.os.unix.shell Helmut Waitzmann <nn.throttle> wrote:
[..]
> done
> )
> laufen lässt, erhält man folgende Ausgabe:


Wer in shell-scripts UTF-8 verwendet, dem sollte man den Rechner wegnehmen
und ihn nie mehr naeher als 1 km in die Naehe einer Tastatur lassen.

Tschuess,
Juergen Ilse (juergen)
Helmut Waitzmann (01.06.2020, 05:51)
Juergen Ilse <news>:
>In de.comp.os.unix.shell Helmut Waitzmann <nn.throttle> wrote:


>> Dem Dash fehlt vor allem die Fähigkeit, mit UTF-8 umzugehen:


>Wer in shell-scripts UTF-8 verwendet, dem sollte man den Rechner
>wegnehmen und ihn nie mehr naeher als 1 km in die Naehe einer
>Tastatur lassen.


Quatsch. 

Der POSIX?Standard
(<https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_02>)
legt fest, dass ein zu POSIX kompatibles Shell bei

${#parameter}

die Anzahl der Zeichen (characters) zählt. 

Unter «character» versteht der POSIX?Standard
(<https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_87>)
«A sequence of one or more bytes representing a single graphic
symbol or control code».
Juergen Ilse (02.06.2020, 12:51)
Hallo,

Helmut Waitzmann <nn.throttle> wrote:
> Juergen Ilse <news>:
> Quatsch. 


Nein, kein Quatsch. Es gibt nun mal (ob es einem gefaellt oder nicht) shells,
die den aktuellen PROSIX-Standard nicht (oder nicht vollstaendig) erfuellen.
Wer unnoetig die Kompatibilititaet mit solchen shells einschraenkt, sollte
IMHO keine shellscripts schreiben. Und die Verwendung von UTF-8 in shell-
scripts ist i.d.R. unnoetig.

> Der POSIX?Standard
> (<https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_02>)
> legt fest, dass ein zu POSIX kompatibles Shell bei
> ${#parameter}
> die Anzahl der Zeichen (characters) zählt. 


Nicht alles, was vom Standard erlaubt ist, ist auch eine gute Idee.

Tschuess,
Juergen Ilse (juergen)
Helmut Waitzmann (04.06.2020, 10:09)
Juergen Ilse <news>:
>Helmut Waitzmann <nn.throttle> wrote:
>> Juergen Ilse <news>:
>>>In de.comp.os.unix.shell Helmut Waitzmann <nn.throttle> wrote:


>Nein, kein Quatsch. Es gibt nun mal (ob es einem gefaellt oder
>nicht) shells, die den aktuellen PROSIX-Standard nicht (oder
>nicht vollstaendig) erfuellen.


Sicher gibt es die.  Aber man muss sie ja nicht ohne Not
verwenden, wenn es Alternativen gibt, die den POSIX?Standard
besser erfüllen. 

>Wer unnoetig die Kompatibilititaet mit solchen shells
>einschraenkt, sollte IMHO keine shellscripts schreiben. Und die
>Verwendung von UTF-8 in shellscripts ist i.d.R. unnoetig.


Das heißt, du startest Utilities vorsichtshalber nur in
Single?Byte?Locales oder vergewisserst dich vorher, dass sie keine
Shell?Funktionalität nutzen, bei der der Dash in einem
UTF-8?Locale scheitert? 

Ein Beispiel aus der Praxis:  HylaFAX+ 5.5.9 hatte ein Problem bei
beispielsweise dem Locale?Setting, das man mit den folgenden
Shell?Kommandos erhält: 

set -a
eval "$( l=POSIX && LANG="$l" LC_ALL="$l" locale )" &&
unset LC_ALL && LC_CTYPE=de_DE.UTF-8
set +a

Das ist ein gemischtes Locale?Setting, bei denen für alle
Locale?Kategorien außer LC_CTYPE das POSIX?Locale verwendet wird,
während LC_CTYPE auf Deutsch mit UTF-8?Zeichensatz eingestellt
ist.  Dieses Locale?Setting wurde bei openSUSE Leap 42.3
eingestellt, wenn in der Datei «/etc/sysconfig/language» die
Einstellung

«ROOT_USES_LANG="ctype"»

vermerkt war ? eine Einstellung, die aus Sicherheitsgründen
empfohlen wird ? und ansonsten das Default?Locale auf
«de_DE.UTF-8» eingestellt war. 

Bei diesem Locale?Setting wurden die Telefax?Versandprotokolle in
deutscher Sprache mit fehlenden Umlauten verfasst, sodass man dann
beispielsweise «Empfnger: ?» lesen konnte.  Verantwortlich dafür
waren gewisse POSIX?Shell?Skripte, die daran scheiterten, das
Locale?Setting der Kategorie LC_CTYPE richtig einzustellen.  Dank
der Fähigkeit des POSIX?Shells, beim Kommando

v='Öse' && printf '%s\n' "${v#?}"

auch in einem UTF-8?Locale?Setting die Ausgabe «se» zu erhalten,
konnten die Shell?Skripte korrigiert werden.  Mit Dash als
vermeintlichem POSIX?Shell würden sie nicht funktionieren, undman
bekäme in den Telefax?Versand?Protokollen weiterhin «Empfnger» zu
lesen. 

Wer die POSIX?Kompatibilitität einer Linux?Distribution durch
Verwendung solcher Shells als POSIX?Shell einschränkt, sollte sich
im Klaren sein, dass die Distribution nur in
Single?Byte?Locale?Settings zum POSIX?Standard kompatibel ist, und
so ehrlich sein, das auch offen zu kommunizieren, z.?B. als FAQ: 

Frage:  Warum verschluckt HylaFAX in seinen Versand?Protokollen
Umlaute?

Antwort:  Wir ziehen es vor, als POSIX?Shell Dash zu verwenden,
weil es schneller ist als beispielsweise Bash.  Dass HylaFAX damit
in UTF-8?Umgebungen auf die Schnauze fällt, nehmen wir in Kauf.

Oder kürzer:  «Schnellix ? funktioniert mit UTF?8 nicht richtig ?
das aber rasend schnell!»
Michael Bäuerle (04.06.2020, 11:29)
Helmut Waitzmann wrote:
[..]
> Das ist ein gemischtes Locale?Setting, bei denen für alle
> Locale?Kategorien außer LC_CTYPE das POSIX?Locale verwendet wird,
> während LC_CTYPE auf Deutsch mit UTF-8?Zeichensatz eingestellt ist.


Hier muss man aber fairerweise sagen, dass POSIX [1] fordert, dass
alle Kategorien der Locale die gleiche Codierung verwenden müssen:
|
| If different character sets are used by the locale categories, the
| results achieved by an application utilizing these categories are
| undefined. [...]

Das obige Beispiel funktioniert also, wenn die POSIX-Locale ebenfalls
UTF-8 verwendet (was AFAIK nicht verboten ist). Anderenfalls darf man
kein bestimmtes Ergebnis erwarten, egal mit welcher Shell und mit
welchem Programm.

_______________
[1] <https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap07.html>
Helmut Waitzmann (05.06.2020, 15:25)
Michael Bäuerle <michael.baeuerle>:
>Helmut Waitzmann wrote:
>> Juergen Ilse <news>:


[..]
>ebenfalls UTF-8 verwendet (was AFAIK nicht verboten ist).
>Anderenfalls darf man kein bestimmtes Ergebnis erwarten, egal mit
>welcher Shell und mit welchem Programm.


Ich meine:  Mit einem Locale, das in allen Kategorien außer
LC_CTYPE auf POSIX, in der Kategorie LC_CTYPE aber auf einen
Zeichensatz, der den Zeichensatz der Einstellung POSIX umfasst,
eingestellt ist, sollte es keinen Ärger geben:  Beispielsweise
Fehlermeldungen und andere erzeugte Texte (u.?a. die Kategorien
LC_MESSAGES, LC_NUMERIC, LC_MONETARY, LC_TIME) liegen dann alle im
POSIX?Zeichensatz (müsste dafür nicht der ASCII ausreichen?) und
werden damit vom bei LC_CTYPE eingestellten Zeichensatz
abgedeckt:  Sowohl UTF-8 als auch ISO_8859 umfassen den ASCII.

Das Problem mit Hylafax dabei hatte nicht direkt mit dem
gemischten Locale zu tun, sondern damit, dass versucht wurde, in
einem der beteiligten Shell?Skripte das Locale so umzustellen,
dass es den gewünschten Zeichensatz benutzt, für deutschsprachige
Protokolle beispielsweise auf ein deutschsprachiges Locale mit
ISO_8859-1?Zeichensatz: 

LANG="${LANG%%.*}".ISO_8859-1 && export LANG

Das hatte beim oben angeführten gemischten Locale aber für die
Kategorie LC_CTYPE keinen Effekt, weil die Umgebungsvariable
LC_CTYPE unverändert auf de_DE.UTF-8 stand und das Shell?Skript es
unterließ, danach zu schauen.  (Vermutlich hatte vorher niemand
Hylafax in Verbindung mit «ROOT_USES_LANG="ctype"» ausprobiert,
ehe es ins openSUSE?Release kam.)

Außerdem bringt ja

LANG="${LANG%%.*}".ISO_8859-1

generell nicht in jedem Fall eine korrekte Locale?Einstellung
hervor.  Beispielsweise wird im Fall, dass vor dem Umsetzen LANG
auf POSIX steht, danach POSIX.ISO_8859-1 eher kein gültiger
Locale?Name sein.  => Diese Vorgehensweise ist von vorne herein
zum Scheitern verurteilt. 

Motivation für den Wunsch, das Locale umzustellen, war ein
Wörterbuch, gespeichert in Shell?Variablen, das je nach
gewünschter Sprache der Versandprotokolle in einer von
verschiedenen Übersetzungen mit entsprechendem Zeichensatz geladen
wurde.  Für die deutsche Fassung war das ISO_8859-1. 

Ich meine, mal irgendwann im POSIX?Standard gelesen zu haben
(finde es aber gerade nicht mehr), dass das POSIX?Locale
einerseits, was die Klassifikation der möglichen Zeichen angeht,
den ASCII als Zeichensatz verwendet, also beispielsweise bei den
Buchstaben («[[:alpha:]]») nur die des lateinischen Alphabets
umfasst, andererseits aber auch mit anderen Zahlenwerten in einem
Byte umgehen kann, auch wenn die dann kein gültiges Zeichen aus
dem Zeichensatz darstellen.  Das würde dann bedeuten, dass das
POSIX?Locale alle Bytes klaglos schluckt, ohne über ungültige
Zeichen zu stolpern.

Zurück zur gescheiterten Locale?Umstellung bei Hylafax:  Weil das
nicht funktionierte, wurden die Shell?Skripte umgebaut:  Stattzu
versuchen, die Locale?Einstellung zu ändern, wurden die
Wörterbucheinträge mittels «iconv» in den Zeichensatz des
vorgefundenen Locales (ermittelt über das Kommando «locale --
charmap») umkodiert.  Das Versandprotokoll wurde dann
quoted?printable kodiert und an «sendmail» verfüttert.  Die
Quoted?Printable?Kodierung wurde ebenfalls per Shell?Skript
gemacht und musste ? mindestens, was das «Subject»?Vorspannfeld
der E?Mail?Nachricht angeht ? zeichenweise, nicht byteweise,
geschehen, um UTF-8?Zeichen nicht zu zersägen.  Das bedeutet
beispielsweise, dass das Shell?Kommando

v='Öse' && printf '%s' "${v%"${v#?}"}"

von der Zeichenkette «Öse» nicht das erste Byte des in UTF-8
kodierten «Ö» ausgeben darf, sondern das erste Zeichen, das «Ö»,
ausgeben muss, damit der Quoted?Printable?Kodierer in dem
Daten?Strom, den er erhält, alle Bytes des Multi?Byte?Zeichens «Ö»
auf einmal erhält und daraus ermitteln kann, wo ihm
Kodierungsgrenzen erlaubt sind und wo nicht.  Dazu ist es nötig,
dass erstens die Locale?Kategorie «LC_CTYPE» passend eingestellt
ist (das war der Fall) und zweitens der Shell im Fall eines
UTF-8?Locales mit UTF-8 umgehen kann. 

Am zweiten Punkt scheitert Debian Buster, wie zuvor beschrieben,
wenn der Administrator «/bin/sh» nicht auf beispielsweise Bash
umstellt, sondern auf Dash stehen lässt. 
Michael Bäuerle (05.06.2020, 18:46)
Helmut Waitzmann wrote:
> Michael Bäuerle <michael.baeuerle>:
> Ich meine:  Mit einem Locale, das in allen Kategorien außer LC_CTYPE
> auf POSIX, in der Kategorie LC_CTYPE aber auf einen Zeichensatz, der
> den Zeichensatz der Einstellung POSIX umfasst, eingestellt ist, sollte
> es keinen Ärger geben:  Beispielsweise Fehlermeldungen und andere
> erzeugte Texte (u.?a. die Kategorien LC_MESSAGES, LC_NUMERIC,
> LC_MONETARY, LC_TIME) liegen dann alle im POSIX?Zeichensatz (müsste
> dafür nicht der ASCII ausreichen?)


In [2] heißt es:
|
| The POSIX locale shall contain 256 single-byte characters including
| the characters in Portable Character Set and Non-Portable Control
| Characters, which have the properties listed in LC_CTYPE. [...]

Demnach wären US-ASCII, ISO-8859-1 oder EBCDIC für die POSIX-Locale
möglich.
Nicht aber UTF-8 oder ISO-2022-JP (obwohl beide auf US-ASCII basieren),
die von mir geäußerte Vermutung trifft also offenbar nicht zu.

> und werden damit vom bei LC_CTYPE
> eingestellten Zeichensatz abgedeckt:  Sowohl UTF-8 als auch ISO_8859
> umfassen den ASCII.


Ja, es dürfte wohl in den meisten Fällen so implementiert sein, dass
es sich so verhält. Dass es nicht funktioniert wäre aber auch konform,
falls ich die Norm richtig interpretiere.

Es es sogar erlaubt mehrere POSIX-Locales zu implementieren.
Zitat aus [3] (am Ende):
|
| According to XBD Portable Character Set, the standard requires that
| all supported locales must have the same encoding for <period> and
| <slash>, because these two characters are used within the locale-
| independent pathname resolution sequence. Therefore, it would be an
| error if locale -a listed both ASCII and EBCDIC-based locales, since
| those two encodings do not share the same representation for either
| <period> or <slash>. Any system that supports both environments would
| be expected to provide two POSIX locales, one in either codeset, where
| only the locales appropriate to the current environment can be visible
| at a time. [...]

[..]
> Beispielsweise wird im Fall, dass vor dem Umsetzen LANG auf POSIX
> steht, danach POSIX.ISO_8859-1 eher kein gültiger Locale?Name sein.  =>
> Diese Vorgehensweise ist von vorne herein zum Scheitern verurteilt. 


Ja. Die Namen der anderen Locales müssen den Zeichensatz auch nicht im
Namen stehen haben.

BTW: Mein Newsreader versucht z.B. bei verfügbarer XSI-Extension nicht
den Locale-Name zu parsen, sondern auf diese Weise den Zeichensatz der
Locale herauszufinden:
|
| nl_langinfo(CODESET);

Da kann aber auch "ISO-8859-1", "iso88591", "iso-885915", "UTF-8" oder
"utf8" zurückkommen. Das dürfte alles gerne präziser genormt sein ...

> _______________
> [1] <https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap07.html>

[2] <https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap06.html#tag_06_02>
[3] <https://pubs.opengroup.org/onlinepubs/9699919799/utilities/locale.html>
Ähnliche Themen