ubuntuusers.de

bash: Script Terminal schließen lassen

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

Zoner

Anmeldungsdatum:
30. August 2019

Beiträge: 121

Ich hoffe ich werde dafür nicht verhauen, aber ein par einfache Dinge bekomme ich einfach nicht vernünftig recherchiert.

Ersteinmal, ich habe ein Bash-Script erstellt. Dieses öffnet ein Terminalfenster und führt einen simplen Befehl aus. Da mir einerseits Rückmeldungen wichtig sind und ich generell Spaß an vernünftig designten Programmen habe, soll das Fenster nicht sofort wieder verschwinden.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
#!/bin/bash 

bashallstart () {
        sudo systemctl start eins.timer \
        zwei.timer \
        drei.timer \
        vier.timer \
        fünf.timer \
        }

echofirst () {
        echo "$(tput bold)$(tput setaf 202) START all Timers$(tput sgr0)"
        }
        
echosecond () {
        echo "$(tput bold)$(tput setaf 2) ALL Timers $(tput blink)$(tput setaf 2)████$(tput sgr 0)$(tput bold)$(tput setaf 2) started $(tput bold)$(tput blink)$(tput setaf 2)████$(tput sgr 0)"
        }

echofirst && bashallstart && echosecond && sleep 5 && kill -9 $PPID

Das Fenster zeigt einen Titel (welche Aufgabe es hat), in der zweiten Zeile kommt die notwendige Sudo Passwortabfrage, und wenn alles durch ist, wird das mit einer dritten Zeile bestätigt und nach 5 Sekunden schließt sich das Fenster automatisch.

Nun habe ich schonmal festgestellt, dass man das Fenster nicht mit "exit" geschlossen bekommt. Bei normaler Terminal Benutzung klappt es, aber innerhalb eines Bash-Scripts nicht (obwohl ich viele Scripte im Internet finde, wo "exit" am Ende drin stand). Daher löse ich das per "kill -9 $PPID". Oder gibt es sauberere Lösungen? Und wieso schließt "exit" bei manueller Eingabe das Fenster aber nicht im Script?

Desweiteren möchte ich das Fenster, nachdem das Script durchgelaufen ist (um den Workflow zu erhöhen und weil X anklicken und Tastenkombinationen lästig sind) das Fenster zusätzlich zu den 5 Sekunden auch manuell per beliebiger Taste schließen. Am besten per Leertaste oder einem beliebigem Buchstaben aber ohne danach zusätzlich Enter drücken zu müssen.

Und weil das noch nicht genug ist, möchte ich einen rückwärts laufenden Ladebalken in einer extra Zeile, der mir anzeigt wann das Fenster sich schließt. Ich weiß nicht wie man das am saubersten löst. "echo -ne \b" funktionert nicht zusammen mit "sleep 0.1". Und sämtliche Lösungen wo es daraum geht, einfach nur die aktuelle Zeile durch eine neue zu ersetzen (einen langen Ladebalken durch einen etwas kürzeren) sind hochkompliziert. Ich habe das vor Jahrzehnten damals in Dos unter Windows schon gemacht und weiß dass das zumindest dort deutlich einfacher zu lösen war. Allerdings ist das schon lange her und vieleicht bin ich nur noch nicht auf die richtige Lösung gestoßen.

Mir ist auch aufgefallen, dass eine Funktion scheinbar immer ÜBER dessen "Verknüpfung" stehen muss. Also

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

bla () {
 irgendeinbefehl
}

bla

funktioniert. Aber:

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

bla

bla () {
 irgendeinbefehl
}

funktioniert hingegen nicht. Warum ist das so? (das macht halt das Script etwas unübersichtlicher, wenn die "wichtigen" Sachen ganz unten stehen müssen) Dass die Funktion erst "in den Speicher geladen werden muss", damit sie anschließend aufgerufen werden kann, kann ich mir nicht ganz vorstellen, weil in den Scripten sowieso teils kreuz und quer gesprungen wird und die Scripte vor Ausführung doch ohnehin erstmal komplett geladen werden?

Bearbeitet von sebix:

Besseren Titel gesetzt.

user_unknown

Avatar von user_unknown

Anmeldungsdatum:
10. August 2005

Beiträge: 17621

Wohnort: Berlin

Zoner schrieb:

