ubuntuusers.de

Ausführen von Skripten / Programme

Status: Ungelöst | Ubuntu-Version: Ubuntu MATE 12.04 (Precise Pangolin)
Antworten |

UbuntuUsersNeuling

Anmeldungsdatum:
14. Januar 2009

Beiträge: 228

Hallo,

ich habe einen Denkfehler. Bin das erste mal an einem Bash-Skript dran. Dazu habe ich mal das Ubuntuusers-Anfänger Tutorial gelesen, aber finde gerade nicht das Problem.

Ich habe mir mittels Variablen hartkodiert Parameter erzeugt. Diese sollen mit einem Befehl zusammengesetzt werden und dann ausgeführt werden.

Wir kann ich jetzt den Zusammengesetzten (bis jetzt noch) Text als Befehl ausführen lassen. Machen wir das am Beispiel Sendmail.

1
2
3
4
5
6
empfaenger="to@example.com"
absender="from@example.com"

befehl = sendmail -f $absender - t $empfaenger (... usw. die Parameterliste)

echo /usr/sbin/$befehl

das echo $befehl zeigt mir den Befehl nur an, führt ihn aber doch nicht aus? ohne den echo-Befehl passiert gar nichts... Irgendwo hab ich hier einen Denkfehler, der vermutlich ganz einfach ist. Kann mir kurz jemand sagen, wo ich den Fehler eingebaut hab ☹

Sorry... teste mich gerade das erste mal ran...

Gruß

TomTobin

Avatar von TomTobin

Anmeldungsdatum:
24. August 2007

Beiträge: 3101

Hallo UbuntuUsersNeuling,

Bin das erste mal an einem Bash-Skript dran.

Dann sollte das auch in der ersten Zeile drin stehen:

1
#!/bin/bash

beim Zeile 4 hast Du plötzlich Leerzeichen vor und nach dem = und beim Parameter t vor dem Minus?

befehl = sendmail -f $absender - t $empfaenger (... usw. die Parameterliste)

Besser:

1
befehl="sendmail -f $absender -t $empfaenger ..."

Versuchs mal so:

1
2
3
4
5
6
7
8
9
#!/bin/bash
empfaenger="to@example.com"
absender="from@example.com"

befehl="sendmail -f $absender -t $empfaenger -restparameter"

echo "Testausgabe: $befehl"
echo "Ausführen:"
$befehl

Außerdem könnte das hier noch hilfreich sein: Shell/Bash-Skripting-Guide für Anfänger

Gruß

Tom

rklm Team-Icon

Projektleitung

Anmeldungsdatum:
16. Oktober 2011

Beiträge: 13197

UbuntuUsersNeuling schrieb:

ich habe einen Denkfehler.

Im Wesentlichen ein kleines Syntaxproblem. ☺

Wir kann ich jetzt den Zusammengesetzten (bis jetzt noch) Text als Befehl ausführen lassen. Machen wir das am Beispiel Sendmail.

1
2
3
4
5
6
empfaenger="to@example.com"
absender="from@example.com"

befehl = sendmail -f $absender - t $empfaenger (... usw. die Parameterliste)

echo /usr/sbin/$befehl

Das Problem sind die Leerzeichen um das Gleichheitszeichen herum. Die müssen weg. In diesem Fall macht es allerdings wenig Sinn, den Befehl erst einer Variable zuzuweisen und ihn dann auszuführen. Zum einen gibt es ja nur eine Verwendung des Wertes (bei der Ausführung) und zu anderen macht es das Quoten schwerer. Besser ist:

1
/usr/sbin/sendmail -f "$absender" "$empfaenger" (... usw. die Parameterliste)

Ansonsten solltest Du den Befehl in einem Array zusammen bauen, weil dann das Quoting besser funktioniert:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# in einem Rutsch
befehl=(/usr/sbin/sendmail -f "$absender" "$empfaenger" (... usw. die Parameterliste))

# einzeln bzw. in Gruppen
befehl=(/usr/sbin/sendmail)
befehl+=(-f "$absender")
befehl+=("$empfaenger")
befehl+=(... usw. die Parameterliste)

# Ausführung
"${befehl[@]}"

