Bash script with user defined functions in autocomplete
This workaround should do the trick.
#!/bin/bash
func1() {
echo "You are in func1: $@"
}
func2() {
echo "You are in func2: $@"
}
myFunc1() {
echo "You are in myFunc1: $@"
}
# usage: autocomplete "word1 word2 ..."
autocomplete() {
# try to autocomplete the last word, and
# keep a record of the rest of the input
OTHER_WORDS="${READLINE_LINE% *} "
if [[ ${#OTHER_WORDS} -ge ${#READLINE_LINE} ]]; then
# if there is only 1 word...
OTHER_WORDS=""
fi
# the -W flag tells compgen to read autocomplete
# from the 1st argument provided, then we
# evaluate the last word of the current line
# through compgen
AUTOCOMPLETE=($(compgen -W $1 "${READLINE_LINE##* }"))
if [[ ${#AUTOCOMPLETE[@]} == 1 ]]; then
# if there is only 1 match, substitute it
READLINE_LINE="$OTHER_WORDS${AUTOCOMPLETE[0]} "
# position the cursor at the end of the word
READLINE_POINT=${#READLINE_LINE}
else
#...otherwise print the possibilities
echo -e "cmd> $READLINE_LINE\n${AUTOCOMPLETE[@]}"
fi
}
# list the values to be autocompleted
MYFUNC="func1 func2 myFunc1"
# enable line editing
set -o emacs
# call autocomplete when TAB is pressed
bind -x '"\t":"autocomplete \$MYFUNC"';
while read -ep "cmd> "; do
# history is just a nice bonus
history -s $REPLY
eval ${REPLY}
done
To try it :
]$ ./mybash.sh
cmd> my<tab>
cmd> myFunc1
cmd> func<tab>
func1 func2
cmd> func1 hello, world!
You are in func2: hello, world!
cmd> func1 my<tab>
cmd> func1 myFunc1
As mentioned in my previous comment, have a look at this question. It uses a nice trick to auto detect all inner functions in order to use it as auto-complete values.
Bash: how to simplify autocompletion of custom created functions by using the already available bash-completion functions?
Git completion is quite easy to add to your own bash functions actually, for example, this little script autocompletes your git branches:
my_func () { return; }
source /usr/share/bash-completion/completions/git
__git_complete my_func __git_complete_refs
Now my_func
has autocompletion for branch names.
Or like this you can have an alias g
to git
with working auto completion:
source /usr/share/bash-completion/completions/git
alias g=git
__git_complete g __git_main
Look in the /usr/share/bash-completion/completions/git
file for all completions possible. The original file in the source code: https://github.com/git/git/blob/master/contrib/completion/git-completion.bash
There are a bunch of default complete functions, but they might not always do what you want, because they are made specially for git commands. In some cases you might want to make a custom auto complete function. Looking in the source code of the git-completion.bash
you can figure stuff out. For example this auto complete function only completes local branch names:
source /usr/share/bash-completion/completions/git
git_local_branches () {
__gitcomp_direct "$(__git_heads "" "$cur" " ")"
}
my_func () { return; }
__git_complete my_func git_local_branches
Also see this answer for more info on how general bash completion works. Normally you would use the complete
command, but Git created its own complete function __git_complete
, which you should use for git completion.
Autocomplete function argument in shell function
It does matter very much which shell you're using.
First, let me mention that you can add often used directories to a "hotlist" that you can then use with cd
. For instance, you could do this:
cdpath=(~/Development/Personal ~/Development/Work)
and then, at any point (and from any directory), you should be able to type cd blog
. Tab completion will work as well.
If you still want to have your own functions for cd
and add tab completion for them, here's a very informative article about how to write your own completion functions.
In a nutshell, you create a file in the zsh completion directory, called _dp
, and add something like this to it:
#compdef dp
compadd $(command ls -1 $HOME/Development/Personal 2>/dev/null --color=none | sed -e 's/ /\\ /g')
How to configure bash autocomplete for file search and custom search?
You can use complete
's -o default
option (Usually I'd use both -o default
and -o bashdefault
):
complete -o default -F _test_complete remote
According to man bash
:
bashdefault
Perform the rest of the default bash completions if the compspec generates no matches.
default
Use readline's default filename completion if the compspec generates no matches.
Git autocomplete for custom bash functions
Manually-crafted bash completion is as simple as this:
# our handler that returns choices by populating Bash array COMPREPLY
# (filtered by the currently entered word ($2) via compgen builtin)
_gitpull_complete() {
branches=$(git branch -l | cut -c3-)
COMPREPLY=($(compgen -W "$branches" -- "$2"))
}
# we now register our handler to provide completion hints for the "gitpull" command
complete -F _gitpull_complete gitpull
After sourcing the above commands:
$ gitpull <TAB>
asd master qwe zxc
$ gitpull m<TAB>
$ gitpull master
The ultimate reference on bash completion is (of course) the section on Programmable Completion in the bash manual, but a nice introduction is given on "Debian Administration" page (part 1 and a more important part 2).
autocomplete in bash script
Actually you can borrow quite a bit of code from geirha's answer:
# this is a custom function that provides matches for the bash autocompletion
_repo_complete() {
local file
# iterate all files in a directory that start with our search string
for file in ~/Desktop/_REPOS/"$2"*; do
# If the glob doesn't match, we'll get the glob itself, so make sure
# we have an existing file. This check also skips entries
# that are not a directory
[[ -d $file ]] || continue
# add the file without the ~/Desktop/_REPOS/ prefix to the list of
# autocomplete suggestions
COMPREPLY+=( $(basename "$file") )
done
}
# this line registers our custom autocompletion function to be invoked
# when completing arguments to the repo command
complete -F _repo_complete repo
The for
loop iterates all files in a directory that start with the string given as second argument to the _repo_complete
function (this is the string to be autocompleted).
Add the code to your .bashrc
and it should work!
Enable autocomplete for parsed arguments in getopts
First I copied your script snippet in a file called auto.sh and set the execution permission on it:
#!/bin/bash
while getopts 'l:r:m:?h' c
do
case $c in
l)
library=$OPTARG
;;
r)
rename_config=$OPTARG
;;
m)
align_mm=$OPTARG
;;
h|?) usage
;;
esac
done
if [ $library = "bassik" ];
then
read_mod="clip"
clip_seq="GTTTAAGAGCTAAGCTGGAAACAGCATAGCAA"
echo "Bassik library selected"
elif [ $library = "moffat_tko1" ];
then
read_mod="trim"
sg_length=20
echo "Moffat TKO1 library selected"
elif [ $library = "sabatini" ];
then
read_mod="trim"
sg_length=20
echo "Sabatini library selected"
fi
Then, to set up an auto-completion for the -l
option, you can begin with those basics steps (this can be future enhanced):
1. Create a completion script (e.g. ./auto-complete.sh) which contains the libs function to be called upon completion request (-F
parameter of complete command). The function triggers the display of the library names (content of COMPREPLY array variable) if -l
option is the word preceding the completion place ($3
argument):
function libs()
{
# $1 is the name of the command
# $2 is the word being completed
# $3 is the word preceding the word being completed
case $3 in
-l) COMPREPLY+=("bassi")
COMPREPLY+=("moffat_tko1")
COMPREPLY+=("sabatini");;
esac
}
complete -F libs auto.sh
2. Source the script in your local shell:
$ source ./auto-complete.sh
3. Launch the shell script and type TAB
key twice after a space behind the -l
option:
$ ./auto.sh -l <tab><tab>
bassik moffat_tko1 sabatini
$ ./auto.sh -l bassik
Bassik library selected
4. The preceding systematically lists all the choices when you type TAB
key. To have a more accurate completion when typing the first letters, the completion script can be enhanced to use compgen command:
function libs()
{
# $1 is the name of the command
# $2 is the word being completed
# $3 is the word preceding the word being completed
case $3 in
-l) COMPREPLY=($(compgen -W "bassik moffat_tko1 sabatini" "${COMP_WORDS[$COMP_CWORD]}"));;
esac
}
complete -F libs auto.sh
How to pass a function with arguments to another function
The -F
option is supposed to be followed by just a function name. If you want to execute a command with options, you need to use -C
. But the command is required to print the completions to standard output, not set COMPREPLY
. So change the function to:
_autocomplete() {
COMPREPLY=( $(compgen -W "$1" -- "${COMP_WORDS[COMP_CWORD]}") )
for reply in "${COMPREPLY[@]}"
do
printf '%s\n' "$reply"
done
return 0
}
complete -C "_autocomplete example_param" some_function
How to make a custom BASH function to cd into a certain directory with autocomplete
You could consider CDPATH
. You can export CDPATH=~/Documents
to have all the directories under ~/Documents added for autocompletion. You can have a function or alias for this export command and set & unset CDPATH
as and when you need.
Hope this helps!
Related Topics
Curl Error "No Alternative Certificate.."
Merge Multiple Lines to 1 Row with Awk(Or Familiar)
Linux to Define Custom Shell Command
Wmctrl: Moving a Fullscreen Window
Capture Network Traffic on Two Different Ports Simultaneously
Linux Set End of File (Shrink, Truncate, Cut Out Some Data @ End)
Create and Test X86-64 Elf Executable Shellcode on a Linux Machine
Killing a Daemon Using a Pid File
Debian 7, Fstab, Mount.Cifs Invalid Argument
Infinite Loop Receive from Serial Port
What Is The Mutex Acquire and Release Order
Using Find But Only in Subdirectories Matching Certain Pattern
How to Run 16 Bit Code on 32 Bit Linux
Assign Output of a Shell Command to a Variable
Is It Correct to Use The Rc.Local File to Start a Program When The System Starts