Und weil das noch nicht genug ist, möchte ich einen rückwärts laufenden Ladebalken in einer extra Zeile, der mir anzeigt wann das Fenster sich schließt.

Proof of concept, bedarf der Feinjustierung:

1
echo -n "Fenster schließt in" {0..9}; for i in {0..9};  do echo -ne " \b\b\b "; sleep 0.3; done; echo 

Ich weiß nicht wie man das am saubersten löst. "echo -ne \b" funktionert nicht zusammen mit "sleep 0.1". Und sämtliche Lösungen wo es daraum geht, einfach nur die aktuelle Zeile durch eine neue zu ersetzen (einen langen Ladebalken durch einen etwas kürzeren) sind hochkompliziert. Ich habe das vor Jahrzehnten damals in Dos unter Windows schon gemacht und weiß dass das zumindest dort deutlich einfacher zu lösen war. Allerdings ist das schon lange her und vieleicht bin ich nur noch nicht auf die richtige Lösung gestoßen.

Mir ist auch aufgefallen, dass eine Funktion scheinbar immer ÜBER dessen "Verknüpfung" stehen muss.

Ja, die Funktion muss vor deren Verwendung oder Aufruf definiert sein. Der Interpreter arbeitet das von oben nach unten ab.

Also

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

bla () {
 irgendeinbefehl
}

bla

funktioniert. Aber:

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

bla

bla () {
 irgendeinbefehl
}

funktioniert hingegen nicht. Warum ist das so? (das macht halt das Script etwas unübersichtlicher, wenn die "wichtigen" Sachen ganz unten stehen müssen)

Man muss nur wissen, das die abstrakteste Lösung unten steht.

Für die anderen Fragen habe ich gerade keine Zeit. Man macht eh besser pro Frage einen Thread auf, dann kann man auch pro Frage dokumentieren, wenn sie gelöst ist.

kB Team-Icon

Supporter, Wikiteam
Avatar von kB

Anmeldungsdatum:
4. Oktober 2007

Beiträge: 9714

Wohnort: Münster

Zoner schrieb:

[…] Mir ist auch aufgefallen, dass eine Funktion scheinbar immer ÜBER dessen "Verknüpfung" stehen muss.

Nicht scheinbar, sondern ganz sicher ist das so. In einem Skript kann man nur das verwenden, was vorher definiert wurde oder mit der Verwendung angelegt werden kann. Das ist so, weil ein Skript interpretiert wird und dazu wird es bei der Ausführung einmal gelesen. Bei Sprachen wie z.B. Fortran, C, Ada, Java ist das anders. Der Compiler liest den Quelltext mehrmals und kann dann auch Dinge verstehen, deren Definition im Text erst nach ihrer Verwendung stehen. Jedenfalls manche Compiler können das.

user_unknown

Avatar von user_unknown

Anmeldungsdatum:
10. August 2005

Beiträge: 17621

Wohnort: Berlin

Zoner schrieb:

Desweiteren möchte ich das Fenster, nachdem das Script durchgelaufen ist (um den Workflow zu erhöhen und weil X anklicken und Tastenkombinationen lästig sind) das Fenster zusätzlich zu den 5 Sekunden auch manuell per beliebiger Taste schließen. Am besten per Leertaste oder einem beliebigem Buchstaben aber ohne danach zusätzlich Enter drücken zu müssen.

Noch ein Infoschnipsel:

1
2
read -t 5 -n 1 -p "Drücken Sie die Pinguintaste fuer Abbruch" taste 
echo $taste

Näheres verrät

1
help read

Zoner

(Themenstarter)

Anmeldungsdatum:
30. August 2019

Beiträge: 121

Mein Code für den Ladebalken sieht jetzt so aus:

1
echo -n "$(tput setab 8)$(tput setaf 0)|<-- closing window$(tput sgr 0)$(tput setaf 8)███████████████████████████████████████████████████████████████$(tput sgr 0)"; for i in {0..80};  do echo -ne " \b\b\b "; sleep 0.03; done; echo

(die Dauer kann man dann mit sleep feinjustieren, in diesem Fall theoretisch 2,4 Sekunden)

