
Creating a bash completion script - pelsio
https://iridakos.com/tutorials/2018/03/01/bash-programmable-completion-tutorial
======
powercf
Shell programmable completion highlights how slow the OS community can be to
change/improve core tools (shell, coreutils, ttys). Completion should be
specified in the binary, and compatible with all shells. A similar interface
could be designed for all scripting languages. It was obvious ~20 years ago
that it makes no sense for each shell to specify their own completion system,
and yet here we still are.

~~~
peff
This makes sense for some completions (e.g., vanilla lists of options). But
often the completion depends on other context that the binary doesn't need to
know about. For example, I complete `git grep` patterns based on ctags.
There's no reason git should know about ctags; it's only my personal
completion that brings the two together.

~~~
powercf
That is probably a very rare case, and any shell-agnostic-completion-protocol
could be extensible to handle such a case. But, I think 99% of completions
that people want/use on a daily basis could be covered by a machine-readable
version of the usual "\--help" option (with support for placement of paths,
pids, strings, numbers etc.).

~~~
loa-in-backup
If it doesn't work reliably for all cases, there would soon be inevitable need
for the kind of scripted completion we have now.

------
cellularmitosis
I noticed a while back that Debian 9 introduced some strange breakage with
bash completion. Previously, if you were typing 'dd if=/dev/...' and started
using tab for completion, it would behave as expected. Under Debian 9, typing
'dd if=/dev/' and hitting tab will turn the command into 'dd /dev/'.

I'm sure this was an oversight in the march of progress, but it sure is
annoying to see a regression.

~~~
jamietanna
If this is still an issue, would you mind reporting it?

------
mabbo
Slowly but surely, I'm replacing half my job with bash scripts. Anything even
remotely tedious or error prone, I find that the small investment of time I'm
putting in pays off remarkably quickly.

This article? Amazing. My scripts are about to become even more useful and
easy to use.

~~~
jamietanna
I'd recommend trying to move anything fairly complicated into a "real"
language - you'll get a lot of libraries, more well-defined and familiar
syntax and also won't have to deal with cases like "do I want double quotes
here"

~~~
rhencke
Or, have your cake and eat it too!

