4

I'm new on bash and I'm trying to write a bash script that will save user's input (some tags), to help this user I would like to allow completion based on my personal list of predefined tags only and not on the common TAB files completion (files names in the folder).

predefinedtags=(one two three four five)
echo "enter tags (separate multiple values by space)"
read -e tags
echo $tags

I would like that during the read input the user can press TAB to complete is word with the list of predefined tags. I thought it was an common question and method but I do not find a good way to do it. I found some posts that are a bit too complex for me and they seem to explain that is a not a so simple question. I don't even know if it's possible or not.

Changing tab-completion for read builtin in bash

bash and readline: tab completion in a user input loop?

Do you have any ideas ? Or there is maybe a completely different way to do it ? Thank you for your help.

Community
  • 1
  • 1
grrr
  • 151
  • 11
  • It might be a bit tricky, since the first word is completed as a command, and the following words are complete as arguments of that command. You could configure each tag to be treated as a command, which takes any of the tags as arguments, but I'm not sure how to prevent the first word from completing as anything other than one of the tags. – chepner Apr 09 '16 at 19:06

1 Answers1

2

In the second part, there is a simple version.

Give this tested version a try:

#!/bin/bash --

reade () {
  tmpdir=$(date "+/tmp/%Y%m%d%H%M%S$$")
  mkdir "${tmpdir}"
  for ptag in "${predefinedtags[@]}" ; do
    touch "${tmpdir}"/"${ptag}"
  done
  readetags=$(cd "${tmpdir}" || printf "internal error" ; read -re usertags ; printf "%s" "${usertags}")
  rm -rf "${tmpdir}" 2>/dev/null >/dev/null
  eval "${1}"=\"\$\{readetags\}\"
}
predefinedtags=(one two three four five)
printf "enter tags (separate multiple values by space)\n"
reade tags
printf "%s\n" "${tags}"

It migth be seen as odd but it is fun ! (and checked with shellcheck)

It defines a new reade function which creates a temporary directory with a unique name, and one empty file for each elements in predefinedtags. It changes the current directory to the new temporary one and runs read -e .

The TAB key will work as expected.

Finally the tags entered by the user are all assigned to tags.

Beware to not insert tags with spaces or special chars like ', " (etc.) into predefinedtags.

----

second part

You might want to define a configuration directory that would already contain empty files (the predifined tags) instead of creating and removing a temporary directory.

Replace /path/to/configuration with real pathname of the configuration directory in the script below:

#!/bin/bash --

printf "enter tags (separate multiple values by space)\n"
tags=$(cd /path/to/configuration || printf "internal error" ; read -re usertags ; printf "%s" "${usertags}")
printf "%s\n" "${tags}"

The test (where TAB key press is written):

$ ls configuration/
five  four  one  three  two

$ ./script.sh
enter tags (separate multiple values by space)
TAB
five   four   one    three  two
five ten
five ten

$ touch configuration/cat
$ ls configuration/
cat  five  four  one  three  two

$ ./script.sh
enter tags (separate multiple values by space)
TAB
cat    five   four   one    three  two
cat hello
cat hello
Jay jargot
  • 2,745
  • 1
  • 11
  • 14
  • Hello and thank you for your answer, I thought about this kind of solution and I like the way you do it. That could be a very good temporary and working solution for me instead of the "real" completion based on my array. I have to find the way to manage tags with spaces because I need to complete with multi words tags (authors, titles, etc.). Thank you for this solution and if somebody know a bit more about the array based completion feel free to write informations here. – grrr Apr 10 '16 at 10:11