complete -o filenames incorrectly adds slashes after directory names

Bug #1439851 reported by hakon
6
This bug affects 1 person
Affects Status Importance Assigned to Milestone
bash-completion (Ubuntu)
New
Undecided
Unassigned

Bug Description

I have a Bash application where I need to complete filenames and directory names that exist in another directory relative to the current directory. In the completion list shown in the terminal after I press TAB, I would like to see directory names with a slash after the name, and filenames with no slash after. This will help the user to distinguish between directory names and filenames.

As I understand it, there are two ways to achieve this:

 a) either use 'complete -o nospace', or
 b) use 'complete -o filenames -o nospace'

For option a), there is a problem as soon as the depth of the path exceeds 1. For example: If I have directories
  - a/b/c
  - a/b/d

I will, after pressing TAB in the terminal window get

$ cmd a/
b/c b/d

so the completion list will be 'b/c', 'b/d' instead of the less verbose 'c', 'd' (which is also desired, and also how 'complete -o filenames' works..)

For option b) , the problem is that 'complete -o filenames' will add slashes after completion words that exist as directory names in the current directory. This is of course, correct if you try to complete names in the current directory, but if the completion words are taken from another directory, this can lead to either multiple slashes (two slashes) after directory names, or to filenames with trailing slashes ( a filename should of course not have a trailing slash after it).

Here is an example, that I hope will illustrate the problems:

First generate some dummy directories and files:

$ mkdir a
$ touch b
$ mkdir c
$ mkdir dir1
$ touch dir1/a
$ mkdir dir1/b
$ mkdir dir1/c
$ mkdir dir1/b/c
$ mkdir dir1/b/d

Then consider the following completion setup:

$ cat setup

_my_test1() {
    local cur comp_dir
    cur="${COMP_WORDS[$COMP_CWORD]}"
    comp_dir="$PWD"
    COMPREPLY=( $( cd "$comp_dir"; compgen -f "$cur" ) )
}
complete -o filenames -o nospace -F _my_test1 test1

_my_test2() {
    local cur comp_dir
    cur="${COMP_WORDS[$COMP_CWORD]}"
    comp_dir="$PWD/dir1"
    COMPREPLY=( $( cd "$comp_dir"; compgen -f "$cur" ) )
}
complete -o filenames -o nospace -F _my_test2 test2a
complete -S '/' -o nospace -F _my_test2 test2b

_my_test3() {
    local cur comp_dir temp word
    cur="${COMP_WORDS[$COMP_CWORD]}"
    comp_dir="$PWD/dir1"
    temp=( $(cd "$comp_dir"; compgen -f "$cur") )
    COMPREPLY=()
    for word in "${temp[@]}" ; do
        [[ -d "$comp_dir/$word" ]] && word="$word/"
       COMPREPLY+=( "$word" )
    done
}
complete -o nospace -F _my_test3 test3

_my_test4() {
    local cur comp_dir temp word
    cur="${COMP_WORDS[$COMP_CWORD]}"
    comp_dir="$PWD/dir1"
    temp=( $(cd "$comp_dir"; compgen -f "$cur") )
    COMPREPLY=()
    for word in "${temp[@]}" ; do
        [[ -d "$comp_dir/$word" ]] && word="$word/"
       COMPREPLY+=( "$word" )
    done
}
complete -o filenames -o nospace -F _my_test4 test4

_my_test5() {
    local cur comp_dir temp word
    cur="${COMP_WORDS[$COMP_CWORD]}"
    comp_dir="$PWD/dir1"
    temp=( $(cd "$comp_dir"; compgen -f "$cur") )
    COMPREPLY=()
    for word in "${temp[@]}" ; do
        [[ -d "$comp_dir/$word" ]] && word="$word/"
        [[ -d "$word" ]] && word="${word%/}"
       COMPREPLY+=( "$word" )
    done
}
complete -o filenames -o nospace -F _my_test5 test5

Then source the file in the Bash terminal window:

$ . setup

Then:

  - 'test1': will complete correctly in the current directory. This example is just to show how the completion should work when the directory to complete in, is different from the current directory.

- 'test2a': will not add slashes after directory names in 'dir1', but will incorrectly add slashes after directory names that also exist in the current directory.

- 'test2b' : Investigates how 'complete -o nospace' works without '-o filenames' option

- 'test3' : Same as 'test2b', but also manually adds slashes after directory names in 'dir1'.. (but still leads to the verbose completion lists described above in a))

- 'test4' : same as 'test2a', but also manually adds slashes after directory names in 'dir1',
 but still unwanted slashes are added after names that also exist in the current directory

- 'test5' : Same as 'test4' but also tries to trick Bash completion, by removing slashes from names that also exists in the current directory. Notice that still there is no way to avoid the incorrect slash after the file 'a' in 'dir1'. The reason is that the name 'a' also exists as a directory name in the current directory..

$ lsb_release -rd
Description: Ubuntu 14.04.2 LTS
Release: 14.04

$ apt-cache policy bash-completion
bash-completion:
  Installed: 1:2.1-4
  Candidate: 1:2.1-4
  Version table:
 *** 1:2.1-4 0
        500 http://no.archive.ubuntu.com/ubuntu/ trusty/main amd64 Packages
        100 /var/lib/dpkg/status

To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.