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

Wege aus der Quotinghoelle

1 view
Skip to first unread message

Marc Haber

unread,
Sep 1, 2022, 2:11:36 PM9/1/22
to
Hallo,

gegeben sei ein Shellscript keks, das zu Konfigurationszwecken ein
Shellsnippet keks-config sourced. In keks-config wird ein Variable mit
einer kompletten Kommandozeile initialisiert, keks ruft diese
Kommandozeile dann auf. In dieser Kommandozeile soll ein Parameter mit
Leerzeichen, z.B. --from="bar <baz@example>" enthalten sein.


|[8/5002]mh@fan:~/tmp $ head -n-0 keks keks-config keks-show
|==> keks <==
|#!/bin/sh
|
|. ./keks-config
|
|${CMD}
|
|
|==> keks-config <==
|CMD="./keks-show --from=\"bar <baz@example>\" bum"
|
|
|==> keks-show <==
|#!/bin/bash
|
|printf '$1 "%s" - $2 "%s" - $3 - "%s"\n' "$1" "$2" "$3"
|
|[9/5003]mh@fan:~/tmp $ bash -x ./keks
|+ . ./keks-config
|++ CMD='./keks-show --from="bar <baz@example>" bum'
|+ ./keks-show '--from="bar' '<baz@example>"' bum
|$1 "--from="bar" - $2 "<baz@example>"" - $3 - "bum"
|[10/5004]mh@fan:~/tmp $

Da scheint mir die Tokenization der shell mindestens an zwei Stellen
hineinzupfuschen.

Wie muss ich das in keks-config quoten, damit es am Ende funktioniert
wie intendiert?

Grüße
Marc
--
-------------------------------------- !! No courtesy copies, please !! -----
Marc Haber | " Questions are the | Mailadresse im Header
Mannheim, Germany | Beginning of Wisdom " |
Nordisch by Nature | Lt. Worf, TNG "Rightful Heir" | Fon: *49 621 72739834

Stefan Reuther

unread,
Sep 1, 2022, 3:41:56 PM9/1/22
to
Am 01.09.2022 um 20:11 schrieb Marc Haber:
> |==> keks-config <==
> |CMD="./keks-show --from=\"bar <baz@example>\" bum"

Muss es eine String-Variable sein oder darf es auch eine Array-Variable
sein?

CMD=(./keks-show --from="bar <baz@example>" bum)
...
"${CMD[@]}"

Das mache ich zumindest aus genau dem Grund Quotinghölle schon länger
so, zumindest wenn ich beide Seiten (Produzent und Konsument)
kontrolliere. Ein weiterer Bonus: man kann das auch so formatieren:

CMD=(./keks-show
# must pass --from because autodetection fails today
--from="bar <baz@example>"
# 'bum' is the name of the file in /var/lib/keks
bum)



Stefan

Helmut Waitzmann

unread,
Sep 1, 2022, 6:53:39 PM9/1/22
to
Marc Haber <mh+usene...@zugschl.us>:
So, wie du es am Ende, also in «keks», mit der Kommandozeile


$(CMD}

aufrufst, gibt es für «keks-config» keine Möglichkeit, es richtig
zu machen:  Quoting ist eine Sache des Kommandozeilenparsers. 
Ehe die Variable «CMD» in der angeführten Kommandozeile
expandiert wird, ist der Parser schon gelaufen.  Irgendwelche
Apostrophe, Anführungszeichen oder umgekehrte Schrägstriche
spielen deshalb im Inhalt der Variablen «CMD» keine Rolle mehr. 
Das einzige, was da noch geschieht, ist das Zerbrechen des
Inhalts der Variablen «CMD» an allen Stellen, an denen ein
Zeichen aus der in der Variablen «IFS» aufgezählten Zeichen
sitzt, weil du die Expansion ohne Anführungszeichen aufrufst.

