È possibile configurare il modo in cui bash completa i nomi delle directory?


8

Vorrei incaricare bash di utilizzare un metodo speciale per eseguire il completamento su determinati nomi di directory. Ad esempio, bash chiamerebbe un mio programma per eseguire il completamento se un percorso inizia con "$$" ed eseguirà il completamento normalmente altrimenti.

Questo è possibile? Come lo implementeresti?

Bounty : Gradirei davvero una risposta a questa domanda. L'obiettivo è consentire ad autojump di completare i percorsi per tutti i comandi quando l'utente li avvia con un determinato prefisso. Ad esempio, quando si copia un file da una directory lontana, è possibile digitare:

cp $$patern + <Tab>

e l'autojump si completerebbe

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

e dovresti solo aggiungere dove vuoi mettere il file. Ovviamente posso usare il commento di ott per aggiungerlo ad alcuni comandi specifici, ma se qualcuno ha un'idea migliore, sarei molto grato.


Vedi la sezione "Completamento programmabile" nella pagina man di bash.

Se voti per chiudere la mia domanda, spiega perché.
Peltier,

2
"complete" supporta "-G pattern" per abbinare $$ $$ all'inizio e "-F func" per chiamare la propria funzione, ma per funzionare ha bisogno di uno o più nomi di comandi.

Perché non usare semplicemente una variabile d'ambiente? Ad esempio: cp $ prefisso / file / path / to / dest /
Xenoactive

@Xenoactive: perché autojump è completamente automatizzato e funziona su più di un percorso. L'uso manuale delle variabili d'ambiente impostate non aiuta. O forse hai un'idea potente che non capisco?
Peltier,

Risposte:


3

È possibile farlo sovrascrivendo l'associazione predefinita per TAB (^ i). Per prima cosa devi sovrascrivere l'associazione TAB, quindi devi creare una funzione che chiama il tuo comando, infine devi prendere l'output da quel comando e aggiornare la variabile che contiene la riga di comando corrente.

Questa funzione prende l'attuale riga di comando e cambia gli ultimi due caratteri 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"
}

Per il tuo esempio probabilmente vorrai cambiare la riga new_argument in modo che assomigli a questo:

  new_argument=$(autojump $argument)

Ora sovrascrivi l'associazione ^ i:

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

Ora prova che funziona:

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

quindi il normale completamento funziona ancora, puoi testare la parte $$ facendo cd $$ ... ecc

Se riscontri problemi, attiva la modalità dettagliata:

$ set -x

Stamperà tutto ciò che la funzione sta facendo.

Ho provato questo su Ubuntu 11 usando bash 4.2.8 (1) -release (impostazione predefinita).


Mi sembra che funzioni solo sul primo parametro del comando e può anche fare cose strane se la scheda viene utilizzata in modo imprevisto (ad esempio dopo un $$$ o dopo il nome del comando), o sbaglio?
harrymc,

Bene, sta passando $ *, quindi "funzionerà" su più del semplice parametro (non conosco affatto l'autojump, quindi non sono sicuro che possa accettare più argomenti). È possibile passare alla fine e inviare solo l'ultimo a autojump oppure utilizzare READLINE_POINT per determinare dove si trova il cursore tra gli argomenti del comando e inviare solo quella "parola" anche a autojump.
polinomio,

La tua soluzione è interessante, ma devi ammettere che assumere il tasto Tab è un po 'estremo. Non è possibile anticipare tutti i casi possibili.
harrymc,

Grazie per la tua risposta, è una buona soluzione alternativa e affronta la parte "per tutti i comandi" della mia domanda. Sono d'accordo con harrymc sul fatto che sia un po 'estremo, però ... Suppongo che se nessuno troverà una soluzione migliore, ci proverò e vedrò se è fattibile.
Peltier,

Anche io sono d'accordo con harrymc, ma stavo cercando di rispondere alla domanda come chiesto. Personalmente lo legherei semplicemente a un altro tasto di controllo come ^ G o qualcosa del genere in modo da poter lasciare la scheda da solo ma utilizzare comunque questa funzionalità.
polinomio,

1

La routine di completamento bash può essere programmata come uno script di shell.

Ecco un esempio di uno script di shell che sostituirà in qualsiasi parametro $$[Tab]con my replacement string, ma solo per il comando specifico mycommande solo se il parametro è esattamente "$$":

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

È necessario eseguire il source dello script per bash tramite source <file-name>(o il comando punto) per avviarlo, quindi:

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

Per farlo funzionare sempre per alcuni o tutti gli utenti, includilo in una delle routine del profilo bash .

Il problema con il completecomando è che funzionerà solo per uno o più nomi di comandi specificati come parametri. Si potrebbe semplicemente dargli l'elenco di tutti i comandi che potrebbero essere utilizzati dagli utenti o in casi disperati espandersi /bin/* /usr/bin/* ~/bin/*.

Testato su CentOS 5.5.

Questo semplice script si basa sulle fonti che ho elencato nella mia altra risposta, quella che è stata eliminata dal moderatore studiohack. Se interessati, chiedigli semplicemente di ripristinarlo.


Grazie per la tua risposta. La mia domanda non riguardava molto da quando ero nuovo, ma era impossibile completare tutti i comandi. Tuttavia, penso che se la soluzione di polinomio non dovesse risultare accettabile, implementerò qualcosa del genere e proverò a scegliere i comandi più comuni.
Peltier,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.