Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 9217125
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: June 18, 20262026-06-18T02:34:20+00:00 2026-06-18T02:34:20+00:00

Say I have a command named foo that takes one argument (either encrypt or

  • 0

Say I have a command named “foo” that takes one argument (either “encrypt” or “decrypt”) and then a list of files. I want to write a bash completion script that helps with the first argument and then enables standard file completion for the others. The closest I’ve been able to come is this:

complete -F _foo foo

function _foo()
{
    local cmds cur
    if [ $COMP_CWORD -eq 1 ]
    then
        cur="${COMP_WORDS[1]}"
        cmds=("encrypt decrypt")
        COMPREPLY=($(compgen -W "${cmds}" -- ${cur}) )
    else
        COMPREPLY=($(compgen -f ${COMP_WORDS[${COMP_CWORD}]} ) )
    fi
}

This does the first argument correctly and will chose a filename from the current directory for the subsequent ones. But say the current directory contains a subdirectory bar that contains a file baz.txt. After typing ba-TAB-TAB, completion results in “bar ” (space after the “r”) and is ready to choose the next argument. What I want is the standard bash completion, where the result is “bar/” (no space after the slash), ready to choose a file in the subdirectory. Is there any way to get that?

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-06-18T02:34:21+00:00Added an answer on June 18, 2026 at 2:34 am

    The bash documentation can be a little enigmatic. The simplest solution is to alter the completion function binding:

    complete -o filenames -F _foo foo
    

    This means the function returns filenames (including directories), and special handling of the results is enabled.

    (IMHO the documentation doesn’t make it clear that this effectively post-processes COMPREPLY[] as set by your completion function; and that some of the -o options, that one included, when applied to compgen appear to have no effect.)

    You can get closer to normal bash behaviour by using:

     complete -o filenames -o bashdefault -F _foo foo
    

    that gets you “~” completion back.

    There are two problems with the above however:

    • if you have a directory named “encrypt” or “decrypt” then the expansion of your keywords will grow a trailing “/”
    • $VARIABLE expansion won’t work, $ will become \$ to better match a filename with a $. Similarly @host expansion won’t work.

    The only way that I have found to deal with this is to process the compgen output, and not rely on the “filenames” post-processing:

    _foo()
    {
        local cmds cur ff
        if (($COMP_CWORD == 1))
        then
            cur="${COMP_WORDS[1]}"
            cmds="encrypt decrypt"
            COMPREPLY=($(compgen -W "$cmds" -- "$cur"))
            COMPREPLY=( "${COMPREPLY[@]/%/ }" )   # add trailing space to each
        else
            # get all matching files and directories
            COMPREPLY=($(compgen -f  -- "${COMP_WORDS[$COMP_CWORD]}"))
    
            for ((ff=0; ff<${#COMPREPLY[@]}; ff++)); do
                [[ -d ${COMPREPLY[$ff]} ]] && COMPREPLY[$ff]+='/'
                [[ -f ${COMPREPLY[$ff]} ]] && COMPREPLY[$ff]+=' '
            done
        fi
    }
    
    complete -o bashdefault -o default -o nospace -F _foo foo
    

    (I also removed the superfluous array for cmd in the above, and made compgen more robust and handle spaces or leading dashes in filenames.)

    The downsides now are that when you get the intermediate completion list (i.e. when you hit tab twice to show multiple matches) you won’t see a trailing / on directories, and since nospace is enabled the ~ $ @ expansions won’t grow a space to cause them to be accepted.

    In short, I do not believe you can trivially mix-and-match your own completion and the full bash completion behaviour.

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

Let's say I have an object who's class definition looks like: class Command: foo
Let's say I have: $files = [file1, file2] exec { exec1 : command =>
Lets say I have a loop in Bash: for foo in `some-command` do do-something
I'm using linux. Let's say I have a program named add. The program takes
Say, I have files foo.js and bar.css in my project. There is a :find
Lets say I have a table that has a bit column named Active .
I have a bunch of C source files named sequentially (say f1.c , f2.c
Say I have a command line C program which is currently executing, and I
Say I have a command I want to run ( cmd ) and a
In a shell script lets say i have run a command like this for

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.