Discussion:
Bash und Spass mit Leerzeichen
(zu alt für eine Antwort)
Helmut Waitzmann
2019-02-03 02:24:21 UTC
Permalink
Hallo Tim,
BASH=".bashrc"
TDB=".thunderbird/default"
SKPBAK="backup/alter\ computer/Skype"
WIRE="backup/wire-desktop/"
BACKUPSRC="$BASH $TDB $SKPBAK $WIRE"
du -c $BACKUPSRC
tar vcf backup_home.tar $BACKUPSRC
Leider wird der Inhalt von SKPBAK als 2 Pfade erkannt, geteilt durch das
Leerzeichen.
SKPBAK="backup/alter\ computer/Skype"
verlierst Du schon den, der Deinen Sorgenpfad zusammenhielt(e).
Nein. Die Variable »SKPBAK« enthält den »\« durchaus:

Das Shell‐Kommando

»printf '%s\n' "$SKPBAK"«

gibt nur eine Zeile aus, nicht zwei, und der »\« ist auch
enthalten.
Bei der Zusammensetzung der Einzelvariablen
BACKUPSRC="$BASH $TDB $SKPBAK $WIRE"
(die in diesem Schnipsel recht nutzlos erscheinen) ist der Inhalt der
Variablen also schon "zerbrochen".
Nein. Prüfe es mit dem Kommando

»printf '%s\n' "$BACKUPSRC"«

nach.
Ein "echo $SKPBAK" zeigte Dir das.
Nein, das zeigt nicht den Inhalt der Variablen »SKPBAK« an:
»$SKPBAK« (ohne Anführungszeichen!) führt dazu, dass der Shell den
(zunächst) unversehrten Inhalt der Variablen, bevor er ihn in die
Aufrufparameterliste des »echo«‐Kommandos stellt, an jedem
Zeichen, das in der Variablen »IFS« genannt wird, zerbricht.

Genauer beschrieben ist das in
<http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_05>.
Du mußt also mindestens das Quote-Zeichen in der Variablen
"SKPBAK" quo ten, und dazu ein weiteres gequotetes Quote-Zeichen
einfügen, damit das beim zweiten Umsetzem für die Variable
"BACKUPSRC" noch erhalten bleibt.
Du meinst das Kommando

»SKPBAK='backup/alter\\ computer/Skype'«?

Du hast es nicht ausprobiert. Stimmt's?

Das ist eines der klassischen Shell‐Themen. Deshalb
Crosspost & Followup-To: de.comp.os.unix.shell
Helmut Waitzmann
2019-02-03 03:49:57 UTC
Permalink
BASH=".bashrc"
TDB=".thunderbird/default"
SKPBAK="backup/alter\ computer/Skype"
WIRE="backup/wire-desktop/"
BACKUPSRC="$BASH $TDB $SKPBAK $WIRE"
du -c $BACKUPSRC
tar vcf backup_home.tar $BACKUPSRC
Leider wird der Inhalt von SKPBAK als 2 Pfade erkannt, geteilt durch das
Leerzeichen.
Ja. Man kann in einer (POSIX‐)Shell‐Variablen (ohne erheblichen
Aufwand beim Hineinstecken und Herausholen) nicht mehr als einen
einzigen Wert (also eine Liste von Werten) speichern.

Die einzige Möglichkeit, eine Liste von Werten im POSIX‐Shell
(relativ bequem) zu verarbeiten, ist, die Positionsparameter
»"$1"«, »"$2"«… – besonders in der Form »"$@"« – zu verwenden.

In Deinem Artikel erwähnst Du es nur im Betreff, nicht im
Nachrichtenkörper: Bash. Im »bash« gibt es Feldvariable. Die
können eine Liste von Werten fassen:

BASH='.bashrc'
TDB='.thunderbird/default'
SKPBAK='backup/alter computer/Skype'
WIRE='backup/wire-desktop/'
BACKUPSRC=("$BASH" "$TDB" "$SKPBAK" "$WIRE")

du -c "${BACKUPSRC[@]}"
tar vcf backup_home.tar "${BACKUPSRC[@]}"

(Die Anführungszeichen in den beiden letzten Zeilen sind richtig
so und nötig.)

POSIX‐kompatibel mit den Positionsparametern geht es so:

BASH='.bashrc'
TDB='.thunderbird/default'
SKPBAK='backup/alter computer/Skype'
WIRE='backup/wire-desktop/'
set '' "$BASH" "$TDB" "$SKPBAK" "$WIRE" && shift

du -c "$@"
tar vcf backup_home.tar "$@"

(Die Anführungszeichen in den beiden letzten Zeilen sind richtig
so und nötig.)

Bemerkungen:

Das Zeichen »\« im Variablenwert habe ich gelöscht. Den
gewünschten Effekt, beim Auswerten einer Variablen, die nicht
von »"« eingerahmt ist, das Zerbrechen des Variablenwerts an
Leerstellen zu verhindern, hat es nicht. Statt dessen bleibt es
stehen. Beispiel: Sieh die Ausgabe des folgenden Kommandos an:

(var='zwei\ Teile' && printf '%s\n' $var)

Zum Quoting von Zeichenfolgen verwende ich grundsätzlich »'«,
nicht »"«. »"« haben einige Fallstricke. Einer davon ist
folgender:

printf '%s\n' "a\b" "a\\b"

Mit »'« statt »"« ist alles in Ordnung:

printf '%s\n' 'a\b' 'a\\b'

Und hier wird's noch schlimmer:

printf '%s\n' "a\" "a\\"

Mit »'« statt »"« ist alles in Ordnung:

printf '%s\n' 'a\' 'a\\'

Das ist ein klassisches Shell‐Thema. Deshalb mache ich mal ein
Crosspost & Followup-To: de.comp.os.unix.shell
Marcel Logen
2019-02-03 18:20:50 UTC
Permalink
Post by Helmut Waitzmann
BASH='.bashrc'
TDB='.thunderbird/default'
SKPBAK='backup/alter computer/Skype'
WIRE='backup/wire-desktop/'
set '' "$BASH" "$TDB" "$SKPBAK" "$WIRE" && shift
(Die Anführungszeichen in den beiden letzten Zeilen sind richtig
so und nötig.)
Frage: Warum muß man bei dieser Verwendung von set (Setzen von
positional parameters) mit '' und shift arbeiten?

Geht es nicht auch so?

| ***@r18:~/ybtra-r18 $ set --

| ***@r18:~/ybtra-r18 $ echo "$#"
| 0

| ***@r18:~/ybtra-r18 $ echo "$@".
| .

| ***@r18:~/ybtra-r18 $ set -- 1 2 3 4 5

| ***@r18:~/ybtra-r18 $ echo "$#"
| 5

| ***@r18:~/ybtra-r18 $ echo "$@".
| 1 2 3 4 5.

| ***@r18:~/ybtra-r18 $ shift

| ***@r18:~/ybtra-r18 $ echo "$#"
| 4

| ***@r18:~/ybtra-r18 $ echo "$@".
| 2 3 4 5.

Ich habe mir dazu
<http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#set>
und
<http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#shift>
angesehen, kann aber darin nichts entdecken, was gegen

set -- 1 2 3 4 5

spricht.

Marcel
--
+-----+ +---+ +------+ +--+ +----+ +-+ +--+
+-+ +-+ +-+ +----+ +---+ +--+ +--+ +-+ +-+ +--+ +--+
+ +--+ +-+ +-+ +----------------+ +-+ +-+ +---------+ +--+
+-----+ +---+ +------------------+ +-------------+ +
Helmut Waitzmann
2019-02-03 23:30:14 UTC
Permalink
[…]
Post by Marcel Logen
Post by Helmut Waitzmann
set '' "$BASH" "$TDB" "$SKPBAK" "$WIRE" && shift
Frage: Warum muß man bei dieser Verwendung von set (Setzen von
positional parameters) mit '' und shift arbeiten?
Geht es nicht auch so?
Ja, Shells, die zu POSIX kompatibel sind, können es auch mit

»set -- "$BASH" "$TDB" "$SKPBAK" "$WIRE"«.

(Die »--« sind nötig, falls der Inhalt der Variablen »BASH« mit
einem Plus‐ oder Minuszeichen beginnt, ansonsten aber nicht
schädlich.)
[…]
Post by Marcel Logen
Ich habe mir dazu
<http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#set>
und
<http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#shift>
angesehen, kann aber darin nichts entdecken, was gegen
set -- 1 2 3 4 5
spricht.
Wenn Du in der Beschreibung von »set« zum Abschnitt »RATIONALE«
blätterst
(<http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_25_18>),
findest Du die folgende Bemerkung:

Der Shell im System V Unix interpretiert(e) das Kommando

»set --«

wie

»set«

und löscht(e) deshalb die Positionsparameter nicht sondern
gibt/gab alle Shellvariablen aus.

Im Beispiel oben (»set -- "$BASH" …«) kann dieser Fall nicht
vorkommen, weil ja vier Parameter angegeben sind. Daher ist der
Aufwand, ihn mit

»set '' … && shift«

zu vermeiden, nicht nötig.

(Anders sähe es beispielsweise bei

»set -- "$@" ${var+"$var"}«

aus. Diesem Kommando sieht man nicht an, dass es im Fall, dass
weder Positionsparameter noch die Shellvariable »var« vorhanden
sind, auf ein

»set --«

hinausläuft.)

Weil der Aufwand aber nicht groß ist, mache ich mir ihn immer,
ohne groß darüber nachzudenken.

Des weiteren versuche ich nach Möglichkeit, meine Usenet‐Beiträge
so zu gestalten, dass sie auch in Abwandlung – wer rechnet denn
als Leser schon damit, dass 0 Parameter bei gewissen historischen
Shells plötzlich etwas ganz anderes bewirken – noch funktionieren.
(Wer weiß denn schon, ob irgendwelche Shell‐Skripte nicht auch mal
einem historischen Shell vor die Nase gesetzt werden.)
Marcel Logen
2019-02-05 16:00:59 UTC
Permalink
Post by Helmut Waitzmann
Post by Marcel Logen
Geht es nicht auch so?
Ja, Shells, die zu POSIX kompatibel sind, können es auch mit
»set -- "$BASH" "$TDB" "$SKPBAK" "$WIRE"«.
(Die »--« sind nötig, falls der Inhalt der Variablen »BASH« mit
einem Plus‐ oder Minuszeichen beginnt, ansonsten aber nicht
schädlich.)
Danke.
Das ist eine Bash (hatte vergessen, es zu erwähnen):

| GNU bash, version 4.3.30(1)-release (arm-unknown-linux-gnueabihf)
Post by Helmut Waitzmann
Wenn Du in der Beschreibung von »set« zum Abschnitt »RATIONALE«
blätterst
(<http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_25_18>),
Der Shell im System V Unix interpretiert(e) das Kommando
»set --«
wie
»set«
und löscht(e) deshalb die Positionsparameter nicht sondern
gibt/gab alle Shellvariablen aus.
Ja, den Absatz hatte ich auch gelesen, aber ehrlich gesagt nicht
ganz verstanden.

[...]

[set mit shift]
Post by Helmut Waitzmann
Weil der Aufwand aber nicht groß ist, mache ich mir ihn immer,
ohne groß darüber nachzudenken.
Danke für Deine Erläuterungen. Jetzt ist es mir klar. Ich werde
versuchen, mir das für eigene Verwendungen zu merken.

Marcel
--
+---+ +--+ +-----+ +-+ +--+ +-+ +-+ +------+ +----+ +--+ +--
+-+ +-----+ +-+ +--+ +--+ +--+ +-+ +--+ +---+ +-+ +--+ +--+
+--+ +------+ +------+
| +--------+
Helmut Waitzmann
2019-02-03 13:00:47 UTC
Permalink
BASH=".bashrc"
TDB=".thunderbird/default"
SKPBAK="backup/alter\ computer/Skype"
WIRE="backup/wire-desktop/"
BACKUPSRC="$BASH $TDB $SKPBAK $WIRE"
du -c $BACKUPSRC
tar vcf backup_home.tar $BACKUPSRC
Ohne es wirklich getestet zu haben, wenn Ü in den ganzen
IFS='Ü'
BASH=".bashrc"
TDB=".thunderbird/default"
SKPBAK="backup/alter computer/Skype"
WIRE="backup/wire-desktop/"
BACKUPSRC="$BASHÜ$TDBÜ$SKPBAKÜ$WIRE"
Das scheint bei meinem Shell zu funktionieren. Trotzdem habe ich
etwas Bauchweh dabei: Ich sehe es nicht als ausgeschlossen an,
dass es Shells gibt, für die »Ü« Teil eines Variablennamens werden
kann. Das könnte man aber durch