Die Lösung von TomTobin hat den Nachteil, dass bei Sonderzeichen in Argumenten (z.B. wenn man das Subject der Mail auf der Kommandozeile angeben will, das ja oft Leerzeichen enthält) der Befehl am Ende nicht korrekt ausgeführt wird. Beispiel:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
$ befehl="sendmail -s 'ich habe heute zeit'"
$ printf '%s\n' $befehl
sendmail
-s
'ich
habe
heute
zeit'
$ befehl=(sendmail -s 'ich habe heute zeit')
$ printf '%s\n' "${befehl[@]}"
sendmail
-s
ich habe heute zeit

Wie Du siehst, wird im ersten Fall das Subject in mehrere Argumente zerhackt, während es mit dem Array klappt.

das echo $befehl zeigt mir den Befehl nur an, führt ihn aber doch nicht aus?

Genau.

ohne den echo-Befehl passiert gar nichts...

Du kannst relativ einfach sehen, was das Skript genau macht, indem Du hinter der ersten Zeile (mit dem Shebang) folgende Zeile einfügst:

1
set -x

Das gibt Dir einen Trace der Skriptausführung aus.

Irgendwo hab ich hier einen Denkfehler, der vermutlich ganz einfach ist. Kann mir kurz jemand sagen, wo ich den Fehler eingebaut hab ☹

s.o.

UbuntuUsersNeuling

(Themenstarter)

Anmeldungsdatum:
14. Januar 2009

Beiträge: 228

Hallo,

vielen Dank für den Hinweis. Zeile 1 hab ich nicht vergessen! Nur hier nicht aufgeführt. Sonst wüsste die Shell ja nicht, wo mit es ausgeführt werden soll - hab ich so verstanden. Das mit dem Leerzeichen werde ich gleich kontrollieren - hab es hier von Hand abgeschrieben und nicht C&P gemacht.

Aber das mit der Zeile 9 von dir, hab ich auch probiert... irgendwie nicht geklappt.

Mit

1
$variablenname_inkl.Parameternamen

kann ich also doch den Befehl ausführen, so wie ich es mir eigentlich auch vorgestellt hab. Dann muss das Problem woran anders liegen, dass es nicht funktioniert hat.

Danke für die Erklärung.

Gruß

UbuntuUsersNeuling

(Themenstarter)

Anmeldungsdatum:
14. Januar 2009

Beiträge: 228

rklm schrieb:

Das Problem sind die Leerzeichen um das Gleichheitszeichen herum. Die müssen weg. In diesem Fall macht es allerdings wenig Sinn, den Befehl erst einer Variable zuzuweisen und ihn dann auszuführen. Zum einen gibt es ja nur eine Verwendung des Wertes (bei der Ausführung) und zu anderen macht es das Quoten schwerer. Besser ist:

das hatte ich ja schon beim Vorposting (es hat sich überschnitten) beschrieben, dass dies ein Übertragungsfehler von mir war.

rklm schrieb:

Ansonsten solltest Du den Befehl in einem Array zusammen bauen, weil dann das Quoting besser funktioniert:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# in einem Rutsch
befehl=(/usr/sbin/sendmail -f "$absender" "$empfaenger" (... usw. die Parameterliste))

# einzeln bzw. in Gruppen
befehl=(/usr/sbin/sendmail)
befehl+=(-f "$absender")
befehl+=("$empfaenger")
befehl+=(... usw. die Parameterliste)

# Ausführung
"${befehl[@]}"

Diesen Part versteh ich evtl. nicht ganz: befehl+ wäre die Konkatenation von mehrerer String-Elementen? Dann würde der Befehl zum Fehler führen, weil vor dem Empfänger kein -t steht, oder? Das könnte man ja noch einfügen, aber dann hätte ich das verstanden.

${befehl[@]} erklärt sich mir noch nicht. Hier wird die Variable befehl mit allen Einträgen also befehl[0], befehl[1], ... befehl[x] hintereinanger angezeigt?

rklm schrieb:

