linux - Is it possible to configure the way bash completes directory names?

05
2013-12
  • Peltier

    I'd like to instruct bash to use a special method to perform completion on certain directory names. For example, bash would call a program of mine to perform completion if a path starts with "$$", and perform completion normally otherwise.

    Is this at all possible? How would you implement it?

    Bounty: I'd really appreciate an answer to that question. The goal is to allow autojump to complete paths for all commands when the user starts them with a certain prefix. So for example when copying a file from a far directory, you could type:

    cp $$patern + <Tab>
    

    and autojump would complete

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

    and you would just have to add where you want to put the file. Of course I can use ott's comment to add it to a few specific commands, but if anyone has a better idea, I'd be very grateful.

  • Answers
  • polynomial

    You can do this by overriding the default binding for TAB(^i). First you need to override the TAB binding, then you need to build a function that calls your command, lastly you need to take the output from that command and update the variable that contains the current command line.

    This function takes the current command line and changes the last two characters to '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"
    }
    

    For your example you'd probably want to change the new_argument line to look like this:

      new_argument=$(autojump $argument)
    

    Now override the ^i binding:

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

    Now test that it works:

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

    so normal completion still works, you can test the $$ part by doing cd $$... etc

    If you run into issues turn on verbose mode:

    $ set -x
    

    It will print out everything the function is doing.

    I tested this on Ubuntu 11 using bash 4.2.8(1)-release (the default).

  • harrymc

    This may be a good tutorial to look at, http://www.debian-administration.org/articles/317


  • Related Question

    osx - Case insensitive tab completion in Bash
  • Jeffrey Aylesworth

    Is there any way to make Bash tab complete case insensitively?

    $ bash --version
    GNU bash, version 3.2.48(1)-release (x86_64-apple-darwin10.0)
    Copyright (C) 2007 Free Software Foundation, Inc.
    

    I am using Mac OS X 10.6


  • Related Answers
  • John T

    You should be able to use:

    set completion-ignore-case on

    add it to /etc/inputrc.

  • Lri

    Building on @ClayBridges' comment: To make the setting persistent, as an alternative to editing ~/.inputrc or /etc/inputrc, you can add

    bind "set completion-ignore-case on"
    

    to a shell profile file such as ~/.bash_profile.

    Note that such commands in your profile take precedence over any defined in either /etc/inputrc or ~/.inputrc.

    (A related command that makes completion of file and directory names easier is:

    bind "set show-all-if-ambiguous on"
    

    This makes it unnecessary to press Tab twice when there is more than one match.)