[erledigt] Frage bzgl. Bash-Script (auf dmenu basierender file manager)

Vom einfachen Programm zum fertigen Debian-Paket, Fragen rund um Programmiersprachen, Scripting und Lizenzierung.
RobertDebiannutzer
Beiträge: 182
Registriert: 16.06.2017 09:52:36

[erledigt] Frage bzgl. Bash-Script (auf dmenu basierender file manager)

Beitrag von RobertDebiannutzer » 30.12.2017 15:04:57

Edit: Ergänzung

Hallo,

ich bin noch recht neu bei Linux, aber ich habe schon das Schreiben von mehr oder weniger kleinen Scripten als eine schöne kleine Beschäftigung für zwischendurch entdeckt.
Ich habe auch schon einige Sachen verfasst, aber jetzt würde ich euch erstmal gerne mein letztes Projekt zeigen und euch um eure Meinung dazu bitten.
Es geht um einen File Manager, den ich basierend auf dmenu geschrieben habe.
Möchte sich ein erfahrener Scripte-Schreiber mein Script vielleicht mal anschauen und mir als Anfänger sagen, ob das gut so ist? Ich habe mir zwar viel Mühe gegeben und und funktionieren tut es bei mir, aber ich nutze ihn noch nicht so lange und außerdem will ich sichergehen, dass es nicht nur funktioniert, sondern auch sicher funktioniert. Schließlich kann Programmieren und Scripte-Schreiben ja auch eine gefährliche Angelegenheit sein, wenn man nicht genau Bescheid weiß...

Anmerkung: Wer das Script ausprobieren möchte: Bitte nur, wenn Du es vorher genau geprüft hast! Wie gesagt, ich bin Anfänger und kann keine Garantie für die sichere Funktion des Scriptes übernehmen!

So, jetzt aber:
Erstmal eine grobe Beschreibung:
dmenu basiert ja darauf, dass es seinen Input anzeigt und die vom Nutzer getroffene Eingabe nach Output schreibt. Dabei kann der Nutzer entweder einen Menüeintrag auswählen und mit Enter bestätigen, oder etwas in die Suchzeile schreiben und mit Enter abschicken bzw. mit Shift+Enter, wenn ansonsten ein durch die Eingabe ausgewählter Menüeintrag nach Ouput geschrieben wird - s. dazu auch "man dmenu".
Mein file manger startet mit der Ansicht von "LC_ALL="C" ls -1 --group-directories-first -F" des aktuellen Arbeitsverzeichnisses, also üblicherweise $HOME. Nun kann man mit der beschriebenen Methode entweder einen Ordner aus der Liste wählen, also z.B. "Dokumente" oder man kann einen nicht in der Liste enthaltenen Ordner in die Suchleiste schreiben, wie z.B. .config/i3. In jedem Fall macht das Script "cd "Ordner"" und listet dann dessen Inhalte auf.
Durch den manuellen hinzugefügten Menüeintrag "../" kann man jederzeit auch wieder in den Parent-Ordner wechseln.

Wird eine Datei aus der Liste gewählt, wird sie mit dem für den entsprechenden mime-type eingestellen Programm geöffnet. Bei mir also z.B. plain/txt mit nano.
Wird ein grafisches Programm, also nicht nano, sondern z.B libreoffice geöffnet, beendet sich der file manager automatisch, ansonsten bleibt er im Hintergrund geöffnet und steht nach Schließen von nano (z.B.) wieder zur Verfügung.

Gibt man "+" in das Eingabefeld ein (und bestätigt ggf. mit Shift+Enter statt nur mit Enter, wenn ansonsten ein Eintrag aus der Menüliste ausgeführt wird), wechselt der file manager in die erweiterte Ansicht des aktuellen Ordners, also die Ansicht des Ordners, die sich aus "LC_ALL="C" ls -lAh --group-directories-first -F)"" ergibt.
Dort funktioniert alles genauso, wie in der einfachen Ansicht.
Mit "q" kann man die erweiterte Ansicht wieder verlassen.

Ist die Eingabe weder ein Ordner, noch eine Datei, noch "+", noch "q" (im erweiterten Modus), wird sie als Befehl ausgeführt, so z.B. "touch test" oder "rm test". Der file manager bleibt dabei immer geöffnet und aktualisiert seine Ansicht entsprechend.

Beendet wird der file manger mit ESC, dem kill-Signal von dmenu (s. man dmenu).

Hier das Script:

Code: Alles auswählen

#!/bin/bash

# License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
# This is free software; you are free to change and redistribute it.
# There is NO WARRANTY, to the extent permitted by law.

set -e

dmenu_cmd () {
	dmenu -i -l 25
}
apps_path="/home/robert/.local/share/applications/"

while true; do
if [ -n "$show" ]; then echo "$show" | dmenu_cmd > /dev/null; fi
show=''
list="$(echo -e "$(pwd)\n../\n$(LC_ALL="C" ls -1 --group-directories-first -F)" | dmenu_cmd)"
if [ -d "$list" ]; then
	cd "$list"
elif [ -f "$list" ]; then
	type=$(file -b --mime-type "$list")
	tool=$(grep -m 1 "$type" "/home/robert/.config/mimeapps.list" | sed "s@^.*=@"$apps_path"@" | cut -d ';' -f1)
	if [ ! -r "$tool" ]; then exit; fi
	if [ -n "$(grep 'Terminal=true' "$tool")" ]; then
		urxvt -e bash -c "$(sed -n '/\[Desktop Entry\]/,/^Exec=/!d;s/Exec=//p' "$tool") "$list""
	else
		exec $(sed -n '/\[Desktop Entry\]/,/^Exec=/!d;s/Exec=//p' "$tool") "$list" &
		exit
	fi