BACKUPSRC="${BASH}Ü${TDB}Ü${SKPBAK}Ü${WIRE}"

vermeiden.

Außerdem ist es keine prinzipielle Lösung für das Problem: Es ist
gut möglich, dass es einen Anwendungsfall gibt, bei dem man es
nicht hinbekommt, von vorne herein ein Zeichen zu bestimmen, das
in den Pfaden nicht vorkommt.

Crosspost & Followup-To: de.comp.os.unix.shell
Helmut Waitzmann
2019-02-03 13:28:53 UTC
Permalink
BASH=".bashrc"
TDB=".thunderbird/default"
SKPBAK="backup/alter\ computer/Skype"
WIRE="backup/wire-desktop/"
BACKUPSRC="$BASH $TDB $SKPBAK $WIRE"
du -c $BACKUPSRC
tar vcf backup_home.tar $BACKUPSRC
Ohne es wirklich getestet zu haben, wenn Ü in den ganzen
IFS='Ü'
BASH=".bashrc"
TDB=".thunderbird/default"
SKPBAK="backup/alter computer/Skype"
WIRE="backup/wire-desktop/"
BACKUPSRC="$BASHÜ$TDBÜ$SKPBAKÜ$WIRE"
Das scheint bei meinem Shell zu funktionieren. Trotzdem habe ich
etwas Bauchweh dabei: Ich sehe es nicht als ausgeschlossen an,
dass es Shells gibt, für die »Ü« Teil eines Variablennamens werden
kann. Das könnte man aber durch

BACKUPSRC="${BASH}Ü${TDB}Ü${SKPBAK}Ü${WIRE}"

vermeiden.

Außerdem ist es keine prinzipielle Lösung für das Problem: Es ist
gut möglich, dass es einen Anwendungsfall gibt, bei dem man es
nicht hinbekommt, von vorne herein ein Zeichen zu bestimmen, das
in den Pfaden nicht vorkommt.

Crosspost & Followup-To: de.comp.os.unix.shell
Christian Weisgerber
2019-02-03 15:17:17 UTC
Permalink
Post by Helmut Waitzmann
IFS='Ü'
BACKUPSRC="$BASHÜ$TDBÜ$SKPBAKÜ$WIRE"
Das scheint bei meinem Shell zu funktionieren. Trotzdem habe ich
etwas Bauchweh dabei: Ich sehe es nicht als ausgeschlossen an,
dass es Shells gibt, für die »Ü« Teil eines Variablennamens werden
kann.
Und: In der heute weithin üblichen UTF-8-Kodierung ist 'Ü' eine
Folge von zwei Bytes (0xC3 0x9C). Welche Shells in welchen Locales
behandeln das als ein, welche als zwei Zeichen?

Schlechter Vorschlag, IMO.
--
Christian "naddy" Weisgerber ***@mips.inka.de
Helmut Waitzmann
2019-02-03 23:42:00 UTC
Permalink
Post by Christian Weisgerber
Post by Helmut Waitzmann
IFS='Ü'
BACKUPSRC="$BASHÜ$TDBÜ$SKPBAKÜ$WIRE"
Das scheint bei meinem Shell zu funktionieren. Trotzdem habe ich
etwas Bauchweh dabei: Ich sehe es nicht als ausgeschlossen an,
dass es Shells gibt, für die »Ü« Teil eines Variablennamens werden
kann.
Und: In der heute weithin üblichen UTF-8-Kodierung ist 'Ü' eine
Folge von zwei Bytes (0xC3 0x9C). Welche Shells in welchen Locales
behandeln das als ein, welche als zwei Zeichen?
Das kommt dazu. Beispielsweise erwarte ich, dass »IFS=Ü« mit
einem UTF-8‐kodierten »Ü« im POSIX‐Locale in der Tat als zwei
Zeichen interpretiert wird, mit der Folge, dass dann auch bei
einem »Ä« oder »Ö« (denn sie haben als erstes Byte in ihrer
Kodierung dasselbe wie das »Ü«) der Variableninhalt zerbricht:

Was geben die folgenden Kommandos aus?