[https://xon.sh](https://xon.sh)

------
kazinator
I tried writing Bash completion handlers for a Lisp dialect. I couldn't figure
out how to get Bash to stop closing quotes, so I gave up on it.

Concretely, here is the behavior:

    
    
      $ ./txr -e '(list[Tab]
      (list         (list-carray  (list-str     (list-vector  
      (list*        (listp        (list-vec     
      0:[0924:142129]:zelenka:~/txr$ ./txr -e '(list-vector'
    

I continued with _-e '(list-v[Tab]_ and it then produced _-vector '_ including
the closing quote!

Clearly, it is oriented toward the idea that each token of the language being
completed is a separate command line argument, such as a path name or
whatever; it is not clear how to get it to complete syntax that is packaged as
a single argument in a quote.

The bash code is:

    
    
      txr_complete()
      {
         local target=$2
         local context=$3
         COMPREPLY=($(txr ./txr-bash.tl "$target" "$context"))
      }
    
      complete -F txr_complete txr
    

The _. /txr-bash.tl_ file is:

    
    
      (tree-bind (target context) *args*
        (cond
          ((m^$ #/-[etpP]/ context)
           (iflet ((match-rng (r$ #/[^ ()\[\]]+/ target)))
             (let* ((pref [target 0..(from match-rng)])
                    (suff [target match-rng])
                    (funs (if (plusp (len pref)) (find [pref -1] "[(")))
                    (boundfn (if funs (fun fboundp) (fun boundp))))
               (mapdo (op pprinl `@pref@1`)
                      (keep-if
                        [andf boundfn
                              (opip symbol-name
                                    (starts-with suff))]
                        (package-symbols :usr))))))))

------
mfontani
The "real" screenshot, which was done with transparency turned on and
displayed parts of what was underneath the shell, was a bit difficult to read.

------
eb0la
Thanks! I only knew about this linux journal article:
[https://www.linuxjournal.com/content/more-using-bash-
complet...](https://www.linuxjournal.com/content/more-using-bash-complete-
command)

I used it for coding a simple bash completion for Kafka. Code is almost self-
explanatory. [https://github.com/igponce/kafka-bash-
completion](https://github.com/igponce/kafka-bash-completion) \- just in case
someone might find it useful.

------
JepZ
Nice write up. If you want it down to the point I can recommend this
StackOverflow/AskUbuntu answer:

[https://askubuntu.com/questions/68175/how-to-create-
script-w...](https://askubuntu.com/questions/68175/how-to-create-script-with-
auto-complete)

------
joobus
If you care about having nice completions and are able to switch your shell,
use zsh. The completion engine in zsh is much more featureful.

------
fibo
I created once a completion for a bash function I wrote. Hint: launch npm
completion and steal code from there.

------
Myrmornis
I would like completion to automatically work on aliases in bash. I use bash
over zsh in order to become better at bash programming, but completion of
aliases is the main thing that makes me miss zsh. Well that and * * globbing
syntax.

(How do I cause two consecutive asterisks to be rendered as such in HN?)

~~~
kstrauser
> I use bash over zsh in order to become better at bash programming

That's masochism. It's perfectly reasonable to use different interactive and
programming shells. I mean, I write most of my would-be shell scripts in
Python these days, but I wouldn't want to use it as my main command line
(although xonsh is actually quite nice).

~~~
Myrmornis
It's perfectly reasonable, but what's relevant is whether it's optimal. In
today's world, with the ascendancy of cloud services and containerization,
shell scripting continues to be just as important a skill for software
engineers as it was in 2008, 1998, or 1988. And today, the language of
production shell scripting is bash. Therefore, using bash in one's personal
system is good training for the skills you will make use of in production
systems.

E.g. see
[https://google.github.io/styleguide/shell.xml](https://google.github.io/styleguide/shell.xml)

> bash is the only shell scripting language permitted for executables.

I'm surprised you choose to write would-be shell scripts in python. I think
that a major reason that shell scripting endures is that handling process
management and process output is much more work in real programming languages
than in dedicated shell languages.

EDIT: But thanks for the pointer to xonsh; that looks fun. Something
innovative like that could definitely tip the balance in favor of using that
for local shell work and leaving bash as a language one has to know for
production work.

~~~
kstrauser
I write plenty of shell scripts where appropriate, but my main point was
really that you don't need to couple your interactive environment to your
scripting environment. Sure, write your shell scripts in bash. That doesn't
mean you need to use that as your regular shell, though.

~~~
Myrmornis
It's true. My thinking was that there are some techniques that I use in both
interactive shell usage and in scripts, and that using the same language for
both would teach me them better. I'm trying to think what the best examples
are, having run this experiment on myself for a couple of years now. I think
one is process substitution with <() and io redirection stuff like <<<.

Also IIRC correctly bash and zsh differ in whether piped commands run in
different subshells.

Stuff like that; I'd like to just have firmly in my mind for interactive shell
and scripting and not have to know two similar languages.

But I miss tab completion for aliases.

------
jacabado
This is tangential do the OP but what would it take to send external input to
a completion script?

The idea would be to have a different interface to do the auto-completion.

I'm thinking of creating a visual UI through service discovery and providing
an easy shortcut sheet to various points of a system.

------
techntoke
I really wish they would make completion work in BusyBox/Ash. Would make
Alpine a lot more useful without having to install Bash.

------
tambourine_man
I'm guessing this works with macOS ancient version of Bash, right?

It's been on my todo list for a long time.

~~~
computerfriend
You should update by installing from homebrew.

~~~
tambourine_man
Yeah, but replacing something as basic as the shell is not a comforting
thought. My days of fiddling with the OS are long gone.

~~~
spudlyo
If you're nervous about replacing your default login shell you can do it just
for tmux in your .tmux.conf like:

    
    
        set -g default-shell /usr/local/bin/bash
    

Having competitions on my Mac really makes my day, and every time I complete
on a remote host like below, I am still thrilled.

    
    
        scp somehost:<tab>

~~~
tambourine_man
That sure is enticing.

Do you mind sharing the needed incantation?

~~~
spudlyo

        brew install bash bash-completion@2
    

The SSH magic lives in: /usr/local/Cellar/bash-completion@2/2.8/share/bash-
completion/completions/ssh in a function called _scp_remote_files().