else
	if [ "$list" = '+' ]; then
		while true; do
		if [ -n "$show" ]; then echo "$show" | dmenu_cmd > /dev/null; fi
		show=''
		input="$(echo -e "$(pwd)\n../\n$(LC_ALL="C" ls -lAh --group-directories-first -F)" | dmenu_cmd)"
		if [[ "$input" = "4"* ]]; then
			COM=$(echo ${input#4})
			if eval $COM; then
				continue
			else
				show='An error occurred. Please press Enter.'
				continue
			fi
		elif [[ "$input" = 'q' ]]; then
			continue 2
		else
			list2=$(echo ${input##* })
			if [ -d "$list2" ]; then
				cd "$list2"
			elif [ -f "$list2" ]; then
				type=$(file -b --mime-type "$list2")
				tool=$(grep -m 1 "$type" "/home/robert/.config/mimeapps.list" | sed "s@^.*=@"$apps_path"@" | cut -d ';' -f1)
				if [ ! -r "$tool" ]; then exit; fi
				if [ -n "$(grep 'Terminal=true' "$tool")" ]; then
					urxvt -e bash -c "$(sed -n '/\[Desktop Entry\]/,/^Exec=/!d;s/Exec=//p' "$tool") "$list2""
				else
					exec $(sed -n '/\[Desktop Entry\]/,/^Exec=/!d;s/Exec=//p' "$tool") "$list2" &
					exit
				fi
			else
				show='An error occurred. Please press Enter.'
			fi
		fi
		done
	else
		if eval $list; then
			continue
		else
			show='An error occurred. Please press Enter.'
			continue
		fi
	fi
fi
done
Zuletzt geändert von RobertDebiannutzer am 05.04.2018 18:33:43, insgesamt 1-mal geändert.

owl102
Beiträge: 2296
Registriert: 16.10.2010 13:05:57
Lizenz eigener Beiträge: GNU Free Documentation License
Wohnort: Timbuktu

Re: Frage bzgl. Bash-Script (auf dmenu basierter FM)

Beitrag von owl102 » 30.12.2017 15:58:02

Ich habe jetzt keine Zeit, mir das Script anzuschauen (das hole ich später nach), aber auf jeden Fall würde ich 'mal dein Script durch

Code: Alles auswählen

shellcheck <Dateiname>
jagen, das kann nie schaden.

Wenn du einen Hinweis von shellcheck nicht verstehst: Die sind alle im Wiki von ShellCheck erläutert:

https://github.com/koalaman/shellcheck/wiki
Fedora 28 Workstation -- openSUSE Leap 42 / Gnome -- Debian 9 (Qnap TS-109/119) -- OmniOS (HP N54L)

RobertDebiannutzer
Beiträge: 182
Registriert: 16.06.2017 09:52:36

Re: Frage bzgl. Bash-Script (auf dmenu basierender file manager)

Beitrag von RobertDebiannutzer » 30.12.2017 17:20:07

Vielen Dank, das ist ja toll, dieses Programm!
"shellcheck -s bash ~/.fm.sh" (.fm.sh ist der Name von meinem Script) hat mir hauptsächlich Quoting-Probleme ausgegeben, die sich aus einer zu häufigen Nutzung von Anführungszeichen ergaben. So habe ich gelernt, das eine gequotete Variable in einem gequoteten Befehl nicht mehr gequotet ist - das hätte ich nicht gedacht!
Übrig geblieben sind folgende Hinweise:

Code: Alles auswählen

In /home/robert/.fm.sh line 24:
	if [ -n "$(grep 'Terminal=true' "$tool")" ]; then
             ^-- SC2143: Use grep -q instead of comparing output with [ -n .. ].
In /home/robert/.fm.sh line 27:
		exec $(sed -n '/\[Desktop Entry\]/,/^Exec=/!d;s/Exec=//p' "$tool") "$list" &
                     ^-- SC2046: Quote this to prevent word splitting.
In /home/robert/.fm.sh line 54:
				if [ -n "$(grep 'Terminal=true' "$tool")" ]; then
                                     ^-- SC2143: Use grep -q instead of comparing output with [ -n .. ].
In /home/robert/.fm.sh line 57:
					exec $(sed -n '/\[Desktop Entry\]/,/^Exec=/!d;s/Exec=//p' "$tool") "$list2" &
                                             ^-- SC2046: Quote this to prevent word splitting.
Hinweise 2 und 4 sind geld eingefärbt, sind aber nicht hilfreich. Das habe ich mit einem pdf getested, welches mit "firejail --apparmor --net=none qpdfview" geöffnet werden sollte. Das klappt aber nur ohne den Verbesserungsvorschlag von shellcheck. Aber warum?
Die Hinweise 1 und 3 sind in der Ausgabe von shellcheck grün gefärbt. Aber die sind doch falsch, denn wenn grep immer "success" als Ergebnis ausgibt, funktioniert ja mein If-Statement nicht mehr, oder wie ist das?

Mein verbessertes Script sieht nun so aus (verbessert habe ich gemäß der Vorschläge von shellcheck ein paar schädliche Anführungszeichen und zwei überflüssige echos):

Code: Alles auswählen

#!/bin/bash

# License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
# This is free software; you are free to change and redistribute it.
# There is NO WARRANTY, to the extent permitted by law.

set -e

dmenu_cmd () {
	dmenu -i -l 25
}
apps_path="/home/robert/.local/share/applications/"

while true; do
if [ -n "$show" ]; then echo "$show" | dmenu_cmd > /dev/null; fi
show=''
list="$(echo -e "$(pwd)\n../\n$(LC_ALL="C" ls -1 --group-directories-first -F)" | dmenu_cmd)"
if [ -d "$list" ]; then
	cd "$list"
elif [ -f "$list" ]; then
	type=$(file -b --mime-type "$list")
	tool=$(grep -m 1 "$type" "/home/robert/.config/mimeapps.list" | sed "s@^.*=@$apps_path@" | cut -d ';' -f1)
	if [ ! -r "$tool" ]; then exit; fi
	if [ -n "$(grep 'Terminal=true' "$tool")" ]; then
		urxvt -e bash -c "$(sed -n '/\[Desktop Entry\]/,/^Exec=/!d;s/Exec=//p' "$tool") $list"
	else
		exec $(sed -n '/\[Desktop Entry\]/,/^Exec=/!d;s/Exec=//p' "$tool") "$list" &
		exit
	fi
else
	if [ "$list" = '+' ]; then
		while true; do
		if [ -n "$show" ]; then echo "$show" | dmenu_cmd > /dev/null; fi
		show=''
		input="$(echo -e "$(pwd)\n../\n$(LC_ALL="C" ls -lAh --group-directories-first -F)" | dmenu_cmd)"
		if [[ "$input" = "4"* ]]; then
			COM="${input#4}"
			if eval "$COM"; then
				continue
			else
				show='An error occurred. Please press Enter.'
				continue
			fi
		elif [[ "$input" = 'q' ]]; then
			continue 2
		else
			list2="${input##* }"
			if [ -d "$list2" ]; then
				cd "$list2"
			elif [ -f "$list2" ]; then
				type=$(file -b --mime-type "$list2")
				tool=$(grep -m 1 "$type" "/home/robert/.config/mimeapps.list" | sed "s@^.*=@$apps_path@" | cut -d ';' -f1)
				if [ ! -r "$tool" ]; then exit; fi
				if [ -n "$(grep 'Terminal=true' "$tool")" ]; then
					urxvt -e bash -c "$(sed -n '/\[Desktop Entry\]/,/^Exec=/!d;s/Exec=//p' "$tool") $list2"
				else
					exec $(sed -n '/\[Desktop Entry\]/,/^Exec=/!d;s/Exec=//p' "$tool") "$list2" &
					exit
				fi
			else
				show='An error occurred. Please press Enter.'
			fi
		fi
		done
	else
		if eval "$list"; then
			continue
		else
			show='An error occurred. Please press Enter.'
			continue
		fi
	fi
fi
done

owl102
Beiträge: 2296
Registriert: 16.10.2010 13:05:57
Lizenz eigener Beiträge: GNU Free Documentation License
Wohnort: Timbuktu

Re: Frage bzgl. Bash-Script (auf dmenu basierender file manager)

Beitrag von owl102 » 30.12.2017 18:17:05

RobertDebiannutzer hat geschrieben: ↑ zum Beitrag ↑
30.12.2017 17:20:07
Das klappt aber nur ohne den Verbesserungsvorschlag von shellcheck.
...da ansonsten Befehl und Argumente als eine Zeichenkette übergeben werden. Das Quoting unterbindet ja das Word Splitting, was man aber hier haben möchte.

Die Möglichkeiten von shellcheck sind halt begrenzt. Es kann nur feststellen, daß etwas nicht gequotet ist, aber nicht, daß man vielleicht genau das benötigt.

In einem meiner Scripte gibt es diese Situation auch:

Code: Alles auswählen

# shellcheck disable=SC2086
tar Cxfz ... $verbosity_options ...
shellcheck meckert hier an, daß $verbosity_options nicht gequotet ist. Da stehen aber mehrere Optionen drin, es darf also nicht gequotet werden, weil ansonsten die ganzen Optionen als eine einzelne (unbekannte) Option an tar übergeben werden würde. (Wäre es hingegen ein Verzeichnisname oder ein Dateiname, sollte es gequotet werden, weil es ansonsten nicht funktionieren würde, wenn ein Leerzeichen enthalten ist.) Aber woher soll shellcheck wissen, was $verbosity_options ist?

Solche Situationen kann man mit "# shellcheck disable=<Warnungsnummer>" angeben, shellcheck weiß dann, daß die nächste Zeile bewußt so geschrieben wurde und unterläßt die angegebene Warnung.
Aber die sind doch falsch, denn wenn grep immer "success" als Ergebnis ausgibt, funktioniert ja mein If-Statement nicht mehr, oder wie ist das?
"grep -q" liefert keine Ausgabe, sondern als Ergebniscode, ob es was gefunden hat oder nicht.

Code: Alles auswählen

if [ -n "$(grep 'Terminal=true' "$tool")" ]; then
sollte sich also identisch verhalten wie

Code: Alles auswählen

if grep -q 'Terminal=true' "$tool"; then
Ansonsten eine Frage: Soll das ein POSIX-Script sein oder ein Bash-Script? Manche möchten lieber kompatibel zu anderen Shells programmieren, manche hingegen haben keine Lust, umständlichen Code zu basteln und verwenden stattdessen bewußt Bash-Syntax. (Ich zum Beispiel gehöre zu letzteren.)

Ich frage, weil dein Code irgendwie ein Mischmasch aus beidem ist; wenn ich Anmerkungen zu deinem Code geben soll, muß ich wissen in welche Richtung.
Fedora 28 Workstation -- openSUSE Leap 42 / Gnome -- Debian 9 (Qnap TS-109/119) -- OmniOS (HP N54L)

RobertDebiannutzer
Beiträge: 182
Registriert: 16.06.2017 09:52:36

Re: Frage bzgl. Bash-Script (auf dmenu basierender file manager)

Beitrag von RobertDebiannutzer » 30.12.2017 19:06:26

Vielen Dank für Deine Mühe!
Ja, mit grep -q funktioniert es auch, habe es gerade noch einmal separat getestet. Weiß nicht, was ich da vorher gemacht habe...

Bezüglich Deiner Frage ob bash oder POSIX:
Ich weiß nicht recht... Ich habe als Shebang einfach mal #!/bin/bash genommen, weil ich für bash die Manpage habe, wo ich bei Problemen reinschauen kann, und mir es erst einmal einfacher erschien, nicht auf POSIX-Kompatibilität zu achten.

Im Prinzip tendiere ich aber zu Kompatibilität. Könntest mir vielleicht kurz erklären, was sich ändern würde, je nachdem, wie ich mich entscheide?

Ich nehme mal an, wenn es POSIX-kompatibel sein soll, muss die dmenu_cmd-Funktion ersetzt werden und die if-statements müssen überarbeitet werden, richtig?
Wenn es dagegen rein für bash sein soll, würde man vielleicht die vielen if durch case ersetzen?

Bei bash gefallen mir die Möglichkeiten unter dem Kapitel "parameter expansion" in der Manpage sehr gut, das habe ich ja auch schon in meinen file manager eingebaut. Bei Tests mit "time" waren die eingabauten Funktionen auch immer schneller als z.B. sed (wobei sed bei den einfachen Aufgaben, die bei mir zu erledigen sind, schon schneller ist als awk).
Das liegt wahrscheinlich hauptsächlich daran, dass bash ja schon läuft, während sed z.B. erst gestartet werden muss. Insofern ist es wohl immer effizienter, für eine bestimmte shell zu schreiben. Oder ist das Blödsinn bei meinen recht kleinen Aufgaben, weil man den Zeitgewinn von 0,002s oder so eh nicht merkt?

owl102
Beiträge: 2296
Registriert: 16.10.2010 13:05:57
Lizenz eigener Beiträge: GNU Free Documentation License
Wohnort: Timbuktu

Re: Frage bzgl. Bash-Script (auf dmenu basierender file manager)

Beitrag von owl102 » 30.12.2017 19:25:21

RobertDebiannutzer hat geschrieben: ↑ zum Beitrag ↑
30.12.2017 19:06:26
Könntest mir vielleicht kurz erklären, was sich ändern würde, je nachdem, wie ich mich entscheide?
Du müsstest dich entweder auf POSIX beschränken oder könntest auch die vielen Sachen benutzen, die die bash zusätzlich zum POSIX-Standard anbietet.

(Ich persönlich benötige die POSIX-Kompatibilität nicht. Einige Scripte würde ich auch nie in POSIX schreiben wollen.)
Ich nehme mal an, wenn es POSIX-kompatibel sein soll, muss die dmenu_cmd-Funktion ersetzt werden und die if-statements müssen überarbeitet werden, richtig?
Auf die schnelle habe ich nur 2 ifs gefunden, die bash-Syntax sind:

Code: Alles auswählen

	if [[ "$input" = "4"* ]]; then
	elif [[ "$input" = 'q' ]]; then
Da müsste man in POSIX ein "case" für nehmen, weil POSIX keinen Test mit Wildcards in if erlaubt (wohl aber in "case").

Ändere doch einfach das "#!/bin/bash" nach "#!/bin/sh", dann wirst du ja sehen, was nicht mehr funktioniert :mrgreen: Shellcheck sollte anschließend auch die Dinge anmeckern, die nicht POSIX sind.
Wenn es dagegen rein für bash sein soll, würde man vielleicht die vielen if durch case ersetzen?
Das kannst du so oder so machen, egal ob POSIX oder bash.
Oder ist das Blödsinn bei meinen recht kleinen Aufgaben, weil man den Zeitgewinn von 0,002s oder so eh nicht merkt?
Ich persönlich tendiere zu Blödsinn, versuche aber trotzdem build-ins zu verwenden statt externe Anwendungen, wo es problemlos möglich ist.
Fedora 28 Workstation -- openSUSE Leap 42 / Gnome -- Debian 9 (Qnap TS-109/119) -- OmniOS (HP N54L)

RobertDebiannutzer
Beiträge: 182
Registriert: 16.06.2017 09:52:36

Re: Frage bzgl. Bash-Script (auf dmenu basierender file manager)

Beitrag von RobertDebiannutzer » 30.12.2017 23:34:36

Hmja,

shellcheck hat wenig zu meckern, wenn ich es als POSIX-Script testen lasse und funktionieren tut außer echo -e (was auch shellcheck bemängelte) bei kurzem Test auch alles. Das -e bei echo ist bei POSIX offensichtlich auch gar nicht nötig, weil die newlines eh korrekt interpretiert werden.

Also POSIX wäre leicht zu erreichen.

Aber meinst Du, dass ich mein Script wesentlich effizienter machen könnte, wenn ich nur für bash schreiben würde?
Was könnte ich da grob gesagt modifizieren?
Das größte Problem, vor dem ich mich in diesem Fall sehe, ist folgendes:
Beispiel: Ich möchte den Output eines Kommandos verändern. Ich möchte z.B. vor "prefixstring" das "prefix" entfernen. Dann geht das zwar mit der Pattern Substitution "${parameter/pattern/string}" sehr schön, aber "parameter" muss immer eine Variable sein, sodass ich nie Pipes nutzen kann, sondern immer erstmal den Ouptut in eine Variable verpacken muss.
Geht das auch anders?

owl102
Beiträge: 2296
Registriert: 16.10.2010 13:05:57
Lizenz eigener Beiträge: GNU Free Documentation License
Wohnort: Timbuktu

Re: Frage bzgl. Bash-Script (auf dmenu basierender file manager)

Beitrag von owl102 » 31.12.2017 00:47:27

RobertDebiannutzer hat geschrieben: ↑ zum Beitrag ↑
30.12.2017 23:34:36
Das -e bei echo ist bei POSIX offensichtlich auch gar nicht nötig, weil die newlines eh korrekt interpretiert werden.
Nein. :wink: Bezüglich POSIX ist bei echo nur sehr wenig definiert, der Schalter "-e" ist AFAIK nicht Bestandteil von POSIX und die Interpretation von "\n" und ähnlichem auch nicht.

printf ist hingegen bei POSIX gut dokumentiert und daher würde ich bei sowas lieber printf statt echo einsetzen.

Das Problem bei POSIX ist, daß es keine Shell gibt, die nur POSIX kann. Unter Debian ist zum Beispiel die /bin/sh in Wirklichkeit die dash (Beweis: "ls -l /bin/sh"), die neben POSIX auch ein bischen mehr kann. Unter Fedora/RHEL ist übrigens /bin/sh die bash, die ja auch neben POSIX ein bischen mehr kann. Unter RHEL könnte man also "#!/bin/sh" in die erste Zeile schreiben und reichlich bash-Code produzieren, der auf RHEL problemlos funktioniert, aber unter Debian nicht.

Nur weil es funktioniert, heißt das folglich nicht, daß es POSIX ist, und schon gar nicht, daß es auch mit anderen POSIX-kompatiblen Shells funktioniert. Man muß wissen, was der POSIX-Standard hergibt (und was nicht).
Aber meinst Du, dass ich mein Script wesentlich effizienter machen könnte, wenn ich nur für bash schreiben würde?
Dieses Script? Nein, denke ich nicht. Bash kann zum Beispiel Arrays, POSIX nicht. Wenn man also eine Aufgabe hat, die sich mit Arrays elegant lösen läßt, kommt bei bash eine elegantere Lösung heraus als bei POSIX. Usw.
Dann geht das zwar mit der Pattern Substitution "${parameter/pattern/string}" sehr schön, aber "parameter" muss immer eine Variable sein, sodass ich nie Pipes nutzen kann, sondern immer erstmal den Ouptut in eine Variable verpacken muss.
Geht das auch anders?
Ja, zum Beispiel mit sed.
Fedora 28 Workstation -- openSUSE Leap 42 / Gnome -- Debian 9 (Qnap TS-109/119) -- OmniOS (HP N54L)

RobertDebiannutzer
Beiträge: 182
Registriert: 16.06.2017 09:52:36

Re: Frage bzgl. Bash-Script (auf dmenu basierender file manager)

Beitrag von RobertDebiannutzer » 31.12.2017 12:32:19

Hallo,

ich habe jetzt erstmal noch zwei wichtige Probleme behoben, die ich noch entdeckt habe:
1. Prüfen der Zugangsberechtigung bei Ordnern und Dateien vor dem Öffnen
2. Die Ermittlung des Ordners bei einem string wie "drwxr-xr-x 2 robert robert 4.0K Dec 31 12:17 .test test:drei/" (wie er im erweiterten Modus vorkommen könnte) hat mit meiner vorherigen Lösung nicht funktioniert, bei der alles bis zum letzten Leerzeichen gelöscht wurde. Nun lösche ich alles bis zum ersten Doppelpunkt plus drei zustätzliche Zeichen (nämlich die Minuten und das Leerzeichen).

@owl102: Also ich entscheide mich für dieses Script jetzt erstmal für rein bash. Hättest Du dann noch Verbesserungsvorschläge?

Aktuelles Script sieht so aus:

Code: Alles auswählen

#!/bin/bash

# License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
# This is free software; you are free to change and redistribute it.
# There is NO WARRANTY, to the extent permitted by law.

set -e

dmenu_cmd () {
	dmenu -i -l 25
}
apps_path="/home/robert/.local/share/applications/"

while true; do
if [ -n "$show" ]; then echo "$show" | dmenu_cmd > /dev/null; fi
show=''
list="$(echo -e "$(pwd)\n../\n$(LC_ALL="C" ls -1 --group-directories-first -F)" | dmenu_cmd)"
if [ -d "$list" ]; then
	if [ -x "$list" ]; then
		cd "$list"
	else
		echo "$list: Permission denied" | dmenu_cmd > /dev/null
	fi
elif [ -f "$list" ]; then
	if [ -r "$list" ]; then
		type=$(file -b --mime-type "$list")
		tool=$(grep -m 1 "$type" "/home/robert/.config/mimeapps.list" | sed "s@^.*=@$apps_path@" | cut -d ';' -f1)
		if [ ! -r "$tool" ]; then exit; fi
		if grep -q 'Terminal=true' "$tool"; then
			urxvt -e bash -c "$(sed -n '/\[Desktop Entry\]/,/^Exec=/!d;s/Exec=//p' "$tool") $list"
		else
			exec $(sed -n '/\[Desktop Entry\]/,/^Exec=/!d;s/Exec=//p' "$tool") "$list" &
			exit
		fi
	else
		echo "$list: Permission denied" | dmenu_cmd > /dev/null
	fi
else
	if [ "$list" = '+' ]; then
		while true; do
		if [ -n "$show" ]; then echo "$show" | dmenu_cmd > /dev/null; fi
		show=''
		input="$(echo -e "$(pwd)\n../\n$(LC_ALL="C" ls -lAh --group-directories-first -F)" | dmenu_cmd)"
		if [[ "$input" = "4"* ]]; then
			COM="${input#4}"
			if eval "$COM"; then
				continue
			else
				show='An error occurred. Please press Enter.'
				continue
			fi
		elif [[ "$input" = 'q' ]]; then
			continue 2
		else
			list2="${input#*:???}"
			if [ -d "$list2" ]; then
				if [ -x "$list2" ]; then
					cd "$list2"
				else
					echo "$list2: Permission denied" | dmenu_cmd > /dev/null
				fi
			elif [ -f "$list2" ]; then
				if [ -r "$list2" ]; then
					type=$(file -b --mime-type "$list2")
					tool=$(grep -m 1 "$type" "/home/robert/.config/mimeapps.list" | sed "s@^.*=@$apps_path@" | cut -d ';' -f1)
					if [ ! -r "$tool" ]; then exit; fi
					if grep -q 'Terminal=true' "$tool"; then
						urxvt -e bash -c "$(sed -n '/\[Desktop Entry\]/,/^Exec=/!d;s/Exec=//p' "$tool") $list2"
					else
						exec $(sed -n '/\[Desktop Entry\]/,/^Exec=/!d;s/Exec=//p' "$tool") "$list2" &
						exit
					fi
				else
					echo "$list2: Permission denied" | dmenu_cmd > /dev/null
				fi
			else
				show='An error occurred. Please press Enter.'
			fi
		fi
		done
	else
		if eval "$list"; then
			continue
		else
			show='An error occurred. Please press Enter.'
			continue
		fi
	fi
fi
done

RobertDebiannutzer
Beiträge: 182
Registriert: 16.06.2017 09:52:36

Re: Frage bzgl. Bash-Script (auf dmenu basierender file manager)

Beitrag von RobertDebiannutzer » 03.01.2018 16:57:24

Hallo,

ich weiß nicht, ob's jemanden interessiert, aber irgendwie kann ich auch keine alte Version stehen lassen. Jedenfalls hier die aktuelle:

Leider kann ich die beiden blöden evals nicht in Funktionen umwandeln, weil dann bei Befehlen wie "mkdir "test test"" gar nix mehr klappt... Dafür funktionieren jetzt immerhin überhaupt Befehle, die Datei- oder Ordnernamen mit Leerzeichen enthalten. Habe jetzt auch endlich die Verwendung eines Befehls eindeutig gemacht: Wenn vor dem Output von dmenu ein "///" steht, ist es als Befehl zu behandeln, also mit eval auszuführen. Drei "/" hintereinander kann auf jeden Fall in keinem anderen Kontext vorkommen...
Habe auch noch geändert, dass der file manager immer im Hintergrund offen bleibt, wenn eine Anwendung im Terminal geöffnet wird und nach Schließen der letzteren wieder zur Verfügung steht. Nun ist das nur noch im erweiterten Modus der Fall, dafür aber auch bei GUI-Anwendungen.

Wenn jemand noch Verbesserungsvorschläge hat, immer her damit!

Code: Alles auswählen

#!/bin/bash

# License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
# This is free software; you are free to change and redistribute it.
# There is NO WARRANTY, to the extent permitted by law.

set -e

dmenu_cmd () {
	dmenu -i -l 25
}
apps_path="/home/robert/.local/share/applications/"

while true; do
if [ -n "$show" ]; then echo "$show" | dmenu_cmd > /dev/null; fi
unset show
list="$(echo -e "$(pwd)\n../\n$(LC_ALL="C" ls -1 --group-directories-first -F)" | dmenu_cmd)"
if [ -d "$list" ]; then
	if [ -x "$list" ]; then
		cd "$list"
	else
		echo "$list: Permission denied" | dmenu_cmd > /dev/null
	fi
elif [ -f "$list" ]; then
	if [ -r "$list" ]; then
		type=$(file -b --mime-type "$list")
		tool=$(grep -m 1 "$type" "/home/robert/.config/mimeapps.list" | sed "s@^.*=@$apps_path@" | cut -d ';' -f1)
		if [ ! -r "$tool" ]; then exit; fi
		if grep -q 'Terminal=true' "$tool"; then
			urxvt -e bash -c "$(sed -n '/\[Desktop Entry\]/,/^Exec=/!d;s/^Exec=//p' "$tool") $list" &
			exit
		else
			exec $(sed -n '/\[Desktop Entry\]/,/^Exec=/!d;s/^Exec=//p' "$tool") "$list" &
			exit
		fi
	else
		echo "$list: Permission denied" | dmenu_cmd > /dev/null
	fi
else
	if [ "$list" = '///+' ]; then
		while true; do
		if [ -n "$show" ]; then echo "$show" | dmenu_cmd > /dev/null; fi
		unset show
		input="$(echo -e "$(pwd)\n../\n$(LC_ALL="C" ls -lAh --group-directories-first -F)" | dmenu_cmd)"
		case "$input" in
		"///q")
			continue 2
			;;
		"///"*)
			COM="${input#\/\/\/}"
			if eval "$COM"; then
				continue
			else
				show='An error occurred. Please press Enter.'
				continue
			fi
			;;
		*)
			list2="${input#*:???}"
			if [ -d "$list2" ]; then
				if [ -x "$list2" ]; then
					cd "$list2"
				else
					echo "$list2: Permission denied" | dmenu_cmd > /dev/null
				fi
			elif [ -f "$list2" ]; then
				if [ -r "$list2" ]; then
					type=$(file -b --mime-type "$list2")
					tool=$(grep -m 1 "$type" "/home/robert/.config/mimeapps.list" | sed "s@^.*=@$apps_path@" | cut -d ';' -f1)
					if [ ! -r "$tool" ]; then exit; fi
					if grep -q 'Terminal=true' "$tool"; then
						urxvt -e bash -c "$(sed -n '/\[Desktop Entry\]/,/^Exec=/!d;s/^Exec=//p' "$tool") $list2"
					else
						exec $(sed -n '/\[Desktop Entry\]/,/^Exec=/!d;s/^Exec=//p' "$tool") "$list2"
					fi
				else
					echo "$list2: Permission denied" | dmenu_cmd > /dev/null
				fi
			else
				show='An error occurred. Please press Enter.'
			fi
			;;
		esac
		done
	else
		case "$list" in
		"///"*)
			COM2="${list#\/\/\/}"
			if eval "$COM2"; then
				continue
			else
				show='An error occurred. Please press Enter.'
				continue
			fi
			;;
		*)
			show='An error occurred. Please press Enter.'
			continue
			;;
		esac
	fi
fi
done

owl102
Beiträge: 2296
Registriert: 16.10.2010 13:05:57
Lizenz eigener Beiträge: GNU Free Documentation License
Wohnort: Timbuktu

Re: Frage bzgl. Bash-Script (auf dmenu basierender file manager)

Beitrag von owl102 » 03.01.2018 19:10:00

RobertDebiannutzer hat geschrieben: ↑ zum Beitrag ↑
03.01.2018 16:57:24
ich weiß nicht, ob's jemanden interessiert
Ich hoffe ich komme am Wochenende dazu. In der Woche ist's immer schlecht.

Vorab: Ich bin kein Fan von "set -e". Ich verwende es zwar auch, aber nur in hingerotzten Scripten, die ich hin-und-wieder manuell anstoße. Bei "richtigen" Scripten hingegen nicht, denn: "set -e" fängt nicht alle Probleme ab, dafür aber welche, die gar keine sind:

Code: Alles auswählen

#!/bin/bash
set -e
i=0
((i++))
echo "i=$i"
Außerdem würde ich "[..]" meiden und stattdessen ausschließlich "[[..]]" bzw. "((..))" verwenden. Überhaupt neige ich dazu, allem in http://mywiki.wooledge.org/BashGuide zuzustimmen.

Des weiteren verstehe ich die Notwendigkeit der "show"-Konstruktion nicht. Warum nicht einfach stattdessen eine Funktion "show" anbieten, die man aufruft?
Leider kann ich die beiden blöden evals nicht in Funktionen umwandeln
Wie hattest du das versucht?
Fedora 28 Workstation -- openSUSE Leap 42 / Gnome -- Debian 9 (Qnap TS-109/119) -- OmniOS (HP N54L)

