¿Es posible configurar la forma en que bash completa los nombres de los directorios?

¿Es posible configurar la forma en que bash completa los nombres de los directorios?

Me gustaría indicarle a bash que use un método especial para completar ciertos nombres de directorio. Por ejemplo, bash llamaría a un programa mío para realizar la finalización si una ruta comienza con "$$" y, en caso contrario, realizaría la finalización normalmente.

¿Es esto posible? ¿Cómo lo implementarías?

Generosidad: Realmente agradecería una respuesta a esa pregunta. El objetivo es permitirsalto automáticopara completar las rutas de todos los comandos cuando el usuario los inicia con un prefijo determinado. Entonces, por ejemplo, al copiar un archivo desde un directorio lejano, puede escribir:

cp $$patern + <Tab>

y el autojump se completaría

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

y solo tendrías que agregar dónde quieres poner el archivo. Por supuesto que puedo usar el comentario de Ott para agregarlo a algunos comandos específicos, pero si alguien tiene una idea mejor, estaría muy agradecido.

Respuesta1

Puede hacerlo anulando el enlace predeterminado para TAB(^i). Primero debe anular el enlace TAB, luego debe crear una función que llame a su comando y, por último, debe tomar el resultado de ese comando y actualizar la variable que contiene la línea de comando actual.

Esta función toma la línea de comando actual y cambia los dos últimos caracteres a '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"
}

Para su ejemplo, probablemente desee cambiar la línea new_argument para que se vea así:

  new_argument=$(autojump $argument)

Ahora anule el enlace ^i:

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

Ahora prueba que funciona:

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

por lo que la finalización normal todavía funciona, puedes probar la parte $$ haciendo cd $$... etc.

Si tiene problemas, active el modo detallado:

$ set -x

Imprimirá todo lo que está haciendo la función.

Probé esto en Ubuntu 11 usando la versión bash 4.2.8(1) (la predeterminada).

Respuesta2

La rutina de finalización de bash se puede programar como un script de shell.

A continuación se muestra un ejemplo de un script de shell que reemplazará cualquier parámetro $$[Tab]por my replacement string, pero solo para el comando específico mycommandy solo si el parámetro es exactamente "$$":

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

Debe obtener el script a través del cual ejecutar source <file-name>(o el comando punto) para que comience a funcionar y luego:

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

Para que siempre funcione para algunos o todos los usuarios, inclúyalo en uno de losrutinas de perfil bash.

El problema con el completecomando es que funcionará solo para uno o más nombres de comandos, que se especifican como parámetros. Uno podría simplemente darle la lista de todos los comandos que los usuarios podrían usar o, en casos desesperados, expandirla /bin/* /usr/bin/* ~/bin/*.

Probado en CentOS 5.5.

Este script simple se basa en las fuentes que enumeré en mi otra respuesta, la que fue eliminada por el moderador studiohack. Si está interesado, pídale que lo recupere.

información relacionada