bash和readline:用户输入循环中的制表符完成?
我正在制作一个bash脚本,它向用户显示一个命令行 cli代码如下所示:bash和readline:用户输入循环中的制表符完成?,bash,bash-completion,Bash,Bash Completion,我正在制作一个bash脚本,它向用户显示一个命令行 cli代码如下所示: #!/bin/bash cmd1() { echo $FUNCNAME: "$@" } cmd2() { echo $FUNCNAME: "$@" } cmdN() { echo $FUNCNAME: "$@" } __complete() { echo $allowed_commands } shopt -qs extglob fn_hide_prefix='__' allow
#!/bin/bash
cmd1() {
echo $FUNCNAME: "$@"
}
cmd2() {
echo $FUNCNAME: "$@"
}
cmdN() {
echo $FUNCNAME: "$@"
}
__complete() {
echo $allowed_commands
}
shopt -qs extglob
fn_hide_prefix='__'
allowed_commands="$(declare -f | sed -ne '/^'$fn_hide_prefix'.* ()/!s/ ().*//p' | tr '\n' ' ')"
complete -D -W "this should output these words when you hit TAB"
echo "waiting for commands"
while read -ep"-> "; do
history -s $REPLY
case "$REPLY" in
@(${allowed_commands// /|})?(+([[:space:]])*)) $REPLY ;;
\?) __complete ;;
*) echo "invalid command: $REPLY" ;;
esac
done
澄清:在Bash4中制作和测试
因此,“read-e”提供了readline功能,我可以调用命令、编辑输入行等。我不能以任何方式做的是让readline的制表符完成工作
我尝试了两件事:
为什么readline在脚本中使用“complete”时不能正常运行?当我在互动模式下从bash尝试它时,它会工作…在尝试了一个我知道有效的自定义完成脚本(我每天都使用它)后,遇到了相同的问题(当装配它时与您的类似),我决定窥探bash 4.1源代码,并在
bash-4.1/builtins/read.def:edit_line()中找到了这个有趣的块
:
似乎在调用readline()
之前,它会将completion函数重置为null,原因可能只有bash黑客长胡子才知道。因此,使用内置的read
执行此操作可能只是被硬编码为禁用
编辑:更多信息:在读取
内置中停止完成的包装代码发生在bash-2.05a和bash-2.05b之间。我在该版本的bash-2.05b/CWRU/changelog
文件中发现了此注释:
- edit_line(由read-e调用)现在只通过将rl_尝试的_completion_函数设置为NULL来完成readline的文件名完成,因为例如,对行上的第一个字执行命令完成并不是真正有用的
read
一起使用
EDIT2:好的,我刚刚测试了一个补丁,它似乎“起作用”。通过所有单元和注册表测试,并在使用修补bash运行时显示脚本的输出,如您所料:
$ ./tabcompl.sh
waiting for commands
-> **<TAB>**
TAB hit output should these this when words you
->
请记住,经过修补的bash必须分发或以某种方式提供给任何使用您的脚本的地方……好吧,看来我终于找到了答案,遗憾的是:实际上,通过“read-e”与readline接口时,readline并没有得到完全支持 BASH维护人员Chet Ramey给出了答案。同样的问题也被提到: 我正在用命令行解释器编写一个脚本,我可以完成大多数事情 工作(如历史等),除了一件事。文件名完成 对于某些命令来说效果很好,但是我想使用其他的补全 其他人的选择。从“真实”命令行可以很好地工作,但我不能 让它在我的“read-e,eval”循环中正常工作 你做不到`read-e'仅使用readline默认值 完成 切特 因此,除非我遗漏了什么//rant//bash将“read-e”机制作为完整、正确的CLI用户接口的手段交给程序员,否则该功能将被削弱,即使底层机制(readline)可以正常工作并与bash的其余部分完美集成//end rant// 我已经向freenode中的#bash的好心人提出了这个问题,有人建议我尝试使用像or这样的Readline包装器 最后,我昨天通过邮件联系了切特本人,他确认这是设计的,他不想将其作为可编程完成的唯一用例更改为“读取”,即向脚本用户提供一个命令列表,这看起来并不是花时间做这件事的令人信服的理由。不过,他表示,如果有人真的做了这项工作,他肯定会看看结果 IMHO没有考虑到使用5行代码实现完整CLI的能力的价值,这在很多语言中都是可能的,这是一个错误
在这种情况下,我认为西蒙的答案是明智和正确的。我将尝试按照你的步骤,也许运气好的话,我会得到更多的信息。然而,我已经有一段时间没有使用C语言了,我假设我必须掌握的代码数量不会是微不足道的。但无论如何,我会试试。如果你要付出那么多的努力,为什么不增加一两把叉子的成本,使用一些能够提供你想要的一切的东西呢 或者正如手册页所说: 在shell脚本中,在一个脚本中使用
rlwrap
−“放炮”模式代替read
我不确定这是否准确地回答了OP的问题,但我正在搜索可以使用哪个命令,以获得已知可执行命令的默认
bash
tab完成(按照$PATH
),如按tab键时所示。由于我第一次被带到这个问题(我认为是相关的),我想我应该在这里贴一张便条
例如,在我的系统上,键入lua
,然后TAB给出:
。。。这正是我想要的:)
希望这对某人有所帮助,干杯 我已经为同一问题挣扎了一段时间,我想我有一个可行的解决方案,在我的现实世界中,我正在使用compgen生成可能的补全。但这里有一个例子说明了核心逻辑:
#!/bin/bash
set -o emacs;
tab() {
READLINE_LINE="foobar"
READLINE_POINT="${#READLINE_LINE}"
}
bind -x '"\t":"tab"';
read -ep "$ ";
设置emacs选项以启用键绑定,将tab键绑定到函数,更改READLINE\u LINE
以在提示后更新该行,并设置READLINE\u POINT
以反映该行新的较长长度
在我的用例中,我采取行动
--- bash-4.1/builtins/read.def 2009-10-09 00:35:46.000000000 +0900
+++ bash-4.1-patched/builtins/read.def 2011-01-20 07:14:43.000000000 +0900
@@ -394,10 +394,12 @@
}
old_alrm = set_signal_handler (SIGALRM, sigalrm);
add_unwind_protect (reset_alarm, (char *)NULL);
+/*
#if defined (READLINE)
if (edit)
add_unwind_protect (reset_attempted_completion_function, (char *)NULL);
#endif
+*/
falarm (tmsec, tmusec);
}
@@ -914,8 +916,10 @@
if (bash_readline_initialized == 0)
initialize_readline ();
+/*
old_attempted_completion_function = rl_attempted_completion_function;
rl_attempted_completion_function = (rl_completion_func_t *)NULL;
+*/
if (itext)
{
old_startup_hook = rl_startup_hook;
@@ -923,8 +927,10 @@
deftext = itext;
}
ret = readline (p);
+/*
rl_attempted_completion_function = old_attempted_completion_function;
old_attempted_completion_function = (rl_completion_func_t *)NULL;
+*/
if (ret == 0)
return ret;
#!/bin/bash
which yum && yum install rlwrap
which zypper && zypper install rlwrap
which port && port install rlwrap
which apt-get && apt-get install rlwrap
REPLY=$( rlwrap -o cat )
order=$(rlwrap -p Yellow -S 'Your pizza? ' -H past_orders -P Margherita -o cat)
$ lua<TAB>
lua lua5.1 luac luac5.1 lualatex luatex luatools
$ compgen -c lua
luac
lua5.1
lua
luac5.1
luatex
lualatex
luatools
#!/bin/bash
set -o emacs;
tab() {
READLINE_LINE="foobar"
READLINE_POINT="${#READLINE_LINE}"
}
bind -x '"\t":"tab"';
read -ep "$ ";