Ich habe die Befürchtung dass sich der Ladebalken nicht zusätzlich mit der Funktion "schließen mit beliebiger Taste" kombinieren lässt, da in Bash alles nacheinander abgearbeitet wird? Also entweder läuft der Ladebalken ODER es wird gewartet bis eine beliebige Taste gedrückt wird. Beides gleichzeitig geht nicht? Zumindest fand ich keine Lösung dafür, bzw. sogar Aussagen, dass eine parallele Abarbeitung von Befehlen innerhalb eines Bash-Scripts nicht möglich sind.

user_unknown

Avatar von user_unknown

Anmeldungsdatum:
10. August 2005

Beiträge: 17621

Wohnort: Berlin

Ich würde sowas ja einfach mal rasch probieren:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
cnt () {  
  for i in {0..3}; do echo $i; sleep 0.5 ; done 
}

cnt & cnt 
[1] 18048
0
0
1
1
2
2
3
3
[1]+  Fertig                  cnt

Zumindest fand ich keine Lösung dafür, bzw. sogar Aussagen, dass eine parallele Abarbeitung von Befehlen innerhalb eines Bash-Scripts nicht möglich sind.

Wo hast Du diese Aussagen denn gefunden?

Zoner

(Themenstarter)

Anmeldungsdatum:
30. August 2019

Beiträge: 121

user_unknown schrieb:

Wo hast Du diese Aussagen denn gefunden?

Das weiß ich nicht mehr. Habe wild herum gegooglet auf deutschen und englischen Seiten. Es kann aber sein, dass es dabei vieleicht eher um Multithreading ging. Mein Fall war wol zu simpel und die Themen die ich fand alle zu spezifisch.

Hab es durch herumprobieren jetzt einfach mit "&" gelöst.

Hab das Anfangs nicht verstanden, weil ich sowas versucht hatte:

1
Echo1 && Aufgabe && Echo2 && Ladebalkenschließung & Tastenschließung

Und das funktionierte nicht. Dachte er arbeitet die ersten 3 Dinge nacheinander ab und dann erst die letzten beiden gleichzeitig. Statt dessen, führt er "Tastenschließung" sofort am Scriptanfang aus, sodass ich das sudo Passwort nicht mehr eingeben kann. (wobei ich die Logic dahinter jetzt aber verstanden habe) Ich hab einfach zu wenig mit dem "&" ausprobiert. (hatte dafür bisher nie Verwendnung)

Also habe ich es an eine Bedingung verknüpft (erst nach echo2):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15

Echo1 (){
echo
}

Aufgabe (){
command
}

Echo2 (){
echo
Ladebalkenschließung & Tastenschließung
}

Echo1 && Aufgabe && Echo2

Jetzt funktioniert alles in der richtigen Reihenfolge und die beiden Schließmechanismen dennoch beide gleichzeitig. Wenn ich Zeit habe, muss ich mir die Grundlagen unbedingt nochmal anschauen. Das mit dem & hatte ich bisher falsch verstanden. Dachte immer, damit haut man eine Aufgabe nur in den Hintergrund, sodass diese nur nicht im Terminal angezeigt wird aber ansonsten ähnlich wie mit "&&" behandelt wird. Das kommt davon wenn man nur Zeit hat, sich damit zu beschäftigen was man gerade braucht aber nicht erstmal das Grundgerüst richtig verinnerlicht.

Damit sind für mich jetzt alle Probleme gelöst. Vielen Dank für die Hilfe!

Finale "Schließ"script sieht also 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
25
echo1 () {
        echo "Scriptbezeichnung"
        }

Aufgabe () {
        command
        {

echo2 () {
        echo "$(tput bold)$(tput setaf 2) All Timers $(tput blink)$(tput setaf 2)████$(tput sgr 0)$(tput bold)$(tput setaf 2) started $(tput bold)$(tput blink)$(tput setaf 2)████$(tput sgr 0)"
        echoexit & tastexit
        }
        
echoexit () {
        echo -n "$(tput setab 8)$(tput setaf 0) |<-- closing window$(tput sgr 0)$(tput setaf 8)███████████████████████████████████████████████████████████████$(tput sgr 0)"; for i in {0..80};  do echo -ne " \b\b\b "; sleep 0.03; done; echo
        kill -9 $PPID
        }

tastexit () {
        read -n 1 taste 
        echo $taste
        kill -9 $PPID
}     
        
echo1 && Aufgabe && echo2
Antworten |