2

I'm learning about bash completion. I'm able to list the content of only current directory. Here is my code:

   _foo()
   {
       local cur prev opts
       COMPREPLY=()
       cur="${COMP_WORDS[COMP_CWORD]}"
       prev="${COMP_WORDS[COMP_CWORD-1]}"

       opts="push pull"
       OUTPUT=" $(ls) "

      case "${prev}" in
          push)
              COMPREPLY=( $(compgen -W "--in --out" -- ${cur}) )
              return 0
              ;;
          --in)
              COMPREPLY=( $(compgen -W "$OUTPUT" -- ${cur}) )
              return 0
              ;;
      esac

        COMPREPLY=($(compgen -W "${opts}" -- ${cur}))
        return 0
  }
  complete -F _foo foo

It's output is:

$ foo push --in[TAB]
file1.txt file2.txt foo  ;; content of pwd

But when I do this:

$ foo push --in ~[TAB]

It's not working. So I want to know how to do bash completion in different directory (not only in pwd)? Thanks.

rishi kant
  • 1,235
  • 1
  • 9
  • 28
  • Oh they are actually not in script. These are just because of Vim editor. And I copied this script from there so line number also copied. – rishi kant Jul 09 '16 at 20:10

1 Answers1

2

You can use -f to match filenames :

#!/bin/bash
_foo()    {
       local cur prev opts
       COMPREPLY=()
       cur="${COMP_WORDS[COMP_CWORD]}"
       prev="${COMP_WORDS[COMP_CWORD-1]}"
       opts="push pull"

       case "${prev}" in
          push)
              COMPREPLY=( $(compgen -W "--in --out" -- ${cur}) )
              return 0
              ;;
          --in)
              COMPREPLY=( $(compgen -f ${cur}) )
              return 0
              ;;
      esac

      COMPREPLY=($(compgen -W "${opts}" -- ${cur}))
      return 0   
}

complete -F _foo foo

However it seems that it doesn't work for ~ alone but $ foo push --in ~/[TAB] works and all other directories This solution wont include slash to look for file in directory : $ foo push --in /etc[TAB] will give foo push --in /etc and not foo push --in /etc/

The following post solves that problem using default mode :
Getting compgen to include slashes on directories when looking for files

default

Use Readline’s default filename completion if the compspec generates no matches.

So you can use :

#!/bin/bash
_foo()
   {
       local cur prev opts
       COMPREPLY=()
       cur="${COMP_WORDS[COMP_CWORD]}"
       prev="${COMP_WORDS[COMP_CWORD-1]}"

       opts="push pull"
       OUTPUT=" $(ls) "

      case "${prev}" in
          push)
              COMPREPLY=( $(compgen -W "--in --out" -- ${cur}) )
              return 0
              ;;
          --in)
              COMPREPLY=()
              return 0
              ;;
          --port)
              COMPREPLY=("")
              return 0
              ;;
      esac

        COMPREPLY=($(compgen -W "${opts}" -- ${cur}))
        return 0
  }
  complete -o default -F _foo foo

Or setting to default mode when you need to like this post : https://unix.stackexchange.com/a/149398/146783

Community
  • 1
  • 1
Bertrand Martel
  • 42,756
  • 16
  • 135
  • 159
  • This is good. But What If I don't want to do anything in particular case. Suppose there is argument --port, And I want to take it from keyboard. It should be like this `$ foo push --port[TAB]` ;; Auto completion should stop, no result. It indicate user to pass --port value from keyboard. But by your answer, It will be `$ foo push --port[TAB]` ;; content of pwd So is there any way to specify that, we don't default result in these cases? – rishi kant Jul 10 '16 at 03:54
  • But that's not working. `$ foo push --in[TAB] bash: compopt: command not found` This is error message which I got. – rishi kant Jul 10 '16 at 04:09
  • Did you source the file in bash_completion.d ? try to add `#!/bin/bash` at the top to be sure it uses the right bash. If your bash is not in `/bin/bash` replace with the right bash location (`which bash`) – Bertrand Martel Jul 10 '16 at 04:24
  • this wont include slash to look for subdirectories if you do that – Bertrand Martel Jul 10 '16 at 04:34
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/116908/discussion-between-rishi-kant-and-bertrand-martel). – rishi kant Jul 10 '16 at 04:41