在尝试了一个我知道有效的自定义完成脚本(我每天都使用它)并遇到了同样的问题(在与你的类似的情况下安装它时),我决定窥探 bash 4.1源码,在bash-4.1/builtins/read.def:edit_line()发现了这个有趣的块:
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;
rl_startup_hook = set_itext;
deftext = itext;
}
ret = readline (p);
rl_attempted_completion_function = old_attempted_completion_function;
old_attempted_completion_function = (rl_completion_func_t *)NULL;
似乎在调用readline() 之前,由于某种原因,它会将完成函数重置为空,而只有一个 bash-hacking 长胡子可能知道。因此,使用内置的read 执行此操作可能只是被硬编码为禁用。
编辑:更多内容:在 bash-2.05a 和 bash-2.05b 之间发生了在 read 内置函数中停止完成的包装代码。我在那个版本的bash-2.05b/CWRU/changelog 文件中找到了这个注释:
- edit_line(由 read -e 调用)现在只是通过将 rl_attempted_completion_function 设置为 NULL 来完成 readline 的文件名完成,因为例如,对行上的第一个单词执行命令完成并不是很有用
我认为这是一个遗留的疏忽,而且由于可编程完成已经走过了漫长的道路,你所做的事情是有用的。也许你可以要求他们重新添加它,或者只是自己修补它,如果这对你正在做的事情是可行的。
恐怕除了您目前提出的解决方案之外,我没有其他解决方案,但至少我们知道为什么它不适用于 read。
EDIT2:对,这是我刚刚测试的一个似乎“有效”的补丁。通过所有单元和注册测试,并在使用修补的 bash 运行时显示脚本的输出,如您所料:
$ ./tabcompl.sh
waiting for commands
-> **<TAB>**
TAB hit output should these this when words you
->
正如您将看到的,我只是注释掉了这 4 行和一些计时器代码,以在指定 read -t 并发生超时时重置 rl_attempted_completion_function 并且不再需要超时。如果您要向 Chet 发送一些东西,您可能希望首先删除整个 rl_attempted_completion_function 垃圾邮件,但这至少可以让您的脚本正常运行。
补丁:
--- 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;
请记住,修补过的 bash 必须以某种方式分发或以某种方式在人们使用您的脚本的任何地方提供...