在系统调用中以编程方式触发 shell 的自动完成事件并获取输出

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

在实际提问之前,先简单介绍一下我在做什么来理解这个想法。

我想为 Authentic Theme 添加另一个很棒的功能 Webmin.

我制作了 命令 Shell 模块 look/feel 就像它是 ordinary shell 一样。但是,由于它只是一个端口,因此几乎没有限制。当您按 Tab 键(或其他基于系统的键:Esc+Esc and/or Ctrl+I).

我的观点是让它在本地工作。我要用一个 XMLHttpRequest 调用服务器并将输入的命令部分传递给实际的 shell。调用将在 Tab 键事件时触发。

例如,当您在 Authentic Theme 下拉列表 shell 中(您可以在上面的视频截屏中看到它),并且当您键入时,假设, xa 并点击 Tab, 事件将被触发并发出请求。然后服务器收到一个字符串xa,我们准备开始。

我的问题是:

1.在 Perl 中执行此类命令的最佳方法是什么?
2。如何正确转义此类命令以确保它不会被利用;
3. 如何在 system() 调用中 以编程方式触发 Tab 键(到 运行 自动完成);
4。如何grep输出。

关于回复,以xa为例,我希望得到xargs的结果。


我知道传递的命令可能有歧义,例如,当使用 sys 时,以及当自动完成对单个 Tab 键不起作用时。我认为最好将其排除在当前问题的范围之外。

如果您知道要生成的补全类型,则可以使用 compgen bash 内置命令生成补全。

最有用的是,-c 选项将完成命令名称,-o default 将通过 readline 完成文件名。请参阅 options for complete,其中大部分内容还可以与 compgen.

一起使用

请注意,system() 会将命令传递给 /bin/sh -c,这可能与您系统上的 bash 不同。所以你可以这样做:

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

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

如果你想在给定一个特定字符串的情况下做 bash 的字面上相同的事情(而不是自己猜测完成类型),你将需要实际调用 tab-press (或等效的),您可以使用 expect 脚本来完成。这也是正确调用您可能已定义的任何自定义完成函数的唯一方法。例如,参见 bash-completion 处理 its test suite.

的方式

下面是我尝试使用 expect 脚本打印出 bash 对任意命令输入建议的完成:

#!/usr/bin/env expect

log_user 0
set prompt {/@}
set cmd [lindex $argv 0]

# start bash with no startup files for clean env
spawn env INPUTRC=/dev/null PS1=$prompt bash --norc
expect $prompt

# set some readline variables for consistent completion output
send "bind 'set show-all-if-ambiguous on'\r"
expect $prompt
send "bind 'set bell-style none'\r"
expect $prompt
send "bind 'set completion-query-items -1'\r"
expect $prompt
send "bind 'set page-completions off'\r"
expect $prompt
send "bind 'set completion-display-width 0'\r"
expect $prompt

# run the completion
send "$cmd\t $prompt"
expect {
   # multiple matches, printed on separate lines, followed by prompt
   -re "^$cmd\r\n(.*)\r\n$prompt$cmd" { puts $expect_out(1,string) }
   # single match, completed in-place
   -re "^($cmd\[^ \]*)  $prompt" { puts $expect_out(1,string) }
   # single match, completed in-place, nospace
   -re "^($cmd\[^ \]+) $prompt"  { puts $expect_out(1,string) }
   # no match
   -re "^$cmd $prompt" { exit }
}

调用 ./script.exp string 将打印出 bash 将为 string 生成的实际完成,每行一个。如果没有建议的补全,则不会打印任何内容。