在系统调用中以编程方式触发 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
生成的实际完成,每行一个。如果没有建议的补全,则不会打印任何内容。
在实际提问之前,先简单介绍一下我在做什么来理解这个想法。
我想为 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
生成的实际完成,每行一个。如果没有建议的补全,则不会打印任何内容。