Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > de.comp.os.unix.shell > #14537 > unrolled thread
| Started by | Alexander Goetzenstein <alexander_goetzenstein@web.de> |
|---|---|
| First post | 2025-07-16 15:14 +0200 |
| Last post | 2025-07-16 23:38 +0200 |
| Articles | 11 — 5 participants |
Back to article view | Back to de.comp.os.unix.shell
richtig quoten Alexander Goetzenstein <alexander_goetzenstein@web.de> - 2025-07-16 15:14 +0200
Re: richtig quoten Ulli Horlacher <framstag@rus.uni-stuttgart.de> - 2025-07-16 13:22 +0000
Re: richtig quoten Ulli Horlacher <framstag@rus.uni-stuttgart.de> - 2025-07-16 16:19 +0000
Re: richtig quoten "Peter J. Holzer" <hjp-usenet4@hjp.at> - 2025-07-16 16:06 +0200
Re: richtig quoten "Peter J. Holzer" <hjp-usenet4@hjp.at> - 2025-07-16 17:30 +0200
Re: richtig quoten Stefan Reuther <stefan.news@arcor.de> - 2025-07-16 18:05 +0200
Re: richtig quoten Alexander Goetzenstein <alexander_goetzenstein@web.de> - 2025-07-16 21:17 +0200
Re: richtig quoten Helmut Waitzmann <nn.throttle@xoxy.net> - 2025-07-16 23:59 +0200
Re: richtig quoten Stefan Reuther <stefan.news@arcor.de> - 2025-07-17 18:27 +0200
Re: richtig quoten Helmut Waitzmann <nn.throttle@xoxy.net> - 2025-07-17 22:20 +0200
Re: richtig quoten Helmut Waitzmann <nn.throttle@xoxy.net> - 2025-07-16 23:38 +0200
| From | Alexander Goetzenstein <alexander_goetzenstein@web.de> |
|---|---|
| Date | 2025-07-16 15:14 +0200 |
| Subject | richtig quoten |
| Message-ID | <078ee6a7-4eb6-4927-a40f-49bb333298b3@alexander-goetzenstein.my-fqdn.de> |
Hallo, ich habe mir angewöhnt, zur leichteren Fehlersuche und Tippfehlervermeidung Befehle in Scripts zuerst in eine Variable zu stecken und diese dann mittels eval auszuführen. Meist gibt es kein Problem, aber momentan stehe ich auf dem Schlauch. Folgender Befehl will nicht so wie ich es will: > [...] > ## Beispielwerte: > DATUM=2025-07-16_14-10 > FERTIG=2025-07-16_14-15 > LAUFZEIT=5 Minuten > [...] > kdialog --msgbox "Beginn: $DATUM \nEnde: $FERTIG \n$LAUFZEIT" & Letzteren Befehl möchte ich wie erwähnt behandeln, doch Konstrukte wie > BEFEHL=kdialog --msgbox "Beginn: $DATUM \nEnde: $FERTIG \n$LAUFZEIT" & > eval "$BEFEHL" ergeben nicht das gewünschte Ergebnis. Meist habe ich nur eine Ausgabe wie > Beginn: erreicht, alles andere ist abgeschnitten, wenn nicht gleich eine Fehlermeldung statt des Popups kam. Jetzt habe ich soviel mit ' und " herumgewurschtelt, dass ich den Plan verloren hab. Wie geht es richtig? -- Gruß Alex
[toc] | [next] | [standalone]
| From | Ulli Horlacher <framstag@rus.uni-stuttgart.de> |
|---|---|
| Date | 2025-07-16 13:22 +0000 |
| Message-ID | <1058934$r7p$1@rusnews.informatik.uni-stuttgart.de> |
| In reply to | #14537 |
Alexander Goetzenstein <alexander_goetzenstein@web.de> wrote: > Hallo, > ich habe mir angewöhnt, zur leichteren Fehlersuche und > Tippfehlervermeidung Befehle in Scripts zuerst in eine Variable zu > stecken und diese dann mittels eval auszuführen. Meist gibt es kein > Problem, aber momentan stehe ich auf dem Schlauch. Folgender Befehl will > nicht so wie ich es will: > >> [...] >> ## Beispielwerte: >> DATUM=2025-07-16_14-10 >> FERTIG=2025-07-16_14-15 >> LAUFZEIT=5 Minuten Das funktioniert so nicht. Da fehlen Quote-Zeichen! Letzteres macht folgendes: Es ruft den externen Befehl Minuten auf mit der Environment Variablen LAUFZEIT=5 >> kdialog --msgbox "Beginn: $DATUM \nEnde: $FERTIG \n$LAUFZEIT" & > > > Letzteren Befehl möchte ich wie erwähnt behandeln, doch Konstrukte wie > >> BEFEHL=kdialog --msgbox "Beginn: $DATUM \nEnde: $FERTIG \n$LAUFZEIT" & >> eval "$BEFEHL" > > ergeben nicht das gewünschte Ergebnis. Das wird mit dem & nur noch schlimmer! > Wie geht es richtig? Gar nicht. eval und Quotes beissen sich. Don't do that. -- Ullrich Horlacher Server und Virtualisierung Rechenzentrum TIK Universitaet Stuttgart E-Mail: horlacher@tik.uni-stuttgart.de Allmandring 30a Tel: ++49-711-68565868 70569 Stuttgart (Germany) WWW: https://www.tik.uni-stuttgart.de/
[toc] | [prev] | [next] | [standalone]
| From | Ulli Horlacher <framstag@rus.uni-stuttgart.de> |
|---|---|
| Date | 2025-07-16 16:19 +0000 |
| Message-ID | <1058je5$tds$1@rusnews.informatik.uni-stuttgart.de> |
| In reply to | #14538 |
Ulli Horlacher <framstag@rus.uni-stuttgart.de> wrote:
>> ich habe mir angewöhnt, zur leichteren Fehlersuche und
>> Tippfehlervermeidung Befehle in Scripts zuerst in eine Variable zu
>> stecken und diese dann mittels eval auszuführen. Meist gibt es kein
>> Problem, aber momentan stehe ich auf dem Schlauch. Folgender Befehl will
>> nicht so wie ich es will:
>>
>>> [...]
>>> ## Beispielwerte:
>>> DATUM=2025-07-16_14-10
>>> FERTIG=2025-07-16_14-15
>>> LAUFZEIT=5 Minuten
(...)
>> Wie geht es richtig?
>
> Gar nicht.
> eval und Quotes beissen sich. Don't do that.
Nicht ganz das, was du gefragt hast, aber vielleicht hilft dir das:
Ich hab vdo (verbode do) geschrieben, das anzeigt, welches Kommando es
ausfuehrt UND das die Argument korrekt uebergibt.
Mit der environment variable VDO=n werden Kommandos nur angezeigt, aber
nicht ausgefuehrt.
Mit der environment variable VDO=i wird vorher gefragt ob die Kommandos
ausgefuehrt werden sollen.
framstag@watschel:/moep: vdo -h
vdo: verbose do (with quoting)
usage: vdo [-i] [-n] [-s SECONDS] COMMAND [ARG...]
options: -i prompt before execution
-n dry-run mode, no execution
-s wait SECONDS before execution
env var: VDO=i VDO=n
Ich hab dein Beispiel etwas umgewandelt in:
framstag@moep:/tmp: cat beispiel.sh
DATUM="2025-07-16_14-10"
FERTIG="2025-07-16_14-15"
LAUFZEIT="5 Minuten"
vdo showargs kdialog --msgbox "Beginn: $DATUM \nEnde: $FERTIG \n$LAUFZEIT"
showargs ist ein weiteres Programm von mir, das nur anzeigt welche Argumente
uebergeben werden. Sonst sieht man Shell Metazeichen wie Spaces nicht.
framstag@moep:/tmp: ./beispiel.sh
$ showargs kdialog --msgbox 'Beginn: 2025-07-16_14-10 \nEnde: 2025-07-16_14-15 \n5 Minuten'
kdialog --msgbox Beginn: 2025-07-16_14-10 \nEnde: 2025-07-16_14-15 \n5 Minuten
1 [kdialog]
2 [--msgbox]
3 [Beginn: 2025-07-16_14-10 \nEnde: 2025-07-16_14-15 \n5 Minuten]
framstag@moep:/tmp: VDO=n ./beispiel.sh
$ showargs kdialog --msgbox 'Beginn: 2025-07-16_14-10 \nEnde: 2025-07-16_14-15 \n5 Minuten'
framstag@moep:/tmp: VDO=i ./beispiel.sh
$ showargs kdialog --msgbox 'Beginn: 2025-07-16_14-10 \nEnde: 2025-07-16_14-15 \n5 Minuten'
execute? [y]
kdialog --msgbox Beginn: 2025-07-16_14-10 \nEnde: 2025-07-16_14-15 \n5 Minuten
1 [kdialog]
2 [--msgbox]
3 [Beginn: 2025-07-16_14-10 \nEnde: 2025-07-16_14-15 \n5 Minuten]
vdo und showargs findest du da: https://fex.belwue.de/fstools/
--
Ullrich Horlacher Server und Virtualisierung
Rechenzentrum TIK
Universitaet Stuttgart E-Mail: horlacher@tik.uni-stuttgart.de
Allmandring 30a Tel: ++49-711-68565868
70569 Stuttgart (Germany) WWW: https://www.tik.uni-stuttgart.de/
[toc] | [prev] | [next] | [standalone]
| From | "Peter J. Holzer" <hjp-usenet4@hjp.at> |
|---|---|
| Date | 2025-07-16 16:06 +0200 |
| Message-ID | <slrn107fcfp.n7bl.hjp-usenet4@trintignant.hjp.at> |
| In reply to | #14537 |
On 2025-07-16 15:14, Alexander Goetzenstein <alexander_goetzenstein@web.de> wrote:
> ich habe mir angewöhnt, zur leichteren Fehlersuche und
> Tippfehlervermeidung Befehle in Scripts zuerst in eine Variable zu
> stecken und diese dann mittels eval auszuführen.
Zusätzlich zu dem was Ulli schon geschrieben hat:
Das klingt nach einer ganz schlechten Idee. Code und Daten sollte man
möglichst trennen und eval nur verwenden, wenn es nicht anders geht (was
in der Shell leider häufiger der Fall ist als in vernünftigen
Programmiersprachen).
hjp
[toc] | [prev] | [next] | [standalone]
| From | "Peter J. Holzer" <hjp-usenet4@hjp.at> |
|---|---|
| Date | 2025-07-16 17:30 +0200 |
| Message-ID | <slrn107fhda.p4mv.hjp-usenet4@trintignant.hjp.at> |
| In reply to | #14539 |
On 2025-07-16 16:46, Stefan Ram <ram@zedat.fu-berlin.de> wrote:
> "Peter J. Holzer" <hjp-usenet4@hjp.at> schrieb oder zitierte:
>>Das klingt nach einer ganz schlechten Idee. Code und Daten sollte man
>>möglichst trennen und eval nur verwenden, wenn es nicht anders geht
>
> Nehmen wir einmal dieses Beispiel:
>
>|#!/usr/bin/env bash
>|set -euo pipefail
>|backup_dir="${1:-$HOME}"
>|timestamp=$(date +%Y-%m-%d_%H-%M-%S)
>|tar -czf "$HOME/backup_$timestamp.tar.gz" -C "$backup_dir" .
>
> . "backup_dir" und "timestamp" sind "Daten", und die letzte Zeile
> ist "Code". Aber sie enthält mit den Argumenten auch Daten.
Jedes (nicht-triviale) Programm enthält "Daten": Variable, Literale,
etc.
Aber das ist (vielleicht nicht für den Computer, aber für den Menschen)
etwas anderes als Code dynamisch zu erzeugen und auszuführen. Das macht
es einfach sehr viel schwieriger, nachzuvollziehen, was das Programm
eigentlich tut. Und da Alexanders Ziel nach seiner eigenen Aussage
"leichtere Fehlersuche" ist, schießt er sich damit selbst ins Knie.
Ganz besonders in der Shell, deren Parse-Mechanismus ja für sich schon
einige Footguns bereithält. Wenn er das in Lisp macht - ok, mag dort
normal sein. In Python? "There must be a better way!"[1], aber
beherrschbar. In der Shell? You're in for a world of pain.
hjp
[1] Channeling Raymond Hettinger.
[toc] | [prev] | [next] | [standalone]
| From | Stefan Reuther <stefan.news@arcor.de> |
|---|---|
| Date | 2025-07-16 18:05 +0200 |
| Message-ID | <1058pld.3mk.1@stefan.msgid.phost.de> |
| In reply to | #14537 |
Am 16.07.2025 um 15:14 schrieb Alexander Goetzenstein:
>> [...]
>> ## Beispielwerte:
>> DATUM=2025-07-16_14-10
>> FERTIG=2025-07-16_14-15
>> LAUFZEIT=5 Minuten
>> [...]
>> kdialog --msgbox "Beginn: $DATUM \nEnde: $FERTIG \n$LAUFZEIT" &
>
> Letzteren Befehl möchte ich wie erwähnt behandeln, doch Konstrukte wie
>
>> BEFEHL=kdialog --msgbox "Beginn: $DATUM \nEnde: $FERTIG \n$LAUFZEIT" &
>> eval "$BEFEHL"
Allen Unkenrufen zum Trotz ist das ziemlich einfach.
Du musst dafür sorgen, dass die Variable BEFEHL genau den Befehl mit
allen gewünschten Sonderzeichen enthält. Das geht am einfachsten, indem
du vor alle Sonderzeichen einen Backslash packst:
BEFEHL="kdialog --msgbox \"Beginn: \$DATUM \\nEnde: \$FERTIG\\n\$LAUFZEIT\" &"
Im konkreten Fall reicht auch, einfach ein Hochkomma davor und eins dahinter
BEFEHL='kdialog --msgbox "Beginn: $DATUM \nEnde: $FERTIG\n$LAUFZEIT" &'
aber das wird dann unhandlich, wenn der Befehl Hochkommate enthält.
Zum Prüfen: echo "$BEFEHL" - da muss genau der Befehl zurückkommen,
immer noch mit den $VARIABLEN und allen Sonderzeichen.
Dennoch wäre meine Empfehlung, eine Shellfunktion zu verwenden.
status() {
kdialog --msgbox "Beginn: $DATUM \nEnde: $FERTIG \n$LAUFZEIT" &
}
BEFEHL=status
Dann kannst du zum Aufrufen auch auf das 'eval' verzichten, sondern
einfach $BEFEHL aufrufen.
Stefan
[toc] | [prev] | [next] | [standalone]
| From | Alexander Goetzenstein <alexander_goetzenstein@web.de> |
|---|---|
| Date | 2025-07-16 21:17 +0200 |
| Message-ID | <591d43a4-5fc3-4cfe-be66-274905c3c431@alexander-goetzenstein.my-fqdn.de> |
| In reply to | #14543 |
Hallo, Am 16.07.25 um 18:05 schrieb Stefan Reuther: > Du musst dafür sorgen, dass die Variable BEFEHL genau den Befehl mit > allen gewünschten Sonderzeichen enthält. Das geht am einfachsten, indem > du vor alle Sonderzeichen einen Backslash packst: Danke, danach habe ich gesucht. -- Gruß Alex
[toc] | [prev] | [next] | [standalone]
| From | Helmut Waitzmann <nn.throttle@xoxy.net> |
|---|---|
| Date | 2025-07-16 23:59 +0200 |
| Message-ID | <83jz47sso6.fsf@helmutwaitzmann.news.arcor.de> |
| In reply to | #14543 |
Stefan Reuther <stefan.news@arcor.de>:
> Am 16.07.2025 um 15:14 schrieb Alexander Goetzenstein:
>>> [...]
>>> ## Beispielwerte:
>>> DATUM=2025-07-16_14-10
>>> FERTIG=2025-07-16_14-15
>>> LAUFZEIT=5 Minuten
>>> [...]
>>> kdialog --msgbox "Beginn: $DATUM \nEnde: $FERTIG \n$LAUFZEIT" &
>>
>> Letzteren Befehl möchte ich wie erwähnt behandeln, doch
>> Konstrukte wie
>>
>>
>>> BEFEHL=kdialog --msgbox "Beginn: $DATUM \nEnde: $FERTIG \n$LAUFZEIT" &
>>> eval "$BEFEHL"
>
> Allen Unkenrufen zum Trotz ist das ziemlich einfach.
>
>
> Du musst dafür sorgen, dass die Variable BEFEHL genau den Befehl
> mit allen gewünschten Sonderzeichen enthält. Das geht am
> einfachsten, indem du vor alle Sonderzeichen einen Backslash
> packst:
>
>
> BEFEHL="kdialog --msgbox \"Beginn: \$DATUM \\nEnde: \$FERTIG\\n\$LAUFZEIT\" &"
Wenn in dem Befehl ein Newline‐Zeichen vorkommt, scheitert das,
weil Newline‐Zeichen mit einem Backslash nicht geschützt werden
können. (Statt dessen werden sie mitsamt dem Backslash entfernt,
so, als stünden sie nicht da. Im konkreten Beispiel kommen aber
keine Newline‐Zeichen vor.)
>
> Im konkreten Fall reicht auch, einfach ein Hochkomma davor und
> eins dahinter
>
>
> BEFEHL='kdialog --msgbox "Beginn: $DATUM \nEnde: $FERTIG\n$LAUFZEIT" &'
>
> aber das wird dann unhandlich, wenn der Befehl Hochkommate enthält.
>
Dann ersetzt man einfach zuvor alle im Befehl stehenden
Hochkommata (mit einem Suchen‐und‐Ersetzen‐Kommando des
Texteditors) durch die Zeichenfolge „'\''“ (ein Hochkomma, einen
umgekehrten Schrägstrich und zwei Hochkommata).
> Zum Prüfen: echo "$BEFEHL" - da muss genau der Befehl zurückkommen,
> immer noch mit den $VARIABLEN und allen Sonderzeichen.
>
„echo“ gibt den Text unter Umständen nicht unverändert
wieder. „printf“ ist besser:
printf '%s\n' "$BEFEHL"
> Dennoch wäre meine Empfehlung, eine Shellfunktion zu verwenden.
>
>
> status() {
> kdialog --msgbox "Beginn: $DATUM \nEnde: $FERTIG \n$LAUFZEIT" &
> }
> BEFEHL=status
>
> Dann kannst du zum Aufrufen auch auf das 'eval' verzichten, sondern
> einfach $BEFEHL aufrufen.
>
Nicht
$BEFEHL
sondern
"$BEFEHL".
Grundregel: Variablenexpansionen setzt man immer in
Anführungszeichen, es sei denn, man will komische Effekte mit in
der Variablen „IFS“ aufgezählten Sollbruchstellen haben.
[toc] | [prev] | [next] | [standalone]
| From | Stefan Reuther <stefan.news@arcor.de> |
|---|---|
| Date | 2025-07-17 18:27 +0200 |
| Message-ID | <105bfab.29g.1@stefan.msgid.phost.de> |
| In reply to | #14547 |
Am 16.07.2025 um 23:59 schrieb Helmut Waitzmann:
> Stefan Reuther <stefan.news@arcor.de>:
>> Du musst dafür sorgen, dass die Variable BEFEHL genau den Befehl mit
>> allen gewünschten Sonderzeichen enthält. Das geht am einfachsten,
>> indem du vor alle Sonderzeichen einen Backslash packst:
>>
>> BEFEHL="kdialog --msgbox \"Beginn: \$DATUM \\nEnde:
>> \$FERTIG\\n\$LAUFZEIT\" &"
>
> Wenn in dem Befehl ein Newline‐Zeichen vorkommt, scheitert das, weil
> Newline‐Zeichen mit einem Backslash nicht geschützt werden können.
Die Newlines muss man hier nicht gesondert behandeln, sondern einfach
stehenlassen:
BEFEHL="echo \"foo
bar\""
eval "$BEFEHL"
>> Im konkreten Fall reicht auch, einfach ein Hochkomma davor und eins
>> dahinter
>>
>> BEFEHL='kdialog --msgbox "Beginn: $DATUM \nEnde:
>> $FERTIG\n$LAUFZEIT" &'
>>
>> aber das wird dann unhandlich, wenn der Befehl Hochkommate enthält.
>
> Dann ersetzt man einfach zuvor alle im Befehl stehenden Hochkommata (mit
> einem Suchen‐und‐Ersetzen‐Kommando des Texteditors) durch die
> Zeichenfolge „'\''“ (ein Hochkomma, einen umgekehrten Schrägstrich und
> zwei Hochkommata).
Das ist das, was ich mit unhandlich meine.
>> Dennoch wäre meine Empfehlung, eine Shellfunktion zu verwenden.
>>
>> status() {
>> kdialog --msgbox "Beginn: $DATUM \nEnde: $FERTIG
>> \n$LAUFZEIT" &
>> }
>> BEFEHL=status
>>
>> Dann kannst du zum Aufrufen auch auf das 'eval' verzichten, sondern
>> einfach $BEFEHL aufrufen.
>
> Nicht
>
> $BEFEHL
>
> sondern
>
> "$BEFEHL".
Das kommt halt drauf an, was man will.
"$BEFEHL" -- die Variable enthält ein Wort, das als Befehlsname
interpretiert werden soll, z.B. einen Dateinamen, der Leerzeichen
enthalten kann.
$BEFEHL -- die Variable enthält ein Kommando mit Optionen. Das ist
angemessen für Dinge wie "CC=gcc -m32 -sysroot=/whatever", aber
Parameter mit Leerzeichen drin sind nicht möglich.
eval "$BEFEHL" -- die Variable enthält ein Kommando, das
Shell-Sonderzeichen beinhalten kann, von Quoting über weitere Variablen
bis zu '&' und Umleitungen.
Und außer Konkurrenz: '$BEFEHL' -- jemand war der Meinung, dass der Name
des Binaries mit einem Dollarzeichen beginnen solle.
Shell ist nicht so eine unvorhersehbare Naturkatastrophe, wie sie
manchmal dargestellt wird, aber man muss eben immer gut bei der Sache
sein und sich zu jedem Zeitpunkt klar sein, was für Werte man wie in
seine Variablen packt, und wenn man zu viel auf einmal will, wird es
unübersichtlich.
Wenn eine Variable aber z.B. entweder den Wert 'true' oder den Wert
'false' beinhalten kann, kann man Dinge wie 'if $var; then' ganz elegant
aufschreiben, ohne den Code mit Quoting zu verunstalten.
Stefan
[toc] | [prev] | [next] | [standalone]
| From | Helmut Waitzmann <nn.throttle@xoxy.net> |
|---|---|
| Date | 2025-07-17 22:20 +0200 |
| Message-ID | <8334auy3fq.fsf@helmutwaitzmann.news.arcor.de> |
| In reply to | #14548 |
Stefan Reuther <stefan.news@arcor.de>:
> Am 16.07.2025 um 23:59 schrieb Helmut Waitzmann:
>> Stefan Reuther <stefan.news@arcor.de>:
>>> Du musst dafür sorgen, dass die Variable BEFEHL genau den
>>> Befehl mit allen gewünschten Sonderzeichen enthält. Das geht
>>> am einfachsten, indem du vor alle Sonderzeichen einen
>>> Backslash packst:
>>>
>>>
>>> BEFEHL="kdialog --msgbox \"Beginn: \$DATUM \\nEnde:
>>> \$FERTIG\\n\$LAUFZEIT\" &"
>>
>> Wenn in dem Befehl ein Newline‐Zeichen vorkommt, scheitert das,
>> weil Newline‐Zeichen mit einem Backslash nicht geschützt werden
>> können.
>>
>
> Die Newlines muss man hier nicht gesondert behandeln, sondern
> einfach stehenlassen:
>
>
> BEFEHL="echo \"foo
> bar\""
>
> eval "$BEFEHL"
>
Das ist richtig, entspricht aber nicht dem, was du oben
als Regel beschrieben hast (nochmal zitiert):
>>> Du musst dafür sorgen, dass die Variable BEFEHL genau den
>>> Befehl mit allen gewünschten Sonderzeichen enthält. Das geht
>>> am einfachsten, indem du vor alle Sonderzeichen einen
>>> Backslash packst:
>>>
Du hast mehr als diese Regel angewendet: Du hast außerdem die
ganze Kommandozeile in Anführungszeichen gesetzt.
Außerdem hat man dann noch die Frage zu beantworten, welche
Zeichen denn Sonderzeichen sind. (Und die Antwort fällt
unterschiedlich aus je nachdem, ob man die ganze Kommandozeile in
Anführungszeichen setzen will oder nicht.)
Wie du richtig bemerkt hast, ist das Newline‐Zeichen in diesem
Fall kein Sonderzeichen.
>
>>> Im konkreten Fall reicht auch, einfach ein Hochkomma davor und
>>> eins dahinter
>>>
>>>
>>> BEFEHL='kdialog --msgbox "Beginn: $DATUM \nEnde:
>>> $FERTIG\n$LAUFZEIT" &'
>>>
>>> aber das wird dann unhandlich, wenn der Befehl Hochkommate
>>> enthält.
>>>
>>
>> Dann ersetzt man einfach zuvor alle im Befehl stehenden
>> Hochkommata (mit einem Suchen‐und‐Ersetzen‐Kommando des
>> Texteditors) durch die Zeichenfolge „'\''“ (ein Hochkomma,
>> einen umgekehrten Schrägstrich und zwei Hochkommata).
>>
>
> Das ist das, was ich mit unhandlich meine.
>
Da gehen vielleicht unsere Vorlieben auseinander: Ich möchte
lieber die ganze Kommandozeile im Texteditor markieren und dann
stupide bei der ersten Stelle, die der Editor auf dem markierten
Textausschnitt findet, die Rückfrage „Ersetzen: [J]a, [N]ein, [A]lle?“
mit „A“ beantworten und habe genau alle Änderungen auf einen
Sitz vorgenommen. Dabei muss ich nicht entscheiden, welche
Zeichen denn nun Sonderzeichen sind und welche nicht.
>>> Dennoch wäre meine Empfehlung, eine Shellfunktion zu
>>> verwenden.
>>>
>>>
>>> status() {
>>> kdialog --msgbox "Beginn: $DATUM \nEnde: $FERTIG
>>> \n$LAUFZEIT" &
>>> }
>>> BEFEHL=status
>>>
>>> Dann kannst du zum Aufrufen auch auf das 'eval' verzichten,
>>> sondern einfach $BEFEHL aufrufen.
>>>
>>
>> Nicht
>>
>>
>> $BEFEHL
>>
>> sondern
>>
>>
>> "$BEFEHL".
>
> Das kommt halt drauf an, was man will.
>
Genau. Ich wiederhole es gerne: Wenn man will, dass die in der
Shell‐Variablen „IFS“ genannten Zeichen als Sollbruchstellen
wirken, dann muss man die Anführungszeichen weglassen; wenn man
das nicht will, muss man sie hinschreiben.
> "$BEFEHL" -- die Variable enthält ein Wort, das als Befehlsname
> interpretiert werden soll, z.B. einen Dateinamen, der Leerzeichen
> enthalten kann.
>
Und genau da ist die Falle: nicht „Leerzeichen enthalten kann“
sondern „IFS‐Zeichen enthalten kann“.
>
> $BEFEHL -- die Variable enthält ein Kommando mit Optionen. Das ist
> angemessen für Dinge wie "CC=gcc -m32 -sysroot=/whatever", aber
> Parameter mit Leerzeichen drin sind nicht möglich.
>
… mit IFS‐Zeichen drin
>
> eval "$BEFEHL" -- die Variable enthält ein Kommando, das
> Shell-Sonderzeichen beinhalten kann, von Quoting über weitere
> Variablen bis zu '&' und Umleitungen.
Kurz: Die Variable enthält eine Kommandozeile. (Darin können
auch mehrere Kommandos sein.)
>
> Shell ist nicht so eine unvorhersehbare Naturkatastrophe, wie
> sie manchmal dargestellt wird, aber man muss eben immer gut bei
> der Sache sein und sich zu jedem Zeitpunkt klar sein, was für
> Werte man wie in seine Variablen packt, und wenn man zu viel auf
> einmal will, wird es unübersichtlich.
>
Da sind wir uns vollkommen einig.
[toc] | [prev] | [next] | [standalone]
| From | Helmut Waitzmann <nn.throttle@xoxy.net> |
|---|---|
| Date | 2025-07-16 23:38 +0200 |
| Message-ID | <83o6tjstnf.fsf@helmutwaitzmann.news.arcor.de> |
| In reply to | #14537 |
Alexander Goetzenstein <alexander_goetzenstein@web.de>: > Hallo, > ich habe mir angewöhnt, zur leichteren Fehlersuche und > Tippfehlervermeidung Befehle in Scripts zuerst in eine Variable > zu stecken und diese dann mittels eval auszuführen. Meist gibt > es kein Problem, aber momentan stehe ich auf dem Schlauch. > Folgender Befehl will nicht so wie ich es will: > > >> [...] >> ## Beispielwerte: >> DATUM=2025-07-16_14-10 >> FERTIG=2025-07-16_14-15 >> LAUFZEIT=5 Minuten >> [...] >> kdialog --msgbox "Beginn: $DATUM \nEnde: $FERTIG \n$LAUFZEIT" & > Erhältst du damit das gewünschte? (Ich kenne „kdialog“ nicht, deshalb frage ich und gehe im folgenden davon aus, dass das der Fall ist.) > > Letzteren Befehl möchte ich wie erwähnt behandeln, doch > Konstrukte wie > >> BEFEHL=kdialog --msgbox "Beginn: $DATUM \nEnde: $FERTIG \n$LAUFZEIT" & >> eval "$BEFEHL" > > ergeben nicht das gewünschte Ergebnis. > […] > Wie geht es richtig? > Eine Kommandozeile, die ein simple command darstellt, kannst du auf folgende Weise so umarbeiten, dass sie in eine Shell‐Variable (hier: „BEFEHL“) gesteckt werden und anschließend per eval "$BEFEHL" aufgerufen werden kann: Als ersten Schritt schreib die Kommandozeile zunächst ohne „BEFEHL=“ am Zeilenanfang hin. Im Beispiel sieht es so aus: kdialog --msgbox "Beginn: $DATUM \nEnde: $FERTIG \n$LAUFZEIT" Als zweiten Schritt nimm in deinem Texteditor das Suche‐und‐Ersetze‐Kommando her und ersetze alle in der Kommandozeile vorkommenden Apostrophe („'“) durch die folgende Zeichenfolge: „'\''“ (einen Apostroph, einen Backslash und zwei Apostrophe). Im Beispiel sieht es so aus: kdialog --msgbox "Beginn: $DATUM \nEnde: $FERTIG \n$LAUFZEIT" (Das ist hier unverändert, weil in der Kommandozeile keine Apostrophe vorkommen.) Als dritten Schritt setze vorne und hinten an die Kommandozeile jeweils einen Apostroph. Im Beispiel sieht es so aus: 'kdialog --msgbox "Beginn: $DATUM \nEnde: $FERTIG \n$LAUFZEIT"' Als vierten Schritt setze vor den Apostroph am Kommandozeilenanfang noch den Text „BEFEHL=“. Im Beispiel sieht es so aus: BEFEHL='kdialog --msgbox "Beginn: $DATUM \nEnde: $FERTIG \n$LAUFZEIT"' Jetzt hast du ein Zuweisekommando, das an die Variable „BEFEHL“ die Kommandozeile in einer Form zuweist, die es erlaubt, die Kommandozeile mittels des Befehls eval "$BEFEHL" auszuführen. Diese Methode funktioniert immer, egal, welche Sonderzeichen das simple command in der Kommandozeile enthält. Zum Hintergrund, warum das funktioniert: Hast du noch Zugriff auf den im folgenden genannten Usenet‐Beitrag? (Falls gewünscht, kann ich ihn auch nochmal posten.) Subject: Sonderzeichen in der Shell-Kommandozeile? Quoting hilft! (was: rekursive Suche) From: Helmut Waitzmann <nn.throttle@xoxy.net> Newsgroups: de.comp.os.unix.linux.misc, de.comp.os.unix.shell Followup-To: de.comp.os.unix.shell Date: Sat, 04 Jan 2025 23:03:33 +0100 Message-ID: <83o70muthm.fsf_-_@helmutwaitzmann.news.arcor.de>
[toc] | [prev] | [standalone]
Back to top | Article view | de.comp.os.unix.shell
csiph-web