Unexpected bash autocompletion behavior within a symbolic link loop
Asked Answered
M

3

5

I have the following directory structure:

base/
  dir/
    subdir/
    link -> ../dir

Now if I cd to dir/link and type:

cd ../subd[tab]

I get:

cd ../subdir[space] 
  1. I would understand if autocomplete fails (because it would canonize the path and look into base/ and not dir/).

  2. I would also understand if it autocompletes to cd ../subdir/ with the ending / (because it would interpret .. as go up one level and search into dir/).

But I do not understand the actual behaviour that is somewhere between the two. Ideally I would like bash to behave like 2. (autocomplete to cd ../subdir/). I am using fedora 14, bash version 4.1.7(1). Any idea how to accomplish this ?

Misdeem answered 12/4, 2012 at 8:49 Comment(2)
Googling for "bash autocomplete symlink to directory" finds: unix.stackexchange.com/questions/14337/… superuser.com/questions/155167/… superuser.com/questions/271626/…Lilywhite
First link is about find, not bash autocompletion. Second link is about autocompletion to a symlink. This is not my case as subdir is a regular directory. Also I guess I have mark-symlinked-directories set to on already as typing cd li[tab] autocompletes to cd link/ None of these links tell me how to complete to cd ../subdir/Misdeem
M
0

After digging the source code a bit, it looks like this is a bit complicated. The actual problem is a mix between bash allowing symlinks inside the working directory (see pwd -L and pwd -P) and readline not able to determine the type of a match if it is not in a physical directory

In readline/complete.c:1694

s = (nontrivial_match && rl_completion_mark_symlink_dirs == 0)
? LSTAT (filename, &finfo)
: stat (filename, &finfo);

stat() fails since ../ is understood as relative to the physical path and not the logical path. readline fails to determine this is a directory and therefore does not append the final '/'. A very similar problem is described here

So I guess I can live with the existing behaviour for now...

Misdeem answered 13/4, 2012 at 16:14 Comment(0)
E
1

UPDATE: The program with which you can customize auto-completion is called complete.

You can find some good basic examples here: More on Using the Bash Complete Command

Using function and script names as per the above link, here is a script which appends the / to a symbolic link to a directory... It is just a rough sample, but it shows it can be done (I haven't tried it with the cd builtin...

Associate the function _mycomplete_ with executable myfoo

complete -F _mycomplete_ myfoo

The function to go in ~/.bashrc

function _mycomplete_()
{
    local cmd="${1##*/}"
    local word=${COMP_WORDS[COMP_CWORD]}
    local line=${COMP_LINE}
    local xpat='!*.foo'

    COMPREPLY=($(compgen -f -X "$xpat" -- "${word}"))
    if ((${#COMPREPLY[@]}==1)) ;then
       [[ -h $COMPREPLY ]] && COMPREPLY="$COMPREPLY/"
    fi
}

Original answer:

At the command-line, the main indicator of a auto-expansion to a symbolic link is shown on the last line of the following table, ie. a name expands but without the final /.

 on pressing TAB                                         on pressing TAB (again)  
  what happens?              meaning                        what happens?
===================      =======================     ==================================== 
Nothing is appended  1=> Multiple sub-dirs exist  => A list of possibilities is presented
                     2=> No sub-directory exists  => Nothing is appended (again)

Expands to end in /   => A uniquely matching dir  => ...as per first column (repeat)
Expands text only     => Current name is a link   => Expands to end in /

In your example, if you have already primed the command-line to the full name, ie. cd link then the indicator is not obvious. Also you won't know it is a symbolic link via the list of possibilities.

To be able to cd to the link's target, you can use cd -P link, or set -P; cd link

Enclasp answered 12/4, 2012 at 11:47 Comment(6)
Where do you get the table from ? Is it documented in bash manual or did you get it from experience ? About the lcd() command, I do not really need this. What I want is autocomplete to put the ending '/'.Misdeem
Also a strange thing I just noticed is that both cd ../dir and cd ../subdir work ! Looks strange...Misdeem
I seems that what you need it complete ... I haven't used it before, but it certainly allows for customization.... I've added a link ..Enclasp
Problem is I want to customize the default cd command. So using complete would force me to completely override the default completion just for my particular case. This could work but I do not like it so much. And it still does not explain why the default completion is behaving this way...Misdeem
My impression, from reading that linked page, is that it is most likely a simple case of it being the deault behaviour for cd (the page refers to a definition file (couldn't find it on my system though)... eg. I like it (and probably others do too). I like it because it offers a way to know that it is a symbolic link...Enclasp
I guess you're right by saying it 'works as designed' But subdir is not a symlink so I still find the behaviour a bit strange.Misdeem
M
0

After digging the source code a bit, it looks like this is a bit complicated. The actual problem is a mix between bash allowing symlinks inside the working directory (see pwd -L and pwd -P) and readline not able to determine the type of a match if it is not in a physical directory

In readline/complete.c:1694

s = (nontrivial_match && rl_completion_mark_symlink_dirs == 0)
? LSTAT (filename, &finfo)
: stat (filename, &finfo);

stat() fails since ../ is understood as relative to the physical path and not the logical path. readline fails to determine this is a directory and therefore does not append the final '/'. A very similar problem is described here

So I guess I can live with the existing behaviour for now...

Misdeem answered 13/4, 2012 at 16:14 Comment(0)
C
0

I was having the exact same problem in Ubuntu. Autocompletion was working like in your example #2, but started working as you describe at some point. I purged and reinstalled the package bash-completion, and now everything seems back to normal. Do not uninstall bash! Only bash-autocompletion.

Edit

look at this:

https://bbs.archlinux.org/viewtopic.php?id=113158

Clausius answered 14/5, 2012 at 23:59 Comment(1)
I doubt this is the same problem as I do not have the bash-completion installed. Also the problem I describe is very specific to symlink and the internal readline completionMisdeem

© 2022 - 2024 — McMap. All rights reserved.