LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - General (https://www.linuxquestions.org/questions/linux-general-1/)
-   -   commandline autocompletion for my shell script (https://www.linuxquestions.org/questions/linux-general-1/commandline-autocompletion-for-my-shell-script-668388/)

mmn357157 09-08-2008 09:58 AM

commandline autocompletion for my shell script
 
Hi Guys,

I want to create a Linux shell script which will ask you for input and unlike a normal read command it should allow to use 'TAB' character to auto complete the input value. I will be able to use a list of words/names in a file to look for this auto completion.


The real requirement is like this:

I have a websites name-list in a file one name per line. My program should ask for a website name and if the user enters like 'www.mysi' and press 'TAB' for auto completion, it should expand like 'www.mysite.com'.

Any solution we have?

Thanks in advance

mmn357157

Mr. C. 09-08-2008 10:47 PM

The read command can use the -e option to use readline functionality. However, there appears to be a bug with auto-completion and read, which can be seen with:

Code:

$ cat complete.sh
#!/bin/bash

# set of URLs to match against
urls="http://example.com http://example.us http://example.net"

set -o emacs
bind 'set show-all-if-ambiguous on'
bind 'set completion-ignore-case on'
bind 'TAB:dynamic-complete-history'

# load bash's history list against which we'll attempt completion
for i in $urls ; do
    history -s $i
done

read -e -p "URL? " word
echo Value read: $word

If you run complete.sh and hit the TAB key, you'll see partial completion of the URL list specified in $urls. Once that partial completion is done, bash no longer continues working on completion from that point. The good news is that Control-P/Control-N and arrow keys work to cycle through the list.

Another possibility, which you'll have to work out, is to read only 1 character at a time, and test for the TAB character. When you read TAB, you perform your own completion of the current input against your word list using compgen (eg. compgen -W "$urls" $current_input_word). You do this until you get only 1 exact match from compgen. With this mechanism, you'll also have to handle moving the cursor back to the beginning of the line (use tputs).

mmn357157 09-09-2008 05:20 AM

hi,

Following code is working for me exactly like in a command line. It seems no partial completion with below one, but can check always. Thanks for the help.

Quote:

#get arguments from tomcat configuration file
TOMCAT_CONFIG="/root/wsbuild/server/tomcat/conf/server.xml"
args="$(cat $TOMCAT_CONFIG | sed -n 's/^[ ]*<Host[ ]*name[ ]*=[ ]*"[ ]*\([^"]*\)[ ]*".*$/\1/gp')"

set -o emacs
bind 'TAB:dynamic-complete-history'

for vhost in $args
do
history -s $vhost
done

#remove any old history other than site names
HISTSIZE=$(echo $args | wc -w)

read -e -p "Enter sitename: " site
Regards,

MMN

otho 09-10-2008 12:59 PM

you could also use rlwrap which will intermediate terminal input to another program using readline. That way you can make your shell without and extra code, and just call

rlwrap myshell

All of the basics are made up, including tab completion, where the list for tab completion would be a specified file or ~/.myshell_completion

Mr. C. 09-10-2008 01:49 PM

Or rlfe (from the readline source, in the readline/examples directory), which is available on many distributions.

I reported the bug above to the bash maintainers. We'll see what results.

Mr. C. 09-11-2008 11:29 AM

Ok, it appears I was in error thinking the history completion was not working with read -e. The problem is described in the bash FAQ, item E13.

The : (colon) character is special to readline, and must be removed from the bash/readline's COMP_WORDBREAK variable to function with the URLs required in the OPs problem.

So, the new solution is:

Code:

#!/bin/bash

set -o emacs
bind 'set show-all-if-ambiguous on'
bind 'set completion-ignore-case on'

COMP_WORDBREAKS=${COMP_WORDBREAKS//:}

#bind TAB:menu-complete
bind 'TAB:dynamic-complete-history'

urls="http://example.com http://sample.net http://example.us http://example.net"
for i in $urls ; do
    history -s $i
done

echo $urls
compgen -W "$urls" http://sa
read -e -p "What? " arg1

This now works as expected.


All times are GMT -5. The time now is 03:34 PM.