(
IFS='Ü'
var='Was geschieht mit Ä und Ö?'
LC_ALL=POSIX && export LC_ALL
printf '%s\n' $var
)
J***@fokus.fraunhofer.de
2019-02-04 10:27:03 UTC
Permalink
Und: In der heute weithin üblichen UTF-8-Kodierung ist 'Ü' eine
Folge von zwei Bytes (0xC3 0x9C). Welche Shells in welchen Locales
behandeln das als ein, welche als zwei Zeichen?
Das kommt dazu. Beispielsweise erwarte ich, dass »IFS=Ü« mit
einem UTF-8‐kodierten »Ü« im POSIX‐Locale in der Tat als zwei
Zeichen interpretiert wird, mit der Folge, dass dann auch bei
einem »Ä« oder »Ö« (denn sie haben als erstes Byte in ihrer
Wie bereits gesagt: das ist erstmal falsch, denn die POSIX Lokale kann auf
ISO-646 oder auf UTF-8 basieren - das ist nicht festgelegt.

Auch muß man heute auf Linux Systemen mit dem nicht POSIX-konformen dash
rechnen...
--
EMail:***@schily.net (home) Jörg Schilling D-13353 Berlin
***@fokus.fraunhofer.de (work) Blog: http://schily.blogspot.com/
URL: http://cdrecord.org/private/ http://sourceforge.net/projects/schilytools/files/
J***@fokus.fraunhofer.de
2019-02-04 10:21:13 UTC
Permalink
Und: In der heute weithin üblichen UTF-8-Kodierung ist 'Ü' eine
Folge von zwei Bytes (0xC3 0x9C). Welche Shells in welchen Locales
behandeln das als ein, welche als zwei Zeichen?
Also das kommt erstmal darauf an, ob der betreffende Shell POSIX-konform ist
oder nicht.

"dash" z.B. sieht das immer als 2 Zeichen, da dash nicht POSIX konform ist.
Ausnahme: Du befindest Dich auf einem kleinen embedded System, wo die "CX"
Erweiterungen nicht vorgeschrieben sind.

Wenn Du aber einen POSIX-konformen Shell hast, dann sieht der auf einem "normalen"
POSIX konformen Betriebssystem in einer UTF-8 Lokale immer genau ein Zeichen.

Wenn Du aber in der POSIX-Lokale bist, ist es schwieriger, da die POSIX Lokale
entweder ISO-646- oder UTF-8- basiert sein kann. Daher kann man hier nicht
vorhersehen, wie sich der Shell verhält.

Wer also Multi-Byte Zeichen immer als zwei Zeichen sehen will, muß explizit in
eine Single-Byte Lokale gehen. Die POSIX Lokale kann, wie oben gesagt, Beides
(je nach Implementierung) sein.
--
EMail:***@schily.net (home) Jörg Schilling D-13353 Berlin
***@fokus.fraunhofer.de (work) Blog: http://schily.blogspot.com/
URL: http://cdrecord.org/private/ http://sourceforge.net/projects/schilytools/files/
J***@fokus.fraunhofer.de
2019-10-03 06:20:56 UTC
Permalink
Post by J***@fokus.fraunhofer.de
Und: In der heute weithin üblichen UTF-8-Kodierung ist 'Ü' eine
Folge von zwei Bytes (0xC3 0x9C). Welche Shells in welchen Locales
behandeln das als ein, welche als zwei Zeichen?
Also das kommt erstmal darauf an, ob der betreffende Shell POSIX-konform ist
oder nicht.
"dash" z.B. sieht das immer als 2 Zeichen, da dash nicht POSIX konform ist.
Ausnahme: Du befindest Dich auf einem kleinen embedded System, wo die "CX"
Erweiterungen nicht vorgeschrieben sind.
Ich habe bei unserer letzten POSIX Telekonferenz von Geoff Clare, dem Autor der
POSIX Testsuite eine viel besser verständliche formulierung gehört:

Ein Programm, das nur POSIX Konform ist, darf durchaus nur die C-Lokale
unterstützen.

Ein Programm, das das UNIX Branding möchte, muß aber Multi-Byte Lokalen
unterstützen und das tut dash z.B. nicht.
--
EMail:***@schily.net (home) Jörg Schilling D-13353 Berlin
***@fokus.fraunhofer.de (work) Blog: http://schily.blogspot.com/
URL: http://cdrecord.org/private/ http://sourceforge.net/projects/schilytools/files/
Loading...