RobertDebiannutzer
Beiträge: 182
Registriert: 16.06.2017 09:52:36

Re: Frage bzgl. Bash-Script (auf dmenu basierender file manager)

Beitrag von RobertDebiannutzer » 04.01.2018 13:21:12

owl102 hat geschrieben: ↑ zum Beitrag ↑
03.01.2018 19:10:00
Ich hoffe ich komme am Wochenende dazu. In der Woche ist's immer schlecht.
Ich wollte Dir keinen Vorwurf machen. Ich habe kein Problem damit, wenn das Thema dmenu-Script hier im Forum gerade nicht so auf Interesse stößt, nur dann würde ich halt das Thema hier nicht unbedingt weiter führen. Und schon gar nicht habe ich ein Problem damit, wenn jemand gerade nicht die Zeit findet, hier etwas zu schreiben!
Aber wenn Du mir noch ein paar Tipps geben möchtest, freue ich mich selbstverständlich.

Deine Idee mit der Funktion anstelle der "show-Konstruktion" ist toll! Das habe ich gleich mal umgesetzt und die Gelegenheit genutzt, das auch noch für die Permission-denied Anzeige so zu machen und noch eine weitere Anzeige zu implementieren, wenn für den ermittelten file-type keine Anwendung in "mimeapps.list" gefunden wird.

