Ist es möglich zu konfigurieren, wie bash Verzeichnisnamen vervollständigt?


8

Ich möchte bash anweisen, eine spezielle Methode zu verwenden, um bestimmte Verzeichnisnamen zu vervollständigen. Zum Beispiel würde bash ein Programm von mir aufrufen, um die Fertigstellung durchzuführen, wenn ein Pfad mit "$$" beginnt, und ansonsten die Fertigstellung normal durchführen.

Ist das überhaupt möglich? Wie würden Sie es implementieren?

Bounty : Ich würde mich sehr über eine Antwort auf diese Frage freuen. Ziel ist es, dem automatischen Sprung zu ermöglichen , Pfade für alle Befehle zu vervollständigen, wenn der Benutzer sie mit einem bestimmten Präfix startet. Wenn Sie beispielsweise eine Datei aus einem entfernten Verzeichnis kopieren, können Sie Folgendes eingeben:

cp $$patern + <Tab>

und Autojump würde abgeschlossen

cp /home/user/CompliCatedDireCTOry/long/path/bla/bla

und Sie müssten nur hinzufügen, wo Sie die Datei ablegen möchten. Natürlich kann ich den Kommentar von ott verwenden, um ihn einigen spezifischen Befehlen hinzuzufügen, aber wenn jemand eine bessere Idee hat, wäre ich sehr dankbar.


Siehe den Abschnitt "Programmierbare Vervollständigung" in der Bash-Manpage.

Wenn Sie abstimmen, um meine Frage zu schließen, erklären Sie bitte warum.
Peltier

2
"complete" unterstützt "-G pattern", um mit Ihrem $$ an den Anfang übereinzustimmen, und "-F func", um Ihre eigene Funktion aufzurufen, benötigt jedoch einen oder mehrere Befehlsnamen, um zu funktionieren.

Warum nicht einfach eine Umgebungsvariable verwenden? Zum Beispiel: cp $ Präfix / Datei / Pfad / zu / Ziel /
Xenoactive

@Xenoactive: weil der automatische Sprung vollautomatisch ist und auf mehr als einem Pfad funktioniert. Die Verwendung manuell festgelegter Umgebungsvariablen hilft nicht. Oder haben Sie eine starke Idee, die ich nicht verstehe?
Peltier

Antworten:


3

Sie können dies tun, indem Sie die Standardbindung für TAB (^ i) überschreiben. Zuerst müssen Sie die TAB-Bindung überschreiben, dann müssen Sie eine Funktion erstellen, die Ihren Befehl aufruft. Zuletzt müssen Sie die Ausgabe dieses Befehls übernehmen und die Variable aktualisieren, die die aktuelle Befehlszeile enthält.

Diese Funktion übernimmt die aktuelle Befehlszeile und ändert die letzten beiden Zeichen in 'huugs'.

function my_awesome_tab_completion_function () {
  set -- $READLINE_LINE
  command="$1"
  shift
  argument="$*"
  argument_length=$(echo -n $argument | wc -c)
  if echo $argument | grep '^$$' >/dev/null 2>&1; then
    new_argument=$(echo $argument | sed 's/..$/huugs/') # put your autojump here
  else
    new_argument=$(compgen -d $argument)
  fi
  new_argument_length=$(echo -n $new_argument | wc -c)
  READLINE_POINT=$(( $new_argument_length - $argument_length + $READLINE_POINT ))
  READLINE_LINE="$command $new_argument"
}

In Ihrem Beispiel möchten Sie wahrscheinlich die Zeile new_argument so ändern, dass sie folgendermaßen aussieht:

  new_argument=$(autojump $argument)

Überschreiben Sie nun die ^ i-Bindung:

$ bind -x '"\C-i"':'my_awesome_tab_completion_function'

Testen Sie jetzt, ob es funktioniert:

$ cd /ro<TAB>
changes my command to:
$ cd /root

Damit die normale Fertigstellung weiterhin funktioniert, können Sie den $$ -Teil testen, indem Sie cd $$ ... usw. ausführen

Wenn Sie auf Probleme stoßen, aktivieren Sie den ausführlichen Modus:

$ set -x

Es wird alles ausgedruckt, was die Funktion tut.

Ich habe dies unter Ubuntu 11 mit bash 4.2.8 (1) -release (Standardeinstellung) getestet.


Es scheint mir, dass dies nur mit dem ersten Parameter des Befehls funktioniert und auch seltsame Dinge tun kann, wenn die Registerkarte auf unerwartete Weise verwendet wird (zum Beispiel nach einem $$$ oder nach dem Befehlsnamen), oder irre ich mich?
Harrymc

Nun, es übergibt $ *, so dass es bei mehr als nur dem ersten Parameter 'funktioniert' (ich kenne Autojump überhaupt nicht, daher bin ich mir nicht sicher, ob es mehrere Argumente annehmen kann). Sie können zum Ende wechseln und nur den letzten an den automatischen Sprung senden oder mit READLINE_POINT bestimmen, wo sich der Cursor unter den Befehlsargumenten befindet, und nur dieses 'Wort' auch an den automatischen Sprung senden.
Polynom

Ihre Lösung ist interessant, aber Sie müssen zugeben, dass die Übernahme der Tabulatortaste etwas extrem ist. Es gibt keine Möglichkeit, alle möglichen Fälle zu antizipieren.
Harrymc

Vielen Dank für Ihre Antwort, das ist eine nette alternative Lösung, die den Teil "für alle Befehle" meiner Frage anspricht. Ich stimme harrymc zu, dass es ein bisschen extrem ist ... Ich denke, wenn niemand eine bessere Lösung findet, werde ich es versuchen und sehen, ob es machbar ist.
Peltier

Ja, ich stimme auch harrymc zu, habe aber versucht, die gestellte Frage zu beantworten. Persönlich würde ich dies einfach an einen anderen Steuerschlüssel wie ^ G oder etwas anderes binden, damit ich die Registerkarte in Ruhe lassen und diese Funktionalität trotzdem nutzen kann.
Polynom

1

Die Bash-Abschlussroutine kann als Shell-Skript programmiert werden.

Hier ist ein Beispiel für ein Shell-Skript, das in jedem Parameter $$[Tab]durch ersetzt wird my replacement string, jedoch nur für den spezifischen Befehl mycommandund nur, wenn der Parameter genau "$$" ist:

_mycomplete()
{
        if [ ${COMP_WORDS[COMP_CWORD]} == \$\$ ]
        then
                COMPREPLY='my replacement string'
        fi
}
complete -o default -o bashdefault -F _mycomplete mycommand

Sie müssen das Skript als Quelle source <file-name>(oder den Punktbefehl) verwenden, um es zu starten, und dann:

mycommand $$[Tab] -> mycommand my replacement string
mycommand $$$[Tab] -> mycommand $$$ (beep)
mycommand whatever[Tab] -> (will complete "whatever" in the normal bash manner)

Fügen Sie dies in eine der Bash-Profilroutinen ein, damit es für einige oder alle Benutzer immer funktioniert .

Das Problem mit dem completeBefehl ist, dass er nur für einen oder mehrere Namen von Befehlen funktioniert, die als Parameter angegeben werden. Man könnte ihm einfach die Liste aller Befehle geben, die möglicherweise von den Benutzern verwendet werden könnten, oder in verzweifelten Fällen erweitern /bin/* /usr/bin/* ~/bin/*.

Getestet unter CentOS 5.5.

Dieses einfache Skript basiert auf den Quellen, die ich in meiner anderen Antwort aufgeführt habe - derjenigen, die vom Moderator studiohack gelöscht wurde. Wenn Sie interessiert sind, bitten Sie ihn einfach, es wiederherzustellen.


Danke für deine Antwort. Meine Frage war nicht wirklich danach, da ich neu war, war es möglich, aber es werden nicht alle Befehle ausgeführt. Ich denke jedoch, dass ich, wenn sich die Lösung von Polynom nicht als akzeptabel herausstellt, so etwas implementieren und versuchen werde, auf die häufigsten Befehle abzuzielen.
Peltier
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.