编程与软件工程brennan.io编辑精选
用 C 写一个 shell(2015)
Write a Shell in C (2015)
2016 — 2024,它一次次回到首页
黑点是上首页(≥ 50 分)的那次投稿,空心点是没冲上去的投稿,点越大分数越高。
导读
这篇文章是 Brennan 的 C 语言教程,讲如何从零写一个简单的 Unix shell:读取并解析命令、用 fork/exec/wait 启动进程,并处理一些内建命令。它用可运行的示例让人看到,shell 与内核的交互其实只依赖少数系统调用,而大量复杂度来自字符串处理。
为什么经久不衰:它把看似神秘的 shell 拆解成少量 Unix 系统调用和可读代码,是理解 fork/exec 与系统编程的经久不衰的入门材料。
HN 评论精选
shell 核心只依赖少量 Unix 系统调用,复杂度主要在字符串处理。
如果想看用 Python 写的相当完整的 shell(约 1.1 万行),可以看 Oilshell。这篇文章好在展示了启动进程归根结底就是 fork()、exec()、wait() 等系统调用。我的 shell 支持函数调用、循环、条件、管道、子 shell、命令替换、重定向、here docs 等;这些功能只需要少量额外系统调用(dup2()/fcntl() 操作文件描述符、pipe()、open()/read()/write()/close()),说明 Unix 很简单,shell 的复杂度主要在字符串处理,而不在与内核交互。
chubot查看英文原文
If you want to see a pretty complete shell in a higher level language (Python, 11K lines of code), check out: https://github.com/oilshell/oil/ And a blog here: http://www.oilshell.org/ (index: http://www.oilshell.org/blog/2016/11/20.html) This article is good in that it shows that starting processes boils down to the system calls fork(), exec(), wait(), etc. My shell has function calls, loops, conditionals, pipelines, subshells, command substitution, redirects, here docs, etc. (The code has some messiness, but the architecture is clean IMO.) It turns out that these features require just a few more system calls -- dup2() and fcntl() to manipulate file descriptors, pipe(), and open() / read() / write() / close(). It's a good reminder of how simple Unix is. The complexity of the shell is basically all in string processing, and not in interfacing with the kernel (although the interactive parts of the shell do complicate things). These system calls are all available in Python, so the code ends up being comparable to what you would write in C (and I'm in the process of porting to C++ now that the architecture has settled.)
指出 realloc 失败泄漏、sizeof(char) 无作用、size_t 与 strtok 等 C 代码细节。
这篇文章写得很好,作者似乎已经利用了互联网的代码审查能力(文中提到 Reddit 评论带来的改进)。我有强迫性 C 代码审查症,所以快速提几点:“x = realloc(x, ...)”这种模式不好,失败时会泄漏原内存,值得在教程中提及并修复;一般不建议用 sizeof(char) 来缩放字符串分配,因为它总是 1;建议多用 const 和 static;表示大小的地方多用 size_t 而不是 int,更清楚也更安全;strtok() 不总是最佳选择,但这里基本在做它设计要做的事。
unwind查看英文原文
This is very well written, and it seems the author has already used the great code reviewing powers of the Internet (there are references to improvements from Reddit comments). I suffer from compulsory C review disorder, so just a few quick points: - The pattern "x = realloc(x, ...)" is a bad idea, it leaks the original memory on failure. Since the code seems to car about its memory management (and since it's a tutorial), I think this is worth mentioning (and fixing). - I generally recommend against scaling string allocations by sizeof (char); that's always 1 so it doesn't do anything. Some people seem to feel that it's part of a general usage pattern that makes the intent more clear, though. - I would recommend more "const" and "static", but some people seem to not care. - I would use more size_t rather than int for things that are sizes. This is more clear, and also safer since it's unsigned. - Using strtok() is not always the best choice, it has issues, but here it's basically doing what it was designed to do I guess.
推荐 MIT 6.828 shell 练习作为互补,聚焦执行、重定向和管道。
这篇文章的一个好补充是 MIT 6.828 的 shell 练习:它提供命令循环和解析,让你实现命令执行、重定向和管道。
moyix查看英文原文
A nice complement to this article is the MIT 6.828 shell exercise. It provides the command loop and parsing for you, and then has you implement command execution, redirection, and pipes. https://pdos.csail.mit.edu/6.828/2016/homework/xv6-shell.html
malloc 应使用 sizeof(*buffer) 保持类型一致,避免 sizeof 类型错误。
请不要写 char *buffer = malloc(sizeof(char) * bufsize);,sizeof(char) 永远都是 1。更重要的是,不要写 <type> *buffer = malloc(n * sizeof(<type>));,这常导致新类型配旧类型 sizeof 的 bug。应写成 <type> *buffer = malloc(n * sizeof(*buffer));,这样两边总是一致的。
nanis查看英文原文
> char *buffer = malloc(sizeof(char) * bufsize); Please don't do this. sizeof(char) is always and everywhere 1. More importantly, don't do: <type> *buffer = malloc(n * sizeof(<type>)); which frequently leads to bugs of the form <new_type> *buffer = malloc(n * sizeof(<old_type>)); Instead, use <type> *buffer = malloc(n * sizeof(*buffer)); which will always keep both sides consistent. PS: See also http://c-faq.com/charstring/wchar.html
历次讨论
同类还值得读
开源应用架构
The Architecture of Open Source Applications
《开源软件架构》(AOSA)是一本在线免费书,邀请知名开源项目的作者亲自剖析其内部设计,涵盖 SQLAlchemy、LLVM、Audacity、Apache、Bash 等系统。
编程与软件工程上首页 9 次 · 2011–2024aosabook.org编辑精选编程语言简史:简短、不完整且多半错误
A Brief, Incomplete, and Mostly Wrong History of Programming Languages
一篇以戏谑、故意不准确的方式回顾编程语言史的博客文章,用夸张轶事和讽刺定义串起 Lisp、C、C++、Java、JavaScript、PHP 等语言。
编程与软件工程上首页 8 次 · 2009–2021james-iry.blogspot.comSQLite 是如何测试的
How SQLite is tested
SQLite 官方文档页,系统介绍 SQLite 的测试体系:多种测试方法(TCL 测试、模糊测试、回归测试、静态分析等)和海量测试用例,展示了这个小型开源项目如何靠极致测试获得…
编程与软件工程上首页 8 次 · 2009–2025sqlite.org编辑精选高级编程语言(2009)
Advanced programming languages (2009)
Matt Might 的经典文章,按用途推荐“高级编程语言”:如果追求就业就选主流语言,如果追求表达力、学术研究或创业,则推荐 Haskell、OCaml、Scala 等函数式语…
编程与软件工程上首页 8 次 · 2009–2022matt.might.net我的 Forth 与栈机器经历
Yosefk - My history with Forth & stack machines
作者以亲身经历回顾了使用 Forth 语言和栈式机器的历程:既赞叹其简洁优雅、代码量小、可自举的优点,也坦率指出栈操作在实际编程中的痛苦,以及 Forth 社区文化中的问题。
编程与软件工程上首页 8 次 · 2010–2024yosefk.com编辑精选