Ich spiele mit einem Skript, das unter anderem eine Auswahlliste auflistet. Wie in:
1) Punkt 1 # (hervorgehoben) 2) Punkt 2 3) Punkt 3 # (ausgewählt) 4) Punkt 4
- Wenn der Benutzer die
down-arrow
nächsten Elemente drückt , wird dies hervorgehoben - Wenn der Benutzer auf
up-arrow
vorherige Elemente drückt , wird dies hervorgehoben - usw.
- Wenn Benutzer drücken
tab
Element ausgewählt ist - Wenn der Benutzer drückt, werden
shift+tab
alle Elemente ausgewählt / abgewählt - Wenn der Benutzer drückt, werden
ctrl+a
alle Elemente ausgewählt - ...
Dies funktioniert ab dem aktuellen Gebrauch einwandfrei. Dies ist mein persönlicher Gebrauch, bei dem Eingaben durch mein eigenes Setup gefiltert werden.
Die Frage ist, wie dies über verschiedene Terminals hinweg zuverlässig gemacht werden kann.
Ich benutze eine etwas hackige Lösung, um Eingaben zu lesen:
while read -rsn1 k # Read one key (first byte in key press)
do
case "$k" in
[[:graph:]])
# Normal input handling
;;
$'\x09') # TAB
# Routine for selecting current item
;;
$'\x7f') # Back-Space
# Routine for back-space
;;
$'\x01') # Ctrl+A
# Routine for ctrl+a
;;
...
$'\x1b') # ESC
read -rsn1 k
[ "$k" == "" ] && return # Esc-Key
[ "$k" == "[" ] && read -rsn1 k
[ "$k" == "O" ] && read -rsn1 k
case "$k" in
A) # Up
# Routine for handling arrow-up-key
;;
B) # Down
# Routine for handling arrow-down-key
;;
...
esac
read -rsn4 -t .1 # Try to flush out other sequences ...
esac
done
Und so weiter.
Wie bereits erwähnt, stellt sich die Frage, wie dies über verschiedene Terminals hinweg zuverlässig gemacht werden kann: dh welche Byte-Sequenzen einen bestimmten Schlüssel definieren. Ist es überhaupt in Bash machbar?
Ein Gedanke war, entweder tput
oder infocmp
und nach dem Ergebnis zu filtern. Ich bin jedoch in einem Haken als beides tput
und infocmp
unterscheide mich von dem, was ich tatsächlich lese, wenn ich tatsächlich Tasten drücke . Gleiches gilt zum Beispiel für C over Bash.
for t in $(find /lib/terminfo -type f -printf "%f\n"); {
printf "%s\n" "$t:";
infocmp -L1 $t | grep -E 'key_(left|right|up|down|home|end)';
}
Ertragssequenzen werden wie zum Beispiel definiert gelesen linux
, aber nicht xterm
, was durch festgelegt wird TERM
.
ZB Pfeil links:
tput
/infocmp
:\x1 O D
read
::\x1 [ D
Was vermisse ich?
dialog
Varianten oder eine Sprache mit angemessenerncurses
Unterstützung (Perl oder Python, wenn Sie sich an "Skriptsprachen" halten möchten).zsh
die integrierte Curses-Unterstützung (im zsh / curses-Modul) zusätzlich zur grundlegenden Terminfo-Abfrage mit demechoti
integrierten und$terminfo
assoziativen Array unterstützt wird.Antworten:
Was Sie vermissen, ist, dass die meisten Terminalbeschreibungen (
linux
die hier aufgrund der weit verbreiteten Verwendung von fest codierten Zeichenfolgen in der Minderheit sind.inputrc
) den Anwendungsmodus für Spezialschlüssel verwenden. Dadurch werden die Cursortasten wie gezeigt angezeigttput
undinfocmp
unterscheiden sich von dem, was Ihr (nicht initialisiertes) Terminal sendet. Fluchanwendungen initialisieren immer das Terminal, und die Terminaldatenbank wird zu diesem Zweck verwendet.dialog
hat seine Verwendung, geht aber nicht direkt auf diese Frage ein. Auf der anderen Seite ist es umständlich (technisch machbar , selten getan ) eine Bash-only Lösung. Im Allgemeinen verwenden wir dazu andere Sprachen.Das Problem beim Lesen von Sonderschlüsseln besteht darin, dass es sich häufig um mehrere Bytes handelt, einschließlich umständlicher Zeichen wie escapeund ~. Sie können dies mit bash tun , aber dann müssen Sie das Problem lösen, tragbar zu bestimmen, um welchen speziellen Schlüssel es sich handelt.
dialog
Beide übernehmen die Eingabe von Sondertasten und übernehmen (vorübergehend) Ihre Anzeige. Wenn Sie wirklich ein einfaches Befehlszeilenprogramm möchten, ist dies nicht der Falldialog
.Hier ist ein einfaches Programm in C, das einen speziellen Schlüssel liest und ihn in druckbarer (und tragbarer) Form druckt :
Angenommen, dies
tgetch
würde aufgerufen , würden Sie es in Ihrem Skript folgendermaßen verwenden:Weiterführende Literatur:
dialog
- Skriptgesteuerte Fluch-Widgets (Anwendung und Bibliothek)quelle
inputrc
war in der Tat der Schuldige, den ich suchte. Muss es mir noch etwas ansehen. Ich habe überlegt, Python oder C zu verwenden, aber es macht Spaß, sich auch als Bash-Skript zu hacken. Ich habe auch versucht, einen Blick auf die Quelle von ncurses zu werfen, um zu sehen, ob ich die benötigten Teile extrahieren kann - aber nach einiger Zeit habe ich die Quelle auf Eis gelassen. Das "Projekt" begann als einfacher Befehl, wurde dann zu einem einfachen interaktiven Skript und wurde dann erneut erweitert. Irgendwo auf dem Weg hätte ich eine andere Sprache/usr/share/doc/readline-common/inputrc.arrows
. Da ich bereits eine generische "read_key" -Funktion habe, die ich im gesamten Skript verwende, hoffte ich, dass es eine einfachere Möglichkeit gibt, die Sequenzen (im Skript) aus dem zu definieren, was tatsächlich angezeigt wird, wenn eine Taste gedrückt wird. Dh ähnlich wie beim Extrahieren von Definitionen ausinfocmp
. Aber raten Sie nicht und müssen Sie es entweder so lassen wie es ist oder in eine andere Sprache wechseln. Ein Kompromiss könnte natürlich darin bestehen, Ihr nettes C-Snippet zu verwenden. Aber dann kann ich das Ganze stattdessen in C schreiben. (Entschuldigung für das Oversharing.)-lncurses
usw. weggelassenHaben Sie versucht, zu verwenden
dialog
? Es wird standardmäßig mit den meisten Linux-Distributionen geliefert und kann alle Arten von textbasierten Dialogen erstellen, einschließlich Checklisten.Zum Beispiel:
Sie werden so etwas bekommen:
Und die Ausgabe wird sein:
(oder welche Elemente Sie ausgewählt haben).
man dialog
Sie erhalten Informationen zu den anderen Arten von Dialogen, die Sie erstellen können, und zum Anpassen des Erscheinungsbilds.quelle
Curses
,DBI
undDBD::SQLite
Module. oder ihre Python-Äquivalente.