Die evals habe ich versucht zu ersetzen durch folgende Konstruktion:
COM () {
"${input#\/\/\/}" bzw. ${input#\/\/\/} (also ohne Anführungsstriche)
}
und dann weiter mit "if COM; then" und so weiter.
Aber wenn ich das einzeln im Terminal teste:
$ TEST="$(echo '///mkdir "test test"' | dmenu)" #Nun öffnet sich dmenu, ich kann meinen Eintrag wählen, worauf ihn dmenu nach stdout schreibt, also in die Variable TEST.
$ TESTC () { "${TEST#\/\/\/}";
$ TESTC
bash: mkdir "test test": command not found
oder ohne Anführungszeichen:
$ TESTC () { ${TEST#\/\/\/}; }
$ TESTC
$ ls -la
drwxr-xr-x 2 robert robert 4096 Jan 4 13:04 "test
drwxr-xr-x 2 robert robert 4096 Jan 4 13:04 test"

Das ist nicht schön...

Auf Deinen Vorschlag hin habe ich auch die [] durch [[]] ersetzt. In deinen Link habe ich bezüglich der if-statements auch schon reingelesen. Das ist sehr interessant und ausfürhlich, vielen Dank! Bei tldp.org, wo ich bisher manchmal reingeschaut habe, hatte ich nicht so eine ausführliche Dokumentation gefunden.

Aktuelle Version:

Code: Alles auswählen

#!/bin/bash

# License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
# This is free software; you are free to change and redistribute it.
# There is NO WARRANTY, to the extent permitted by law.

set -e

dmenu_cmd () {
	dmenu -i -l 25
}
show_cmd () {
	echo 'An error occurred. Please press Enter.' | dmenu_cmd > /dev/null
}
perm_cmd () {
	echo "$list: Permission denied" | dmenu_cmd > /dev/null
}
noapp_cmd () {
	echo "There's no app specified for $type in mimeapps.list" | dmenu_cmd > /dev/null
}
apps_path="/home/robert/.local/share/applications/"

while true; do
input="$(echo -e "$(pwd)\n../\n$(LC_ALL="C" ls -1 --group-directories-first -F)" | dmenu_cmd)"
case "$input" in
*"*")
	listtmp="${input#*:???}" && list="${listtmp%?}"
	;;
*)
	list="${input#*:???}"
	;;
esac
if [[ -d "$list" ]]; then
	if [ -x "$list" ]; then
		cd "$list"
	else
		perm_cmd
	fi
elif [[ -f "$list" ]]; then
	if [[ -r "$list" ]]; then
		type=$(file -b --mime-type "$list")
		tool=$(grep -m 1 "$type" "$HOME/.config/mimeapps.list" | sed "s@^.*=@$apps_path@" | cut -d ';' -f1)
		if [[ ! -r "$tool" ]]; then noapp_cmd && continue; fi
		if grep -q 'Terminal=true' "$tool"; then
			urxvt -e bash -c "$(sed -n '/\[Desktop Entry\]/,/^Exec=/!d;s/^Exec=//p' "$tool") $list" &
			exit
		else
			exec $(sed -n '/\[Desktop Entry\]/,/^Exec=/!d;s/^Exec=//p' "$tool") "$list" &
			exit
		fi
	else
		perm_cmd
	fi
else
	case "$list" in
	'///+')
		while true; do
		input="$(echo -e "$(pwd)\n../\n$(LC_ALL="C" ls -lAh --group-directories-first -F)" | dmenu_cmd)"
		case "$input" in
		"///q")
			continue 2
			;;
		"///"*)
			COM="${input#\/\/\/}"
			if eval "$COM"; then
				continue
			else
				show_cmd
				continue
			fi
			;;
		*)
			case "$input" in
			*"*")
				listtmp="${input#*:???}" && list="${listtmp%?}"
				;;
			*)
				list="${input#*:???}"
				;;
			esac
			if [[ -d "$list" ]]; then
				if [[ -x "$list" ]]; then
					cd "$list"
				else
					perm_cmd
				fi
			elif [[ -f "$list" ]]; then
				if [[ -r "$list" ]]; then
					type=$(file -b --mime-type "$list")
					tool=$(grep -m 1 "$type" "/home/robert/.config/mimeapps.list" | sed "s@^.*=@$apps_path@" | cut -d ';' -f1)
					if [[ ! -r "$tool" ]]; then noapp_cmd && continue; fi
					if grep -q 'Terminal=true' "$tool"; then
						urxvt -e bash -c "$(sed -n '/\[Desktop Entry\]/,/^Exec=/!d;s/^Exec=//p' "$tool") $list"
					else
						exec $(sed -n '/\[Desktop Entry\]/,/^Exec=/!d;s/^Exec=//p' "$tool") "$list"
					fi
				else
					perm_cmd
				fi
			else
				show_cmd
			fi
			;;
		esac
		done
		;;
	*)
		case "$list" in
		"///"*)
			COM2="${list#\/\/\/}"
			if eval "$COM2"; then
				continue
			else
				show_cmd
			fi
			;;
		*)
			show_cmd
			;;
		esac
		;;
	esac
