(One)-minute geek news

Group talks, Laboratoire de Chimie, ENS de Lyon

Absolute path autocompletion


Relative paths are handy to type, but they can make your commands much harder to reuse if you change your working directory. Let us enable fast absolute path typing!

Absolute vs. relative path

A path starting with the root directory (i.e. /) is called an absolute path. Example: /tmp/ /home/rstaub/ASANN ~/peudoinverse/article/main.tex (the last one will be absolute after tilde expansion).

Otherwise, a path is assumed to start from your working directory, and is called a relative path, because it is by definition relative to your working directory. Therefore, such path might not be valid if you change your working directory (with a cd command for example). Examples: Downloads/vmd-1.9.3.tar.gz ./Au111/6x6x4/opt/slab.xyz POSCAR.

While absolute paths are more painful to type, commands using them can be re-run from anywhere (you can change your working directory in between). At the contrary, commands containing relative paths should be re-run from the same working directory.

Because of relative paths, you might be interested in storing the working directory along with your commands into your bash history. See this previous bash trick if you are interested. Here, we will see how to convert relative paths into absolute paths when performing an autocompletion.

Bash autocompletion

Typing full paths in your terminal would be extremely painful and inefficient. Fortunately, your Bash configuration (hopefully) allow you to perform an autocompletion by simply hitting the <Tab> button. If not, add the following to your .bashrc:

# enable programmable completion features (you don't need to enable
# this, if it's already enabled in /etc/bash.bashrc and /etc/profile
# sources /etc/bash.bashrc).
if ! shopt -oq posix; then
  if [ -f /usr/share/bash-completion/bash_completion ]; then
    . /usr/share/bash-completion/bash_completion
  elif [ -f /etc/bash_completion ]; then
    . /etc/bash_completion
fi

Those configuration files define the functions used for providing the autocompletion features. If we look at them we would see that path autocompletion is performed using the compgen utility. This bash builtin generates the possible completions requested (filenames, commands, variables, directories, ...). The idea is to redefine this function by prefixing generated paths with the current working directory.

Therefore, enable the conversion of autocompleted relative paths to absolute paths (by prefixing them with the current xorking directory), by adding the following to your .bashrc:

# Define function to add PWD to relative paths
add_pwd() {
  if [ "${1#[/~]}" == "$1" ]; then
    echo "$PWD/$1"
  else
    echo "$1"
  fi
}
# Redefine path completion to include PWD if relative path
compgen()
{
  local x tmp OPTIND OPTARG flag
  flag=0
  while getopts ':fdA:' tmp; do
    case "$tmp" in
      f|d)
        flag=1
        break
        ;;
      A)
        case "${OPTARG}" in
          file|directory)
            flag=1
            break
            ;;
          *)
        esac
        ;;
      *)
    esac
  done
  if [ $flag -eq 1 ]; then
    x=$( command compgen "$@" ) &&
    while read -r tmp; do
      add_pwd "$tmp"
    done <<< "$x"
  else
    command compgen "$@"
  fi
}

Disclaimer: Please be aware that this is a hack that I just developed (so not enough time to thoroughly test it), and it could not work on (or even mess up) some types of autocompletion or custom configurations. So enjoy it at your own risk (to disable it, just remove those lines from your .bashrc), even so it is such an awesome hack that it is IMHO worth it...

Bonus

Even with this hack, you can autocomplete as previously (absolute or relative paths), using the Esc-/ key binding. Or Esc-? for simply listing the possible autocompletion.

References

man bash
man bc https://www.tldp.org/LDP/abs/html/debugging.html