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

8

Me gustaría indicarle a bash que use un método especial para completar en 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 realizar la finalización normalmente de lo contrario.

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

Recompensa : Realmente agradecería una respuesta a esa pregunta. El objetivo es permitir que el salto automático complete rutas para todos los comandos cuando el usuario los inicia con un determinado prefijo. Entonces, por ejemplo, al copiar un archivo de un directorio remoto, puede escribir:

cp $$patern + <Tab>

y autojump completaría

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

y solo tendría que agregar donde desea colocar el archivo. Por supuesto, puedo usar el comentario de ott para agregarlo a algunos comandos específicos, pero si alguien tiene una mejor idea, estaría muy agradecido.

Peltier
fuente
Consulte la sección "Finalización programable" en la página del manual de bash.
Si vota para cerrar mi pregunta, explique por qué.
Peltier
2
"complete" admite "-G pattern" para que coincida con su $$ al principio y "-F func" para llamar a su propia función, pero necesita uno o más nombres de comando para funcionar.
¿Por qué no solo usar una variable de entorno? Por ejemplo: cp $ prefix / file / path / to / dest /
Xenoactive
@Xenoactive: porque el salto automático está totalmente automatizado y funciona en más de una ruta. Usar variables de entorno establecidas manualmente no ayuda. ¿O tal vez tienes una idea poderosa que no entiendo?
Peltier

Respuestas:

3

Puede hacer esto anulando el enlace predeterminado para TAB (^ i). Primero debe anular el enlace TAB, luego debe crear una función que llame a su comando, por último, debe tomar la salida 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

para que la finalización normal siga funcionando, puede 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 bash 4.2.8 (1) -release (el valor predeterminado).

polinomio
fuente
Me parece que esto funciona solo en el primer parámetro del comando, y también puede hacer cosas extrañas si la pestaña se usa de manera inesperada (por ejemplo, después de un $$$ o después del nombre del comando), ¿o me equivoco?
harrymc
Bueno, está pasando $ *, por lo que 'funcionará' en algo más que el primer parámetro (no sé el salto automático en absoluto, así que no estoy seguro de si puede tomar múltiples argumentos). Puede pasar al final y solo enviar el último al salto automático, o usar READLINE_POINT para determinar dónde está el cursor entre los argumentos del comando y enviar solo esa 'palabra' al salto automático también.
polinomio
Su solución es interesante, pero debe admitir que asumir la tecla tab es un poco extremo. No hay forma de anticipar todos los casos posibles.
harrymc
Gracias por su respuesta, esa es una buena solución alternativa, y aborda la parte "para todos los comandos" de mi pregunta. Sin embargo, estoy de acuerdo con harrymc en que es un poco extremo ... Supongo que si a nadie se le ocurre una solución mejor, lo intentaré y veré si es viable.
Peltier
Sí, también estoy de acuerdo con harrymc, pero estaba tratando de responder la pregunta tal como se la hizo. Personalmente, simplemente vincularía esto a otra tecla de control como ^ G o algo así podría dejar la pestaña sola pero aún usar esta funcionalidad.
polinomio
1

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

Aquí hay un ejemplo de un script de shell que reemplazará en 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 source <file-name>iniciar el script para bash via (o el comando dot) para comenzar 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 una de las rutinas de perfil de bash .

El problema con el completecomando es que solo funcionará 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 posiblemente podrían ser utilizados por los usuarios, o en casos desesperados expandirse /bin/* /usr/bin/* ~/bin/*.

Probado en CentOS 5.5.

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

harrymc
fuente
Gracias por tu respuesta. Mi pregunta no era realmente sobre eso, ya que sabía que era posible, pero no completará todos los comandos. Sin embargo, creo que si la solución del polinomio no resulta aceptable, implementaré algo así e intentaré apuntar a los comandos más comunes.
Peltier