fi
done

owl102
Beiträge: 2296
Registriert: 16.10.2010 13:05:57
Lizenz eigener Beiträge: GNU Free Documentation License
Wohnort: Timbuktu

Re: Frage bzgl. Bash-Script (auf dmenu basierender file manager)

Beitrag von owl102 » 11.01.2018 20:46:20

Neue Anmerkungen:

"/home/robert" würde ich durch "$HOME" ersetzen. (Kommt ein paar mal vor)

Code: Alles auswählen

input="$(echo -e "$(pwd)\n../\n$(LC_ALL="C" ls -1 --group-directories-first -F)" | dmenu_cmd)"
würde ich durch

Code: Alles auswählen

input="$(printf '%s\n../\n%s\n' "$(pwd)" "$(LC_ALL="C" ls -1 --group-directories-first -F)" | dmenu_cmd)"
ersetzen.

Hintergrund: "echo -e" ist nicht durch POSIX gedeckt, Da dies ein Bash-Script ist, ist das egal, denn bash kann "echo -e". Ich sehe aber bei mir die Gefahr, daß wenn ich mir sowas erst angewöhne, ich es auch in POSIX-Scripten einsetze. Außerdem kann es sein, daß in $pwd ein Backslash enthalten sein kann, der dann fälschlicherweise interpretiert werden würde. Dieses Problem vermeidet man, indem man $pwd nur als Argument von printf einsetzt und nicht direkt in den Format-String einsetzt. Dito bei $(ls). Insgesamt ist es immer eine gute Idee, bei Zeichenketten, wo man nicht sicher sein kann, was da drin steht, immer über "printf '...%s...' <zeichenkette>" zu gehen.