Die Lösung von TomTobin hat den Nachteil, dass bei Sonderzeichen in Argumenten (z.B. wenn man das Subject der Mail auf der Kommandozeile angeben will, das ja oft Leerzeichen enthält) der Befehl am Ende nicht korrekt ausgeführt wird. Beispiel:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
$ befehl="sendmail -s 'ich habe heute zeit'"
$ printf '%s\n' $befehl
sendmail
-s
'ich
habe
heute
zeit'
$ befehl=(sendmail -s 'ich habe heute zeit')
$ printf '%s\n' "${befehl[@]}"
sendmail
-s
ich habe heute zeit

Wie Du siehst, wird im ersten Fall das Subject in mehrere Argumente zerhackt, während es mit dem Array klappt.

das echo $befehl zeigt mir den Befehl nur an, führt ihn aber doch nicht aus?

Genau.

ohne den echo-Befehl passiert gar nichts...

Du kannst relativ einfach sehen, was das Skript genau macht, indem Du hinter der ersten Zeile (mit dem Shebang) folgende Zeile einfügst:

1
set -x

Das gibt Dir einen Trace der Skriptausführung aus.

Irgendwo hab ich hier einen Denkfehler, der vermutlich ganz einfach ist. Kann mir kurz jemand sagen, wo ich den Fehler eingebaut hab ☹

s.o.

Printf macht eine Ausgabe ähnlich zu echo? '%s\n' bedeutet, dass bei einem Leerzeichen umgebrochen wird und damit jedes erzeugte Teilstring in einer neuen Zeile angezeigt wird?

Ansonsten vielen Dank für die Erklärung(en).

track

Avatar von track

Anmeldungsdatum:
26. Juni 2008

Beiträge: 7174

Wohnort: Wolfen (S-A)

Du solltest Dir auch noch einmal das "Quoting" genauer angucken !

- denn Du "quotest" in Deinen Zeilen 1 und 2, wo es gar nicht nötig ist.
Und später, wo es evt. kritisch sein könnte, quotest Du gar nichts mehr, so dass am Ende sowieso alles ungequotet ist.

Da müsstest Du nochmal genauer drauf gucken. Vor allem im Blick darauf, wo Leerzeichen kommen können und wo nicht.
Aber dazu hat Robert ja auch schon was geschrieben, das ich nur noch um Greg's Wiki-Artikel ergänzen möchte.

LG,

track

rklm Team-Icon

Projektleitung

Anmeldungsdatum:
16. Oktober 2011

Beiträge: 13197

UbuntuUsersNeuling schrieb:

rklm schrieb:

Ansonsten solltest Du den Befehl in einem Array zusammen bauen, weil dann das Quoting besser funktioniert:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# in einem Rutsch
befehl=(/usr/sbin/sendmail -f "$absender" "$empfaenger" (... usw. die Parameterliste))

# einzeln bzw. in Gruppen
befehl=(/usr/sbin/sendmail)
befehl+=(-f "$absender")
befehl+=("$empfaenger")
befehl+=(... usw. die Parameterliste)

# Ausführung
"${befehl[@]}"

Diesen Part versteh ich evtl. nicht ganz: befehl+ wäre die Konkatenation von mehrerer String-Elementen?

... von mehreren Einträgen im Array. Es wird an das Array angehängt.

Dann würde der Befehl zum Fehler führen, weil vor dem Empfänger kein -t steht, oder? Das könnte man ja noch einfügen, aber dann hätte ich das verstanden.

Lies Dir noch einmal die Manpage von sendmail zur Bedeutung der Option "-t" durch.

${befehl[@]} erklärt sich mir noch nicht. Hier wird die Variable befehl mit allen Einträgen also befehl[0], befehl[1], ... befehl[x] hintereinanger angezeigt?

Ja, und zwar als getrennte Argumente, wie Du an der Ausgabe von printf erkennen kannst.

Printf macht eine Ausgabe ähnlich zu echo? '%s\n' bedeutet, dass bei einem Leerzeichen umgebrochen wird und damit jedes erzeugte Teilstring in einer neuen Zeile angezeigt wird?

Nein, das bedeutet, dass jedes Argument, das Du printf übergibst, mit dem Muster "%s\n" ausgegeben wird. Es wird also hinter jedem Argument ein Newline ("\n") ausgegeben.

Ansonsten vielen Dank für die Erklärung(en).

Bitte!

Antworten |