[Bug 1394920] Re: Filename completion not working if current directory does not match with COMPREPLY array

Peter Cordes peter at cordes.ca
Mon Dec 1 06:59:55 UTC 2014


This isn't bash-completion's bug.  If anything, it's bash's bug, if
you're sure that COMPREPLY is being mishandled.

More likely, it's a bug in your own script, since the usual programmable
completion code jumps through some hoops do to the Right Thing for files
and directories.  Your script has huge problems with spaces in
filenames, because they get quoted in compgen's output, and never
unquoted before you pass them to COMPREPLY.

Incidentally, it would run WAY faster if you used a glob match instead
of forking basename.  See the hints in /usr/share/doc/bash-
completion/README.gz

Also, pushd / popd would be easier than saving CWD.  And safer still do
do the whole thing inside a ( subshell ) to never affect the directory
context of the user's shell.  Even pushd/popd modify the user's $OLDPWD.

So you're trying to complete the current wod as a filename in a fixed
directory, regardless of the current PWD, right?

The problem might be that you're using complete -o filenames.  The
results of your completion WON'T be filenames when your function
returns, unless they're absolute paths.  The space at the end instead of
/ is because you didn't use -o nospace, and bash didn't identify the
word as a filename, because in the context of the shell when your
function returns, stat("filename") gets ENOENT.  bash only looks at
COMPREPLY once you're done building it, not with the directory context
you had while you were building it.

 If you backspace and put in a /, it will complete files in
subdirectories of wherever you were.

 Anyway, as far as I can tell, everything is working as documented, your
script is just using it wrong.  :(

BTW, you can get the idental result to your script with MUCH less code and overhead from
_compTest() {
    local curdir cur words val name
    cur="${COMP_WORDS[$COMP_CWORD]}"
    baseFolder=~/"tmp"
    COMPREPLY=( $(cd "$baseFolder"; compgen -X '?(*/)backup' -f "$cur") )
}
complete -o filenames -F _compTest aaa

$( command substitution ) is already a subshell, so you can cd in there
without affecting $OLWPWD or anything else in the user's shell.

 Of course, this still doesn't handle filenames with anything in their
name, even spaces.

To do that, borrow code from bash-completion's _filedir function:

_compTest() {
    local IFS=$'\n'
    local cur="${COMP_WORDS[$COMP_CWORD]}"
    local quoted x

    baseFolder=~/"tmp"
    _quote_readline_by_ref "$cur" quoted
#    COMPREPLY=( $(cd "$baseFolder"; compgen -X '?(*/)backup' -f "$cur") )

# IDK why _filedir does directories first.
    x=$( cd "$baseFolder"; compgen -d -X '?(*/)backup' -- "$quoted" ) &&
    while read -r tmp; do
        COMPREPLY+=( "$tmp" )
    done <<< "$x"

    x=$( cd "$baseFolder"; compgen -f -X '?(*/)backup' -- "$quoted" ) &&
    while read -r tmp; do
        COMPREPLY+=( "$tmp" )
    done <<< "$x"
}
complete -o filenames -F _compTest aaa


 Still doesn't know to put / after directory names, but does handle any filenames except those containing a newline.  If you want the / for filenames thing, you'd have to write it yourself  without depending on complete -o filenames to do it for you.  I don't think that's possible for words that don't exist in the filesystem relative to the current directory.


** Changed in: bash-completion (Ubuntu)
       Status: New => Opinion

** Summary changed:

- Filename completion not working if current directory does not match with COMPREPLY array
+ complete -o filename  space vs. trailing / can't be used to complete filenames relative to another directory

** Summary changed:

- complete -o filename  space vs. trailing / can't be used to complete filenames relative to another directory
+ complete -o filename can't be used with filenames relative to another directory to handle  space vs. trailing /

-- 
You received this bug notification because you are a member of Ubuntu
Foundations Bugs, which is subscribed to bash-completion in Ubuntu.
https://bugs.launchpad.net/bugs/1394920

Title:
  complete -o filename can't be used with filenames relative to another
  directory to handle  space vs. trailing /

Status in bash-completion package in Ubuntu:
  Opinion

Bug description:
  I am trying to ignore certain directory names when using bash
  completion. For example to ignore "backup" directories I use

  $ cat setup.sh
  _compTest() {
      local curdir cur words val name
      cur="${COMP_WORDS[$COMP_CWORD]}"
      baseFolder="."
      curdir=$PWD
      cd "$baseFolder"
      words=( $(compgen -f "$cur") )
      COMPREPLY=()
      for val in "${words[@]}" ; do
          name=$(basename "$val")
          if [[ $name == "backup" ]] ; then
              continue
          fi
          COMPREPLY+=( "$val" )
      done
      cd "$curdir"
  }
  complete -o filenames -F _compTest aaa

  
  After sourcing this:

  $ . setup.sh

  I can type

  $ aaa <tab><tab>

  and it works fine. However if I use another baseFolder, for example
  setting

  baseFolder="$HOME/base"

  in the above script (setup.sh) (where $HOME/base is different from the
  current directory) the completion list is no longer what I would
  expect. That is:

  * slashes are missing at the end of directory names, and
  * a space is added after each completed directory name, instead of a slash ("/")

  
  $ lsb_release -rd
  Description:	Ubuntu 14.04.1 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 i386 Packages
          100 /var/lib/dpkg/status

To manage notifications about this bug go to:
https://bugs.launchpad.net/ubuntu/+source/bash-completion/+bug/1394920/+subscriptions



More information about the foundations-bugs mailing list