Code: Alles auswählen

cd "$list"
würde ich durch

Code: Alles auswählen

cd -- "$list"
ersetzen, denn man weiß nicht, ob der Verzeichnisname nicht mit "-" oder "--" anfängt, und das würde dann als Option interpretiert werden. Das "--" verhindert dies. Davon gibt es auch noch mehr Stellen in deinem Script, zum Beispiel

Code: Alles auswählen

type=$(file -b --mime-type -- "$list")

Code: Alles auswählen

if [[ ! -r "$tool" ]]; then noapp_cmd && continue; fi
Ist das wirklich so gemeint, daß wenn noapp_cmd einen Rückgabewert von ungleich 0 hat, das "continue" nicht ausgeführt werden soll? Wenn nicht, dann wäre richtiger:

Code: Alles auswählen

if [[ ! -r "$tool" ]]; then noapp_cmd; continue; fi
Über "set -e" hatte ich ja schon was geschrieben. Ich würde stattdessen lieber

Code: Alles auswählen

type=$(file -b --mime-type -- "$list")
durch

Code: Alles auswählen

if type=$(file -b --mime-type -- "$list"); then ...
usw. ersetzen.

Code: Alles auswählen

grep -q 'Terminal=true' "$tool"
Ich bin jetzt zu faul, die Syntax der Einträge nachzuschauen. Ich hätte eher sowas wie

Code: Alles auswählen

grep -q -i '^[[:blank:]]*terminal=true' -- "$tool"
erwartet, schließlich soll zum Beispiel "XTerminal=true" nicht fälschlicherweise gefunden werden. Außerdem würde ich da ein "--" einsetzen. Und "-i"!?

"type=...; tool=..." kommt mehrfach vor. Ebenso "$(sed -n '/\[Desktop Entry\]/,/^Exec=/!d;s/^Exec=//p' "$tool")". Da würde ich jeweils eine Funktion für nehmen. (Und bei dem sed wieder ein "--" vor "$tool" einbauen.)

Mir fehlen Kommentare, insbesondere mit beispielhaftem Input und Output. Ich müsste daher selber Debugzeilen a la "printf ..." einbauen, um das Script nachvollziehen zu können, da bin ich aber jetzt zu faul zu. :wink:
Fedora 28 Workstation -- openSUSE Leap 42 / Gnome -- Debian 9 (Qnap TS-109/119) -- OmniOS (HP N54L)

RobertDebiannutzer
Beiträge: 182
Registriert: 16.06.2017 09:52:36

Re: Frage bzgl. Bash-Script (auf dmenu basierender file manager)

Beitrag von RobertDebiannutzer » 12.01.2018 14:07:11

Danke, das war sehr hilfreich!

Das mit dem "--" habe ich noch gar nicht gewusst, das ist wirklich nützlich.
Wo sinnvoll, habe ich wie von Dir vorgeschlagen, noch weitere Variablen durch Funktionen ersetzt, jetzt sieht das Script schon bedeutend übersichtlicher aus... Bei der Funktion "TOOL" habe ich noch die drei Schritte durch ein einziges sed-Kommando (+ builtin parameter substitution) ersetzt, was laut time zu einer Geschwindigkeitssteigerung von 0,006s auf 0,002s für das Kommando führt.
Funktionen, die den gleichen Namen wie eine Variable tragen, habe ich zum besseren Verständnis in Großbuchstaben geschrieben, auch wenn ich durch Tests erfahren habe, dass das nicht nötig wäre.
Kommentare zur besseren Nachvollziehbarkeit sind eine sehr gute Idee, auch für mich selber: Durch dieses Verfahren habe ich beim ersten "case $input" zwei völlig überflüssige Variablen gefunden und entfernt.

"set -e" habe ich gestrichen, aber statt Deinem Vorschlag:

Code: Alles auswählen

if type=$(file -b --mime-type -- "$list"); then ...
habe ich mir Folgendes überlegt, das mir eleganter und genauso passend erschien:

Code: Alles auswählen

type="$(TYPE)" || exit
Dieses "|| exit" habe ich einfach überall angehängt, wo es mir sinnvoll schien. Ist das gut so?
Die Konstruktion "||" habe ich auch zum Testen von "eval $COM" und "eval $COM2" anstatt des zuvor verwendeten if verwendet.

zu Deinem Vorschlag:

Code: Alles auswählen

