4

I'm trying to debug auto completion script located in /usr/share/bash-completion/bash_completion (bash completion package on every distro)
I did

export PS4='+'$'\t''$LINENO'$'\t    # \t for proper indentation
set -x

in the current shell, then typed a command (following by space), and pressed tab to call auto completion.
This is a part of the result:

+       2205    for dir in "${dirs[@]}"
+       24      [[ -d /usr/share/bash-completion/completions ]]
+       2207    for compfile in "$cmd" "$cmd.bash" "_$cmd"
+       26      compfile=/usr/share/bash-completion/completions/bittch
+       28      [[ -f /usr/share/bash-completion/completions/bittch ]]
+       2207    for compfile in "$cmd" "$cmd.bash" "_$cmd"

As you see the first line number is 2205 which is the absolute line number inside the script. Surprisingly, the number of the next line (which is a nested block) is 24, that is the line number relative to the function itself (see below)

__load_completion()
{
    local -a dirs=(${BASH_COMPLETION_USER_DIR:-${XDG_DATA_HOME:-$HOME/.local/share}/bash-completion}/completions)
    local ifs=$IFS IFS=: dir cmd="${1##*/}" compfile
    [[ -n $cmd ]] || return 1
    for dir in ${XDG_DATA_DIRS:-/usr/local/share:/usr/share}; do
        dirs+=($dir/bash-completion/completions)
    done
    IFS=$ifs

    if [[ $BASH_SOURCE == */* ]]; then
        dirs+=("${BASH_SOURCE%/*}/completions")
    else
        dirs+=(./completions)
    fi

    local backslash=
    if [[ $cmd == \\* ]]; then
        cmd="${cmd:1}"
        # If we already have a completion for the "real" command, use it
        $(complete -p "$cmd" 2>/dev/null || echo false) "\\$cmd" && return 0
        backslash=\\
    fi
    for dir in "${dirs[@]}"; do
        [[ -d $dir ]] || continue
        for compfile in "$cmd" "$cmd.bash" "_$cmd"; do
            compfile="$dir/$compfile"
            # Avoid trying to source dirs; https://bugzilla.redhat.com/903540
            if [[ -f $compfile ]] && . "$compfile" &>/dev/null; then
                [[ $backslash ]] && $(complete -p "$cmd") "\\$cmd"
                return 0
            fi
        done
    done

    # Look up simple "xspec" completions
    [[ -v _xspecs[$cmd] ]] &&
        complete -F _filedir_xspec "$cmd" "$backslash$cmd" && return 0

    return 1
}

I know that LINENO represents The line number in the script or shell function currently executing. But these are in the same function, so either both should be relative (to the beginning of __load_completion()) or absolute.
Why is this?

New contributor
Alireza Mohamadi is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.
3
  • It looks like it depends on the kind of statement. control-flow statements (e.g. for) get absolute line numbers, ordinary statements get relative.
    – Barmar
    Oct 12 at 19:15
  • @Barmar It makes sense, but this behavior is undesired I believe. At least it's not documented. I'll go through source code this weekend. 2 days ago
  • I wasn't trying to explain it, just noticing a pattern.
    – Barmar
    2 days ago

Your Answer

Alireza Mohamadi is a new contributor. Be nice, and check out our Code of Conduct.

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.