Um es richtig hinzubekommen, muss man erstens das Zerbrechen
verhindern, also «"${CMD}"» anstelle von «${CMD}» verwenden, und
zweitens den Parser nochmals anwerfen, indem man «eval»
verwendet:

eval "${CMD}"

Dann kann und muss(!) man beim Belegen der Variablen «CMD» dafür
sorgen, dass der Inhalt der Variablen «CMD» eine Kommandozeile
wird – mitsamt allen notwendigen Quoting‐ und Escape‐Zeichen.


In «keks-config» kann also beispielsweise folgendes stehen:


CMD='./keks-show --from='\''bar <baz@example>'\'' bum'

Dann erhält die Variable «CMD» den folgenden Inhalt:


./keks-show --from='bar <baz@example>' bum

Das ist eine Kommandozeile, wie du sie haben möchtest.  (Prüfe
mit dem Kommando

printf '==]%s[==\n' "$CMD"

nach, dass die Variable «CMD» wirklich diesen Text enthält.)


Natürlich will man so eine Zuweisung an die Variable «CMD» nicht
gerne von Hand («Quoting‐Hölle») austüfteln.  Als Abhilfe schnapp
dir die Funktion «my_quote_words_for_shells» aus dem News‐Beitrag

Subject: Re: Robuste Pfade
From: Helmut Waitzmann <nn.th...@xoxy.net>
Newsgroups: de.comp.os.unix.shell
Date: Tue, 30 Aug 2022 19:55:40 +0200
Message-ID: <83fshdp...@helmutwaitzmann.news.arcor.de>

und stell sie in eine Datei, beispielsweise
«~/shell-lib/my_quote_words_for_shells.sh».  Dann schreibe in die
Datei «keks-config»

CMD="$( . ~/shell-lib/my_quote_words_for_shells.sh &&
my_quote_words_for_shells \
./keks-show --from='bar <baz@example>' bum
)"


Prüfe nochmals mit dem Kommando


printf '==]%s[==\n' "$CMD"

nach, dass die Variable «CMD» eine passende Kommandozeile
enthält.  Dann sollte anschließend in der Datei «keks» die
Kommandozeile

eval "$CMD"

tun, was du willst.

--
Hat man erst verstanden, wie Unix funktioniert, ist auch
das Shell-Handbuch kein Buch mit sieben Siegeln mehr.

Marc Haber

unread,
Sep 2, 2022, 1:22:59 AM9/2/22
to
Stefan Reuther <stefa...@arcor.de> wrote:
>Am 01.09.2022 um 20:11 schrieb Marc Haber:
>> |==> keks-config <==
>> |CMD="./keks-show --from=\"bar <baz@example>\" bum"
>
>Muss es eine String-Variable sein oder darf es auch eine Array-Variable
>sein?

Das wäre ziemlich unintuitiv, aber ich denke darüber nach. Dankeschön.

Marc Haber

unread,
Sep 2, 2022, 4:15:45 AM9/2/22
to
Helmut Waitzmann <nn.th...@xoxy.net> wrote:
> Um es richtig hinzubekommen, muss man erstens das Zerbrechen
> verhindern, also «"${CMD}"» anstelle von «${CMD}» verwenden, und
> zweitens den Parser nochmals anwerfen, indem man «eval»
> verwendet:
>
> eval "${CMD}"
>
> Dann kann und muss(!) man beim Belegen der Variablen «CMD» dafür
> sorgen, dass der Inhalt der Variablen «CMD» eine Kommandozeile
> wird – mitsamt allen notwendigen Quoting? und Escape?Zeichen.
>
>
> In «keks-config» kann also beispielsweise folgendes stehen:
>
>
> CMD='./keks-show --from='\''bar <baz@example>'\'' bum'
>
> Dann erhält die Variable «CMD» den folgenden Inhalt:

Ja, so genau funktioniert das jetzt. Vielen Dank, das hat mir sehr
geholfen. Auch die Erklärung hat zum Verständnis beigetragen. Ich
hatte gehofft, ohne eval auszukommen, aber herrjeh.
0 new messages