Ilia Rostovtsev Ilia Rostovtsev - 1 year ago 54
Perl Question

Trigger programmatically autocomplete event for shell in system call and get output

Before actual question few words about what I'm doing to grasp the idea.

I would want to add another cool feature to my Authentic Theme for Webmin.

I have made Command Shell module look/feel just if it was ordinary shell. However, as it's only a port, it has few limitations. One of them is missing shell autocomplete, when you hit

Tab
key (or other based on the system:
Esc+Esc
and/or
Ctrl+I
).

My point is to make it work natively. I'm going to use an
XMLHttpRequest

call to the server and pass the part of entered command to the actual shell. The call will be triggered on the event of the
Tab
key.

For example, when you're in Authentic Theme dropdown shell (you could see it on the video screencast above), and when you type, let's say,
xa
and hit
Tab
, the event will be triggered and make a request. Then the server receives a string
xa
and we're ready to begin.

My questions are is:



1. What is the best way to execute such command in Perl?

2. How to properly escape such command to make sure that it won't be exploitable;

3. How to trigger programmatically
Tab
key (to run autocomplete) in the
system()
call;

4. How to grep output.

On the respond, using
xa
as an example, I expect to get
xargs
on the results.




I'm aware about possibly of ambiguity of the passed command, for example, when using
sys
, and when autocomplete wouldn't work on the single
Tab
key. I think it's better to exclude this from the scope of current question.

Answer Source

You can trigger generations of completions using the compgen bash builtin.

The -c option will complete command names, -o default will complete filenames through readline. See the options for complete for a list of options you can also use with compgen.

Note that system() will pass the command to /bin/sh -c, which may not be the same as bash on your system. So you can do something like:

system("/bin/bash", "-c", "compgen -c xa")
# xargs
# xattr
# etc…

or

system("/bin/bash", "-c", "compgen -o default file")
# file.txt
# file.pdf
# etc…

If you want to do literally the same thing that bash would do, you will need to run things through an expect script. See for example the way that bash-completion handles its test suite.

A simple script would be like:

#!/usr/bin/env expect

set prompt {@}
set cmd [lindex $argv 0]
spawn env [email protected] /bin/bash --norc
expect -re $prompt
send "$cmd\t\t"
expect -re $prompt

Calling ./script.exp string will print out the actual completions that bash will produce for string. You'll have to either improve the expect script or parse its output to get rid of the prompt, etc.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download