grep -q -i '^[[:blank:]]*terminal=true'
Das "^" ist eine sehr gute Idee, das habe ich ergänzt. Aber wozu ist das [[:blank:]] dann noch gut? Das "-i" ist glaube ich nicht nötig, wenn man die Spezifikationen von freedesktop.org betrachtet: https://standards.freedesktop.org/deskt ... 01s06.html
Ist da eine abweichende Groß-Kleinschreibung erlaubt?

Aktuelle Version:

Code: Alles auswählen

#!/bin/bash

# License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
# This is free software; you are free to change and redistribute it.
# There is NO WARRANTY, to the extent permitted by law.

dmenu_cmd () { dmenu -i -l 25; }

TYPE () { file -b --mime-type -- "$list"; }

TOOL () { sed -n "/^${type//\//\\/}/ {s@^.*=@$apps_path@;s/\;.*//p;q}" -- "$HOME/.config/mimeapps.list"; }
# the parameter substitution replaces the type, for example "text/plain", with "text\/plain", i.e. the slash is escaped.
# Because the given parameter ("/" in this case) begins with a slash, all matches of the given pattern are replaced, i.e.
# "example/text/plain" is replaced with "example\/text\/plain". IMHO, there aren't any mimetypes with two slahes but we
# can't be careful enough, can we?
# old command: tool=$(grep -m 1 "$type" "$HOME/.config/mimeapps.list" | sed "s@^.*=@$apps_path@" | cut -d ';' -f1)

COMPPRE () { sed -n '/\[Desktop Entry\]/,/^Exec=/!d;s/^Exec=//p' -- "$tool"; }

TESTTERM () { grep -q '^Terminal=true' -- "$tool"; }

show_cmd () { echo 'An error occurred. Please press Enter.' | dmenu_cmd > /dev/null; }

perm_cmd () { echo "$list: Permission denied" | dmenu_cmd > /dev/null; }

noapp_cmd () { echo "There's no app specified for $type in mimeapps.list" | dmenu_cmd > /dev/null; }

apps_path="$HOME/.local/share/applications/"

while true; do
input="$(printf '%s\n../\n%s\n' "$(pwd)" "$(LC_ALL="C" ls -1 --group-directories-first -F)" | dmenu_cmd)" || exit
# example: input="Dokumente/" or input="testscript.sh*" or input="///touch "test file"" or input="///rm testscript.sh*"
# or input="///+" to enter the extended view
case "$input" in
*"*")
	list="${listtmp%?}"
# example: list="testscript.sh" or list="///rm testscript.sh" - the asterisk has to be removed
	;;
*)
	list="$input"
# no modifications needed - slash after directory name is allowed
	;;
esac
if [[ -d "$list" ]]; then
	if [ -x "$list" ]; then
		cd -- "$list" || exit
	else
		perm_cmd
	fi
elif [[ -f "$list" ]]; then
	if [[ -r "$list" ]]; then
		type="$(TYPE)" || exit
# example: type="text/plain"
		tool="$(TOOL)" || exit
# example: tool="/home/robert/.local/share/applications/nano.desktop"
		if [[ ! -r "$tool" ]]; then noapp_cmd; continue || exit; fi
		if TESTTERM; then
			urxvt -e bash -c -- "$(COMPPRE) -- $list" &
# COMPPRE searches the command to execute in the given .desktop file
			exit
		else
			exec $(COMPPRE) -- "$list" &
			exit
		fi
	else
		perm_cmd
	fi
else
	case "$list" in
	'///+')
		while true; do
		input="$(printf '%s\n../\n%s\n' "$(pwd)" "$(LC_ALL="C" ls -lAh --group-directories-first -F)" | dmenu_cmd)" || exit
# example: input="drwx------  2 robert robert 4.0K Aug 13 21:19 .aptitude/" or input="-rwxr-xr-x  1 robert robert  204 Jan 10 14:03 testscript.sh*"
# or input="///touch "test file"" or input="///q" to quit the extended view and return to simple view
		case "$input" in
		"///q")
			continue 2 || exit
			;;
		"///"*)
			COM="${input#\/\/\/}"
# if input is a command, we need to remove the three slashes and then execute the command using eval
# example: COM="touch "test file""
			eval "$COM" || show_cmd
			continue || exit
			;;
		*)
			case "$input" in
			*"*")
				listtmp="${input#*:???}" && list="${listtmp%?}"
# we have to remove all information from ls but the file or directory name - again, an asterisk has to be removed as we did above
# example: list=".aptitude/" or list="testscript.sh"
				;;
			*)
				list="${input#*:???}"
# we have to remove all information from ls but the file or directory name
				;;
			esac
			if [[ -d "$list" ]]; then
				if [[ -x "$list" ]]; then
					cd -- "$list" || exit
				else
					perm_cmd
				fi
			elif [[ -f "$list" ]]; then
				if [[ -r "$list" ]]; then
# the same procedure as above:
					type="$(TYPE)" || exit
					tool="$(TOOL)" || exit
					if [[ ! -r "$tool" ]]; then noapp_cmd; continue || exit; fi
					if TESTTERM; then
						urxvt -e bash -c -- "$(COMPPRE) -- $list"
					else
						exec $(COMPPRE) -- "$list"
					fi
				else
					perm_cmd
				fi
			else
				show_cmd
			fi
			;;
		esac
		done
		;;
	*)
		case "$list" in
		"///"*)
			COM2="${list#\/\/\/}"
# if input is a command, we need to remove the three slashes and then execute the command using eval
			eval "$COM2" || show_cmd
			continue || exit
			;;
		*)
			show_cmd
			;;
		esac
		;;
	esac
fi
done

owl102
Beiträge: 2296
Registriert: 16.10.2010 13:05:57
Lizenz eigener Beiträge: GNU Free Documentation License
Wohnort: Timbuktu

Re: Frage bzgl. Bash-Script (auf dmenu basierender file manager)

Beitrag von owl102 » 12.01.2018 16:45:34

RobertDebiannutzer hat geschrieben: ↑ zum Beitrag ↑
12.01.2018 14:07:11
Dieses "|| exit" habe ich einfach überall angehängt, wo es mir sinnvoll schien. Ist das gut so?
Die Frage ist, was du möchtest. Wenn du möchtest, daß sich das Programm bei Problemen einfach beendet, ist das ok so.
Aber wozu ist das [[:blank:]] dann noch gut?
Mit "[[:blank:]]*" würde man auch optional Leerzeichen/Tabs vor dem "Terminal=true" erlauben. Ob das die Syntax der Datei hergibt, weiß ich nicht.
Das "-i" ist glaube ich nicht nötig, wenn man die Spezifikationen von freedesktop.org betrachtet
Habe auch gerade mal nachgeschaut, du hast Recht, sowohl bei "Terminal" als auch bei "true" ist keine abweichende Groß-/Kleinschreibung erlaubt.
Fedora 28 Workstation -- openSUSE Leap 42 / Gnome -- Debian 9 (Qnap TS-109/119) -- OmniOS (HP N54L)

Antworten