3

When bash-completion is loaded, unrar x completes after pressing tab to RAR-archives in the directory.

But for multipart archives with the new naming convention, like

Filename.part01.rar
Filename.part02.rar
Filename.part03.rar

it doesn't see any difference between the first archive ending on .part1.rar, .part01.rar or .part001.rar and all the others parts like .part02.rar which are never opened directly, it completes them all.

Is it possible to configure bash-completion so that only the first part of multipart RAR-archives is completed? This means files which end on .rar but must not end on .part□.rar where □ is a number greater than 1 with leading zeros (e.g. 2 or 02 or 002)?

The following works for me. I DO NOT know if this is 100% correct:

# unrar(1) completion                                      -*- shell-script -*-

_unrar()
{
    local cur prev words cword cmp_opts=1 i
    _init_completion || return

    # Check if all of the middle part are options.
    # If not, we break at the last-option idx, and won't complete opts.
    for ((i=1; i<${#words[@]}-1; i++)); do
        # not using the whole list for checking -- too verbose
        if [[ ${words[i]} != -* || ${words[i]} == '--' ]]; then
            cmp_opts=0
            break
        fi
    done

    if [[ $cur == -* ]] && ((cmp_opts)); then   # options
        COMPREPLY=( $( compgen -W '-ad -ap -av- -c- -cfg- -cl -cu -dh -ep -f
            -idp -ierr -inul -kb -o+ -o- -ow -p -p- -r -ta -tb -tn -to -u -v
            -ver -vp -x -x@ -y' -- "$cur" ) )
    elif ((cword == 1)); then                   # command
        COMPREPLY=( $( compgen -W 'e l lb lt p t v vb vt x' -- "$cur" ) )
    elif ((cword == i+1)); then                 # archive
        _filedir '[rR][aA][rR]'
        # If there is a second, third, ... ninth part
        for i in "${COMPREPLY[@]}"; do
            if [[ $i == *.part*(0)[2-9].[rR][aA][rR] ]]; then
                # Only look for the first, since it's the only useful one
                COMPREPLY=()
                _filedir 'part*(0)1.[rR][aA][rR]'
                break
            fi
        done
    else                                        # files.../path...
        _filedir
    fi

} &&
complete -F _unrar unrar

# ex: ts=4 sw=4 et filetype=sh
4

1 Answer 1

2

Look at https://github.com/scop/bash-completion/pull/12/files to get a sense of how this filtering can be done.

Basically you will need to post-process COMPREPLY[] in some ways to get rid of the mis-completions. You can add a wrapper around too:

_mycomp_unrar(){
    local i
    _unrar "${[@]}" # use the old one
    # now copy the for i in "${COMPREPLY[]}" stuff
} &&
complete -p rar           # remove old completion
complete -F _mycomp_unrar # use your good new one

Or you can send a Pull Request (as shown above) and see what happens.


Added commit https://github.com/Arthur2e5/bash-completion-1/commit/a586ede to fix the problem that the existance of parts will stop normal files from showing up. (The glob as a whole is.. unreadable.)

Now you need to copy the if ((cmp_parts)) part too. Also, make cmp_parts local.

4
  • Thank you. Sadly it does not work. I've made two small changes to your code (see the edit to my question). Now it works for me. But I can barely program in bash, so I don't know if this is correct.
    – viuser
    Mar 4, 2016 at 15:49
  • @viuser That change is a nice one. Yeah, I forgot to clear the array and a $. Mar 4, 2016 at 19:36
  • @viuser You may want to check out the new commit. Mar 4, 2016 at 20:46
  • Ok, thanks a lot. Your code is kind of messy, but it has worked so far.
    – viuser
    Mar 8, 2016 at 10:27

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .