autocomplete boost program options - bash

after hours of search I ended up writing my first stackoverflow question.
I want to create a completion function for a bash script, so far so good ;).
This bash script calls other executables that have their own autocompletion.
Example:
$ my_script foo par
# calls /usr/local/libexec/my_script/foo par
Autocompleting the first parameter of my_script (in this case "foo") works, because the possible options are the files in the folder "/usr/local/libexec/my_script/".
Each program in this folder does have a working auto completion, which was a byproduct of using boost::program_options.
I now want to implement the auto completion for the next parameters of my_script by referencing to the auto completion of the program gooing to be called.
$ my_script foo <tab>
# should output possible options to the foo subcommand
# like /usr/local/libexec/my_script/foo <tab>
I've started by this answer Bash completion from another completion, but _command or _command_offset 1 does not seem to work for me.
How can I get the options of foo, and how can I use this in my_script?
My current /etc/bash_completion.d/my_script looks like the following
_my_script()
{
local cur prev opts
COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}"
prev="${COMP_WORDS[COMP_CWORD-1]}"
if [[ "$COMP_CWORD" == 1 ]]; then
# 1. param: for program to be loaded
for i in $( ls /usr/local/libexec/my_script/ ); do
opts="${opts} ${i} "
done
COMPREPLY=( $(compgen -W "${opts}" ${cur}) )
else
# next param: of the program to be loaded
# how do I get the options of "foo" here?
fi
return 0
}
complete -F _my_script my_script

As soon as I read your question, the completion of sudo and git came to my mind. They both have the similar behavior you desired. So I looked for their completion functions. Here are your missing lines:
local root_command=${COMP_WORDS[0]}
_command_offset 1
It's copied from /usr/share/bash-completion/completions/sudo in Ubuntu 16.04. I totally don't knows its meaning. But it works.

Related

Run a function defined in the bash script in a new detached screen

I was writing a question, but finally came up with a solution. As it might be useful for others (my future self, at least), here it is.
Context
To run a single command in parallel in several detached screens that automatically close themselves, this works nicely:
timeslots='00_XX 01_XX 02_XX 03_XX 04_XX 05_XX 06_XX'
for timeslot in $timeslots;
do
screen -dmS $timeslot bash -c "echo '$timeslot' >> DUMP";
done
But what if, for each timeslot, we want to execute in screen not one but several (RAM-heavy) commands, one after the other?
We can write a function (in which everything is run sequentially), with an argument in our bash script.
test_function () {
# Commands to be executed sequentially, one at a time:
echo $1 >> DUMP; # technically we'd put heavy things that shouldn't be executed in parallel
echo $1 $1 >> DUMP; # these are just dummy MWE commands
# ETC
}
But, how to create detached screens that run this function with the $timelot argument?
There are lots of discussions on stackoverflow about running a distinct executable script file or on using stuff, but that's not what I want to do. Here the idea is to avoid unnecessary files, keep it all in the same small bash script, simple and clean.
Function definition (in script.sh)
test_function () {
# Commands to be executed sequentially, one at a time:
echo $1 >> DUMP; # technically we'd put heavy things that shouldn't be executed in parallel
echo $1 $1 >> DUMP; # these are just dummy MWE commands
# ETC
}
export -f test_function # < absolutely crucial bit to enable using this with screen
Usage (further down in script.sh)
Now we can do
timeslots='00_XX 01_XX 02_XX 03_XX 04_XX 05_XX 06_XX'
for timeslot in $timeslots;
do
screen -dmS $timeslot bash -c "test_function $timeslot";
done
And it works.

Capturing the exit code of sourced shell script without invoking subshell

I have two shell scripts:
test.sh
function func() {
echo $1
exit 1
}
run.sh
source ./test.sh
func "Hello"
exitCode=$?
echo "Output: ${exitCode}"
Result:
Hello
The current problem which I'm facing is that when the function func returns 1, my run.sh script breaks and nothing gets executed after it. So, is there any way I can effectively capture the exit code without breaking run.sh. I know there is way to invoke a subshell using ( func "Hello" ) but I want to do it without invoking sub-shell using flock. I looked up for reference example but could'nt find any close to it.
2 ideas that are "pushing the boundary". Use with care, as future changes to the sourced script(s) might break the logic. Recommended only if there is a way to monitor that script is working OK - e.g. when executing interactively, etc.
I would not use this kind of solutions in any production/critical system.
Option 1: Alias 'exit' to 'return' when sourcing the file.
Assuming that ALL 'exit' statement in the test.sh are to be replaced with 'return', and assuming that you are willing to take the risk of future changes to test.sh, consider using alias before sourcing
alias exit=return
source test.sh
unalias exit
func "foo"
Option 2: automatically update the function that is using 'exit' to use return.
source test.sh
body=$(type func | tail +2 | sed -e 's/exit/return/g')
eval "$body"

Arbitrary command completion - possible?

I'm looking for a way to hook in a custom bash completion function. Problem is, I want this completion function not just for a specific command, but for all commands.
Is this even possible? Having looked around for a while, I couldn't find any resources online.
To reduce the problem to the most trivial case: would it be possible to always have tab-completion for the string 'foo'?
Meaning echo f<tab> would expand into echo foo, and ls fo<tab> would expand into ls foo
For context: I'm trying to implement something similar to http://blog.plenz.com/2012-01/zsh-complete-words-from-tmux-pane.html in bash, but I'm starting to fear it's not possible.
You can do that with the -D option of the complete command:
suggest_hello()
{
COMPREPLY=( hello )
return 0
}
complete -D -F suggest_hello
Now whenever I type echo h<Tab>, I get echo hello.
$ help complete
complete: ...
...
-D apply the completions and actions as the default for commands
without any specific completion defined
...

Preserve Bash Completion for all commands that are prepended by a custom command

I have a script which allows to execute Bash processes in the background, i called it "backy". Programs I want to run in background I call like this:
backy long-running-script param1 param2
The problem is now that I loose the Bash completion for long-running-script if I prepend another script.
I want to write a Bash completion file which preserves not only the Bash completion for long-running-script and all of its parameters, also for every other script that I want to call with backy.
I have some experience with Bash completion, but I'm just missing the command which I can insert into my Bash completion script so that it completes with the completion of the script that is to be called. Any ideas?
My completion so far:
have backy &&
_backy_complete()
{
local cur prev goals
COMPREPLY=()
cur=${COMP_WORDS[COMP_CWORD]}
# How to get the completion from the script that is the param for backy,
# in a generic way?
COMPREPLY=( ????? )
return 0
} &&
complete -F _backy_complete backy
EDIT - SOLUTION:
Thanks to Lekensteyn, I replaced the content of my existing bash completion script with just this line:
complete -F _command backy
There is already a bash_completion function for such cases:
complete -F _command backy
It's used for autocompleting the commands after sudo, fakeroot and others. Any arguments passed to backy are ignored like:
backy --whatever --this --is=ignored not ignored anymore

Accessing bash completions for specific commands programmatically

I'm trying to write a small command launcher application, and would like to use bash's tab completions in my own completion system. I've been able to get a list of completions for general commands using compgen -abck.
However, I would also like to get completions for specific commands: for instance, the input git p should display completion for git's commands.
Is there any way I can use compgen to do this? If not, are there any other ways I can get a list of completions programmatically?
[EDIT: To clarify, I'm not trying to provide completion to bash - my app is a GUI command launcher. I'd simply like to use bash's existing completions in my own app.]
I don't really know how it works, but the awesome window manager uses the following Lua code for getting access to bash completion's result:
https://github.com/awesomeWM/awesome/blob/master/lib/awful/completion.lua#L119
Via complete -p we find complete -o bashdefault -o default -o nospace -F _git git. We remember "_git" for later.
The length of "git l" is 5, so we set COMP_COUNT=6. We are completing the first argument to "git", so COMP_CWORD=1.
All together we use the following script:
__print_completions() {
printf '%s\n' "${COMPREPLY[#]}"
}
# load bash-completion functions
source /etc/bash_completion
# load git's completion function
_completion_loader git
COMP_WORDS=(git l)
COMP_LINE='git l'
COMP_POINT=6
COMP_CWORD=1
_git
__print_completions
Output: "log"
Check in the /etc/bash_completion.d/ directory. This is where the different command completion scripts stay.
Quite an old question, but in the mean time I've implemented a script that handles this to reuse completions with ZSH
Here a simple but working example in bash :
function foo_completion()
{
local currentWord=${COMP_WORDS[COMP_CWORD]}
local completionList=""
case "${COMP_CWORD}" in
"1")
completionList="command1 command2 command3";
;;
"2")
completionList="param1 param2 param3";
;;
esac
COMPREPLY=( $( compgen -W "${completionList}" -- ${currentWord} ) )
}
complete -F foo_completion foo
With this kind of code, you will get commandN completed when you type "foo c" + tab and paramN completed when you type "foo command1 p" + tab
You can compute the completion list from the command help.
my2c

Resources