Instantly share code, notes, and snippets.
-
Star
(0)
0
You must be signed in to star a gist -
Fork
(0)
0
You must be signed in to fork a gist
-
Save vain/824089 to your computer and use it in GitHub Desktop.
Bash-Menü-Beispiel für Nobuddy
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# Mit den Cursor-Tasten bedienbares Menü. | |
# Hilfsfunktion: Ist ein Item im Array enthalten? | |
# Siehe auch: | |
# http://forum.ubuntuusers.de/topic/contains-mit-bash-implementieren/ | |
contains() | |
{ | |
(( $# > 1 )) && ( [[ "$1" == "$2" ]] || contains "$1" "${@:3}" ) | |
} | |
# Hilfsfunktion: Entferne ein Item aus dem Array. | |
remove() | |
{ | |
key=$1 | |
shift | |
# Iteriere über alle Einträge in "$@" und gib nur die aus, die nicht | |
# mit dem Key übereinstimmen. Diese Variante funktioniert folglich | |
# nicht, falls die Einträge in "$@" Zeilenumbrüche enthalten (da | |
# dies durch die Ausgabe mit "echo" nicht mehr erkennbar ist). Für | |
# diesen Zweck hier reicht es jedoch. | |
for arg | |
do | |
[[ "$arg" != "$key" ]] && echo "$arg" | |
done | |
} | |
# Hilfsfunktion, die nur das Menü einmal zeichnet. | |
draw_menu() | |
{ | |
# Aktuell fokussierter Punkt. | |
cur=$1 | |
shift | |
# Anzahl der selektierten Punkte. | |
numsel=$1 | |
shift | |
# Kopiere nun $numsel viele Punkte in das Array $sel. Danach | |
# befinden sich in "$@" nur noch die auswählbaren Menüpunkte. | |
sel=() | |
for (( i = 0; i < numsel; i++ )) | |
do | |
sel+=($1) | |
shift | |
done | |
# Gib das Menü aus. | |
i=0 | |
for arg | |
do | |
# Ist dies der fokussierte Eintrag? Zeige dies mit einem | |
# "Cursor" an. | |
(( i == cur )) && echo -n '>' || echo -n ' ' | |
# Ist dieser Eintrag augewählt? Markiere ihn mit einem Stern. | |
contains $i "${sel[@]}" && echo -n '* ' || echo -n ' ' | |
# Menüpunkt selbst. | |
echo "$arg" | |
((i++)) | |
done | |
} | |
# Hilfsfunktion: Cursorbewegung. | |
cursor_relative() | |
{ | |
# Schreibe "cuu1" $2-mal auf's Terminal. Siehe "man terminfo" zwecks | |
# der "capnames", die man tput mitgeben kann. | |
for (( i = 0; i < $2; i++ )) | |
do | |
( [[ "$1" == up ]] && tput cuu1 || tput cud1 ) >/dev/tty | |
done | |
} | |
# Bash-Menu. | |
bmenu() | |
{ | |
# Sichtbarkeit des Cursors ausschalten. | |
tput civis >/dev/tty | |
# Bei "Beendigung" den Cursor wieder sichtbar machen. Da diese | |
# Funktion in einer Subshell ausgeführt werden soll, bedeutet | |
# "Beendigung" das Ende dieser Subshell. Folglich wird der Cursor | |
# effektiv dann wieder sichtbar, wenn diese Funktion hier endet (sei | |
# es auf regulärem Wege oder durch Abbruch/Fehler). Im Zweifel wird | |
# der Cursor erst ganz am Ende des Skriptes wieder sichtbar. Deshalb | |
# nach Möglichkeit auf solche Spielereien verzichten. | |
trap 'tput cnorm >/dev/tty' 0 | |
# Am Anfang: Cursor auf erstem Punkt. | |
cur=0 | |
# Am Anfang nichts ausgewählt. Die ausgewählten Items werden in | |
# diesem Array gespeichert. | |
sel=() | |
# Zeichne das initiale Menü direkt auf's Terminal. | |
draw_menu $cur "${#sel[@]}" "${sel[@]}" "$@" >/dev/tty | |
# Cursor zurücksetzen. | |
cursor_relative up $# | |
# Lies in dieser Schleife immer nur ein Zeichen von stdin. | |
while read -sN1 char | |
do | |
# Wenn das erste Zeichen, das du hier gesehen hast, das | |
# Escape-Zeichen war, dann lies noch zwei weitere Zeichen ein. | |
# So können die Cursor-Tasten abgefragt werden. | |
if [[ "$char" == $'\e' ]] | |
then | |
read -sN2; char="$char$REPLY" | |
fi | |
case "$char" in | |
j|$'\e[B') | |
# Auswahl des nächsten Punktes. | |
((cur++)) | |
;; | |
k|$'\e[A') | |
# Auswahl des vorigen Punktes. | |
((cur--)) | |
;; | |
q|'') | |
# Ausgabe der Auswahl, Cursor ans *Ende* des Menüs und | |
# Schluss. | |
echo "${sel[@]}" | |
cursor_relative down $# | |
return | |
;; | |
s) | |
# Füge aktuelles Item der Auswahl hinzu falls noch | |
# nicht enthalten. | |
if ! contains $cur "${sel[@]}" | |
then | |
sel+=($cur) | |
fi | |
;; | |
d) | |
# Entferne aktuellen Punkt aus der Auswahl. | |
sel=($(remove $cur "${sel[@]}")) | |
;; | |
esac | |
# $cur auf gültigen Bereich beschränken. | |
(( cur >= $# )) && cur=$(($# - 1)) | |
(( cur < 0 )) && cur=0 | |
# Aktualisiere die Menüansicht und setze den Cursor wieder | |
# zurück. | |
draw_menu $cur "${#sel[@]}" "${sel[@]}" "$@" >/dev/tty | |
cursor_relative up $# | |
done | |
} | |
# Definition der verfügbaren Optionen in einem Array: | |
options=( | |
"Option 1" | |
"noch eine" | |
"An IPv4 address space walks into a bar ..." | |
"... and says: ..." | |
"... a strong CIDR please, I am exhausted." | |
) | |
# Testaufruf (Ergebnis wieder ein Array): | |
sel=($(bmenu "${options[@]}")) | |
# Paar Infos zur Auswahl und Ausgabe der markierten Elemente: | |
echo "Du hast ${#sel[@]} Einträge ausgewählt: ${sel[@]}" | |
for (( i = 0; i < "${#options[@]}"; i++ )) | |
do | |
contains $i "${sel[@]}" && echo -e "\t> ${options[$i]}" | |
done |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment