staging.inyokaproject.org

Vor einem Programmstart ein eigenes Skript vorschalten

Status: Gelöst | Ubuntu-Version: Ubuntu MATE 20.04 (Focal Fossa)
Antworten |

CarstenHa

Avatar von CarstenHa

Anmeldungsdatum:
1. Mai 2020

Beiträge: 154

Hallo, ich habe da eine kleine Sache, wo ich nicht weiter komme. Ich möchte gerne, bevor ich ein Programm starte, ein eigenes Skript vorschalten und habe versucht, das in einer .desktop-Datei unterzubringen:

Exec=/pfad/zum/eigenen/skript.sh; programmname %F

Das funktioniert leider nicht. Bei zwei Bash-Befehlen funktioniert das ja zum Beispiel mit:

Exec=bash -c "foo ; bar"

Die Sache ist, ich möchte das %F nicht verlieren, sonst könnte ich ja einfach das Programm im Skript aufrufen. Hat jemand eine Idee?

Viele Grüße

Carsten

schmauch

Avatar von schmauch

Anmeldungsdatum:
27. April 2009

Beiträge: 115

Warum packst du den Programm-Aufruf nicht in dein Skript?

Falls du das nicht möchtest, könntest du auch ein zweites Skript anlegen, in dem du zuerst dein Skript ausführst und anschliessend das Programm startest. Zum Beispiel:

1
2
3
4
5
6
7
#!/bin/bash

/pfad/zum/eigenen/skript.sh

/pfad/zum/programm $1

exit 0

Das $1 enthält den Dateinamen, der mittels %F übergeben wurde (genauer, das erste Argument, das dem Skript übergeben wurde). Du könntest dann auch noch einen Test einfügen, ob die Datei existiert...

CarstenHa

(Themenstarter)
Avatar von CarstenHa

Anmeldungsdatum:
1. Mai 2020

Beiträge: 154

Ah super, das klappt. Ich wusste nicht, das man %F mit $1 ansprechen kann. Danke für Deine Hilfe!

seahawk1986

Anmeldungsdatum:
27. Oktober 2006

Beiträge: 11278

Denk daran, dass $1 nur dem ersten Argument entspricht, das dem Skript übergeben wurde. %F ist laut https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html#exec-variables aber eine Liste von Dateien, d.h. es kann mehr als ein Argument übergeben werden.

Dementsprechend wäre sowas eine Möglichkeit:

Exec=bash -c '/pfad/zum/eigenen/skript.sh; programmname "$@"' %F

CarstenHa

(Themenstarter)
Avatar von CarstenHa

Anmeldungsdatum:
1. Mai 2020

Beiträge: 154

Stimmt, da hatte ich jetzt gar nicht dran gedacht. $1 könnte man dann wahrscheinlich bei %f anwenden. Und wieder was gelernt. Vielen Dank!

CarstenHa

(Themenstarter)
Avatar von CarstenHa

Anmeldungsdatum:
1. Mai 2020

Beiträge: 154

Für alle, die es interessiert, hier mein Skript:

Zuerst habe ich die Exec-Zeile in der .desktop-Datei ausgetauscht und durch folgende ersetzt:

Exec=/pfad/zum/eigenen/script.sh %F

Das Skript sieht dann folgendermaßen aus:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#!/bin/bash
# Mit diesem Skript wird ein Dialog vor dem eigentlichen Programmstart vorgeschaltet.
# Hier wird bei 'ja' Festplatte gemountet.

devicebez="/dev/sdh1"

if [ -z "$(type -p zenity)" ]; then
 zenity --info --text "Zenity ist nicht installiert. Festplatteneinbindung bitte manuell vornehmen." --title "Hinweis"
 exit 1
fi

if [ -z "$(mount -l | grep "$devicebez")" ]; then

  zenity --question --title "Festplatte einbinden" --text "Soll Festplatte gemountet werden?"

  # In der entsprechenden .desktop-Datei wird mit %F evtl. eine Liste von Dateien übergeben.
  # Diese wird mit $@ in diesem Skript weiter verarbeitet.
  # 0 ist der Rückgabewert bei Klick auf ja. 1 ist der Rückgabewert bei Klick auf nein.

  if [ $? == 0 ]; then
   gio mount -d "$devicebez"
   programmname "$@"
  elif [ $? == 1 ]; then
   programmname "$@"
  fi
  
else

  programmname "$@"

fi

Folgende Elemente im Skript müssen ggf. angepasst werden:

  • Variable devicebez

  • programmname

Viel Spaß!

Marc_BlackJack_Rintsch Team-Icon

Ehemalige
Avatar von Marc_BlackJack_Rintsch

Anmeldungsdatum:
16. Juni 2006

Beiträge: 4735

@CarstenHa: Nicht böse sein, aber ich musste gerade herzlich lachen beim lesen des Skripts.

Du prüfst ob zenity vorhanden ist, und wenn nicht zeigst Du einen entsprechenden Hinweis an — mit zenity. 😉

Die Ausgabe von mount zu greppen ist umständlich und fehleranfällig. Du musst das Muster beispielsweise am Zeilenanfang verankern und danach auch ein Leerzeichen angeben. Ohne das Leerzeichen würde im konkreten Fall beispielsweise auch /dev/sdh10 erkannt. Die Manpage von mount verweist für solche Aufgaben auf findmnt.

