我正在努力在linux上创建一个简单的shell。我可以创建一些东西来学习如何使用基本系统调用。
方案: 命令中的用户类型,按Tab键(因此shell自动完成其命令),弹出自动完成的命令(或建议),用户按Enter键,命令evals并执行。
就像在bash中一样。
我已经想出了如何进行篡改,将命令转换为令牌,使用管道和东西执行它。我无法弄清楚的是输入部分。即那些标签击键。
我知道我有什么选择:
getc()
- 分别获取每个字符,将其存储在缓冲区中。无法弄清楚如何获得标签击键,因为它会暂停执行,直到它看到' \ n'或Ctrl + D.有点贵,因为命令中的每个字符都会有1个getc()。另外,我将不得不处理缓冲区重新分配,摊销......嘘...... scanf("%s")
- 太担心缓冲区溢出。无法获得我不想要的那些标签击键。暂停执行read()
(来自unistd.h) - 可能是我不想要的。但我在这里看到的人说,用它来做这件事真的很痛苦。我检查了。它是。getline()
- 无法获得标签击键。我研究了bash源代码,看看它是如何处理输入的,以及OH MY GOD。有450行代码专门用来做这个简单的事情(input.c文件)。
真的没有比这更简单的解决方案吗?我不想使用ncurses,我不关心可移植性,我只是想实现一个目标:获取用户输入并知道何时按Tab键。尽可能少地努力做到优雅。
答案 0 :(得分:4)
为了在没有任何延迟或缓冲的情况下从终端获得单独的击键,您必须将其模式从cooked更改为raw。您可以使用tcsetattr()
中定义的<termios.h>
函数执行此操作。有关详细信息,请查看手册页。
将终端设置为适当的模式后,最好使用read()
系统调用从终端句柄读取数据。
请注意,您必须处理回显用户输入,如果您开始执行TAB扩展等高级内容,则需要实现大多数行编辑器...更不用说处理字符组成和其他奇怪的终端给你免费的。正如Basile所说,没有简单的手工解决方案,但潜入这个混乱将是非常有益的!
如果您需要时间并且这是一个受让人,请使用readline()
并首先实现shell的其余部分。这将是很多工作。如果你还敢,你可以随时回到这里。
答案 1 :(得分:4)
要获得某些特定的自动完成功能,您可以使用bash
使用的GNU readline库。
如果您关心终端全屏I / O(例如vi
或emacs
),请考虑GNU ncurses。
终端是相当复杂和神秘的东西(因为他们想模仿上个世纪奇怪的物理电传类型)。通常,一些行处理是在内核中为tty的line discipline完成的。阅读tty demystified网页。因此,la termios(3)的低级别功能使用起来很神秘,您应该更喜欢readline
或ncurses
等库。
所以,不,没有用于自动完成的终端I / O的简单解决方案,因为ttys是复杂的东西。另见tty(4)&amp; tty_ioctl(4)&amp; pty(7)
您还可以使用strace(1)来理解所有复杂的system calls。一个互动的外壳。