Die ganze if/else-Logik in der 3× die gleiche Zeile zum Starten des Programms steht, ist überkompliziert. Das Programm wird ja letztlich in jedem Fall gestartet, muss da also überhaupt gar nicht in diesem Konstrukt das Programm starten, sondern kann diese Zeile einmal hinter das Konstrukt setzen.

Ausserdem sind die Zweige so simpel, dass man das auch ohne if ausdrücken kann.

Last but not least: Wenn man das Programm am Ende von Skript nicht als Kindprozess startet, sondern den Shell-Prozess dadurch ersetzt, hat man einen unnötigen Prozess weniger herumhängen während das Programm läuft.

Ungetestet:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
#!/bin/bash
# Mit diesem Skript wird ein Dialog vor dem eigentlichen Programmstart
# vorgeschaltet.
# Hier wird bei 'ja' Festplatte gemountet.

readonly devicebez=/dev/sdh1

if type -p zenity >/dev/null; then
    # zenity --info \
    #        --title "Hinweis" \
    #        --text "Zenity ist nicht installiert. Festplatteneinbindung bitte manuell vornehmen."
    exit 1
fi

! findmnt -rno SOURCE "$devicebez" >/dev/null \
    && zenity --question \
              --title "Festplatte einbinden" \
              --text "Soll Festplatte gemountet werden?" \
    && gio mount -d "$devicebez"

exec programmname "$@"

CarstenHa

(Themenstarter)
Avatar von CarstenHa

Anmeldungsdatum:
1. Mai 2020

Beiträge: 154

@Marc_BlackJack_Rintsch: Uuuh, ein typischer Fall von zenity-Paradoxon 😀 Und mit scharfer Klinge seziert 👍

Mir ist auch noch was eingefallen: Da sich die Geräte-Dateien unter Umständen ändern können, habe ich die Platte jetzt anhand des Labels ermittelt (man könnte das nach Bedarf auch über UUID machen):

devicebez="$(lsblk --list --fs | grep 'name_der_festplatte' | cut -d' ' -f1)"

@Marc_BlackJack_Rintsch: An die vereinfachte Schreibweise ohne if-Verzweigung muss ich mich erst noch dran gewöhnen. Aber Danke für die vielen Anregungen!

Mein Skript sieht jetzt so aus:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#!/bin/bash
# Mit diesem Skript wird ein Dialog vor dem eigentlichen Programmstart vorgeschaltet.
# Hier wird bei 'ja' Festplatte gemountet.

devicebez="$(lsblk --list --fs | grep 'name_der_festplatte' | cut -d' ' -f1)"

if [ -z "$(type -p zenity)" ]; then
 exit 1
fi

if [ -z "$(findmnt -rno SOURCE /dev/$devicebez)" ]; then

  zenity --question --title "Kartenplatte einbinden" --text "Soll Festplatte gemountet werden?"

  # 0 ist der Rückgabewert bei Klick auf ja. 1 wäre der Rückgabewert bei Klick auf nein.
  if [ $? == 0 ]; then
   gio mount -d /dev/"$devicebez"
  fi
  
fi

# In der entsprechenden .desktop-Datei wird mit %F evtl. eine Liste von Dateien übergeben.
# Diese wird mit $@ weiter verarbeitet.
exec qmapshack "$@"

Marc_BlackJack_Rintsch Team-Icon

Ehemalige
Avatar von Marc_BlackJack_Rintsch

Anmeldungsdatum:
16. Juni 2006

Beiträge: 4735

@CarstenHa: Ich würde noch mal mit Nachdruck auf findmnt hinweisen statt da die Ausgabe von irgendwelchen Werkzeugen mit grep und cut zu verarbeiten. Das ist für Skripte gedacht und man kann dort für die Quelle den Gerätenamen, oder die Major:Minor-Nummer, oder das Label oder die UUID vom Dateisystem oder der Partition angeben.

Und zumindest ich persönlich schrecke vor der Verwendung von $? ein wenig zurück. Das hat sich bei mir als Gefahrenquelle herausgestellt, weil nicht jede Änderung daran so offensichtlich ist. Beispiel:

1
2
3
4
5
6
7
8
das_hier_hat_einen_rueckgabecode_von_2
if [ $? -eq 0 ]; then
    echo 'Null'
elif [ $? -eq 2 ]; then
    echo 'Zwei'
else
    echo "Weder 0 noch 2 sondern: $?"
fi

Ausgabe:

Weder 0 noch 2 sondern: 1

Und wenn man sich jetzt wundern solle und mal nachschauen will was $? vor dem if für einen Wert hat und das naiverweise so macht:

1
2
3
4
5
6
7
8
9
das_hier_hat_einen_rueckgabecode_von_2
echo "Vor if: $?"
if [ $? -eq 0 ]; then
    echo 'Null'
elif [ $? -eq 2 ]; then
    echo 'Zwei'
else
    echo "Weder 0 noch 2 sondern: $?"
fi

Bekommt man:

Vor if: 2
Null

Wenn ich den Wert von $? verwende, dann ist das allererste bei mir immer den Wert sofort an einen anderen Namen binden. Und in Deinem Fall, wo der Wert sowieso nur einmal benötigt wird, gleich den Befehl selbst als Bedingung verwenden, in diesem Fall mit ! negiert.

Antworten |