C 语言实现 Linux cat 命令

用 C 语言模拟实现 Linux 的 cat 命令,支持查看单个或多个文件内容。 代码实现 /* * 模拟 Linux cat 命令 * 用法:./mycat file1 [file2 ...] */ #include <stdio.h> #include <stdlib.h> /* 将文件内容复制到输出流 */ void file_copy(FILE *in, FILE *out) { int c; while ((c = getc(in)) != EOF) putc(c, out); } int main(int argc, char *argv[]) { FILE *fp; if (argc == 1) { /* 无参数时,从标准输入读取(与 cat 行为一致) */ file_copy(stdin, stdout); } else { while (--argc > 0) { if ((fp = fopen(*++argv, "r")) == NULL) { fprintf(stderr, "cat: %s: 无法打开文件\n", *argv); return 1; } file_copy(fp, stdout); fclose(fp); } } return 0; } 要点 getc / putc 逐字符读写,适合小文件;大文件建议用 fread / fwrite 按块读写 argc == 1 时从 stdin 读取,使程序支持管道:echo hello | ./mycat 错误信息输出到 stderr,不会混入正常输出 编译运行 gcc -o mycat mycat.c ./mycat file1.txt file2.txt

2015年3月13日 · 1 分钟 · Jid

Shell编程:bash内部命令

bash命令解释套装程序包含了一些内部命令。内部命令在目录列表时是看不见的,它们由Shell本身提供。常用的内部命令有:echo, eval, exec, export, readonly, read, shift, wait和点(.)。下面简单介绍其命令格式和功能。 1.echo 命令格式:echo arg 功能:在屏幕上显示出由arg指定的字串。 2.eval 命令格式:eval args 功能:当Shell程序执行到eval语句时,Shell读入参数args,并将它们组合成一个新的命令,然后执行。 3.exec 命令格式:exec命令参数 功能:当Shell执行到exec语句时,不会去创建新的子进程,而是转去执行指定的命令,当指定的命令执行完时,该进程(也就是最初的Shell)就终止了,所以Shell程序中exec后面的语句将不再被执行。 4.export 命令格式:export变量名 或:export变量名=变量值 功能:Shell可以用export把它的变量向下带入子Shell,从而让子进程继承父进程中的环境变量。但子Shell不能用export把它的变量向上带入父Shell。 注意:不带任何变量名的export语句将显示出当前所有的export变量。 5.readonly 命令格式:readonly变量名 功能:将一个用户定义的Shell变量标识为不可变。不带任何参数的readonly命令将显示出所有只读的Shell变量。 6.read 命令格式:read变量名表 功能:从标准输入设备读入一行,分解成若干字,赋值给Shell程序内部定义的变量。 7.shift语句 功能:shift语句按如下方式重新命名所有的位置参数变量,即$2成为$1,$3成为$2…在程序中每使用一次shift语句,都使所有的位置参数依次向左移动一个位并使位置参数$#减1,直到减到0为止。 8.wait 功能:使Shell等待在后台启动的所有子进程结束。wait的返回值总是真。 9.exit 功能:退出Shell程序。在exit之后可有选择地指定一个数位作为返回状态。 10.“.”(点) 命令格式:. Shell程序文件名 功能:使Shell读入指定的Shell程序文件并依次执行文件中的所有语句。

2015年3月12日 · 1 分钟 · Jid

值得阅读源码的开源项目推荐

学习优秀的代码风格和架构设计,是提升编程能力的有效途径。以下是几个代码质量高、适合阅读学习的开源项目: C 语言项目 项目 特点 适合学习 nginx 高性能 Web 服务器 事件驱动架构、内存池、模块化设计 Linux Kernel 操作系统内核 数据结构、并发控制、底层编程 SQLite 嵌入式数据库 SQL 解析、B 树实现、事务管理 Redis 内存数据库 数据结构、网络编程、单线程高性能 mxml 小型 XML 解析库 代码精简、接口设计 lighttpd 轻量 Web 服务器 网络编程、事件处理 C++ 项目 项目 特点 适合学习 LLVM 编译器基础设施 现代 C++、编译原理、架构设计 Chromium 浏览器引擎 大型项目组织、多进程架构 阅读建议 从小项目开始(mxml、lighttpd),再读大项目 先理解整体架构,再深入具体模块 带着问题读代码:它怎么解决某个问题的?

2015年3月11日 · 1 分钟 · Jid

C/C++ 安全释放指针的方法

代码如下: #include <stdio.h> #include <stdlib.h> #define SAFE_FREE(ptr) do { free(ptr); ptr = NULL; } while(0) #define SAFE_DEL(ptr) do { delete ptr; ptr = NULL; } while(0) #define SAFE_DELARR(ptr) do { delete [] ptr; ptr = NULL; } while(0) int main(int argc, char **argv) { char* p = new char[100]; SAFE_DELARR(p); //system("pause"); return 0; } 实现安全释放指针的机制正是上面的三个宏,其本质就是在释放了指针后,一定要及时地把指针置为NULL。宏体用 do { ... } while(0) 包裹,避免在 if/else 语句中使用时出现编译错误。 注意:上面的代码包括了delete, delete[], 因此是段 C++代码。C的话只要第一个宏即可。

2015年3月10日 · 1 分钟 · Jid

Linux Locale 详解:从原理到配置

Locale 是 Linux 国际化(i18n)的核心概念。理解它,是解决中文显示、输入问题的基础。 一、为什么需要设定 Locale 设定 Locale 与浏览中文网页无关。 即使 Locale 设为 en_US.ISO-8859-1,只要有合适的字体,浏览器照样能显示中文——浏览器自己会检测网页编码并选择对应的字体渲染。 但 Locale 与"写中文"直接相关。 如果你需要在终端输入中文、让程序识别中文作为有效字符、让系统消息显示为中文,就必须设定正确的 Locale。 简单说:看中文靠字体,写中文靠 Locale。 二、什么是 Locale Locale 是根据用户的语言、国家/地区和文化传统定义的软件运行时语言环境。它涵盖了日常使用的方方面面: 类别 变量 控制内容 字符分类 LC_CTYPE 哪些字符是合法的、大小写转换、标点分类 排序规则 LC_COLLATE 字符串比较和排序顺序 消息语言 LC_MESSAGES 提示信息、错误信息、菜单的语言 时间格式 LC_TIME 日期时间的显示格式 数字格式 LC_NUMERIC 小数点、千分位分隔符 货币格式 LC_MONETARY 货币符号和格式 姓名格式 LC_NAME 姓名书写方式 地址格式 LC_ADDRESS 地址书写方式 电话格式 LC_TELEPHONE 电话号码格式 度量衡 LC_MEASUREMENT 公制/英制 纸张大小 LC_PAPER A4 / Letter 等 概述 LC_IDENTIFICATION Locale 自身的元数据 Locale 定义文件存放在 /usr/share/i18n/locales/,如 zh_CN、en_US 等。 ...

2015年3月9日 · 2 分钟 · Jid

Solaris 创建用户

步骤 # 1. 创建主目录 mkdir -p /export/home/username # 2. 创建用户(指定 Shell 和主目录) useradd -s /usr/bin/bash -d /export/home/username username # 3. 设置密码 passwd username # 4. 设置主目录权限 chown username /export/home/username # 5. 验证 tail -1 /etc/passwd 常用 useradd 选项 选项 作用 -s 指定登录 Shell -d 指定主目录 -g 指定主组 -G 指定附加组 -u 指定 UID -m 自动创建主目录(部分版本支持) 删除用户 userdel username # 保留主目录 userdel -r username # 同时删除主目录 参考:Solaris System Administration Guide

2015年3月8日 · 1 分钟 · Jid

man 命令:在线手册页使用指南

基本用法 man [章节号] 命令名 章节说明 章节 内容 示例 1 用户命令 man 1 ls 2 系统调用 man 2 open 3 C 库函数 man 3 printf 4 设备和特殊文件 man 4 null 5 配置文件格式 man 5 passwd 7 杂项(协议、字符集等) man 7 ascii 8 系统管理命令 man 8 mount 不指定章节号时,man 会按顺序搜索,返回第一个匹配结果。 常见陷阱 man printf # 显示第 1 章:shell 命令 printf man 3 printf # 显示第 3 章:C 库函数 printf 两者完全不同。查 C 函数时务必指定章节号 3。 实用技巧 # 搜索手册页(不知道完整名称时) man -k "copy files" # 等同于 apropos # 在 man 页面内搜索 # 按 / 输入关键词,n 下一个,N 上一个 # 查看手册页存储路径 man --path # 以网页方式打开(部分系统支持) man -H firefox open

2015年3月6日 · 1 分钟 · Jid

touch 命令:创建空文件或更新时间戳

功能 touch 有两个用途: 创建空文件 — 如果文件不存在,创建一个大小为 0 的空文件 更新时间戳 — 如果文件已存在,更新其访问时间和修改时间为当前时间 常用示例 # 创建空文件 touch newfile.txt # 同时创建多个文件 touch file1.txt file2.txt file3.txt # 更新已有文件的时间戳 touch existing.txt # 只更新访问时间(不修改 mtime) touch -a file.txt # 只更新修改时间(不修改 atime) touch -m file.txt # 设置为指定时间(格式:YYYYMMDDhhmm) touch -t 202604011200 file.txt

2015年3月5日 · 1 分钟 · Jid

Linux/Unix 修改 PATH 环境变量

问题 安装软件后执行命令提示 command not found,但程序确实已经安装。原因是程序所在目录不在 PATH 搜索路径中。 查看当前 PATH echo $PATH 输出是以冒号分隔的目录列表,Shell 会依次在这些目录中查找可执行文件。 添加路径 Bash(大多数 Linux 默认) 编辑 ~/.bashrc 或 ~/.profile,添加: export PATH=$PATH:/新路径 例如: export PATH=$PATH:/usr/local/bin:$HOME/bin C Shell 编辑 ~/.cshrc,添加: set path=($path /usr/local/bin $home/bin) 使配置生效 source ~/.bashrc # Bash source ~/.cshrc # C Shell 或重新登录。 全局设置(所有用户) Bash:编辑 /etc/profile 或 /etc/profile.d/ 下创建脚本 所有 Shell:编辑 /etc/environment(格式为 PATH="/usr/local/sbin:/usr/local/bin:...")

2015年3月4日 · 1 分钟 · Jid

获取整数的最大值最小值的宏定义及可能出现的问题

在C/C++编程中时常需要使用整数的最大值最小值,通常这两个常用是跟平台和操作系统有关的,不同的平台会有不同的值,因此可移植的办法就是使用库函数提供的常量定义。 (1)类似的常量定义在limits.h和float.h头文件中,可以查看源文件获取类似常量的使用办法。在头文件中,整数的最值通常是这样的名字:INT_MAX, INT_MIN,直接使用即可。 (2)当然这两个最值完全可以通过编程实现: #define MAX_INT ((unsigned)(-1)>>1) #define MIN_INT (~MAX_INT) 但是,这两个宏仅仅是没有类别的符号,在使用的时候会陷入困境。看下面这段C++程序,输出结果出乎意料。 #include <iostream> #include <limits> #define MAX_INT ((unsigned)(-1)>>1) #define MIN_INT (~MAX_INT) int main() { std::cout << "max_int: " << MAX_INT << "\n" << "min_int: " << MIN_INT << std::endl; } 输出结果是 max_int: 2147483647 min_int: 2147483648 结果怎么会是这样呢? 问题出在类型上:~MAX_INT 中 MAX_INT 是 unsigned 表达式,对 unsigned 取反得到的还是 unsigned,值为 0x80000000(即无符号的 2147483648)。cout 按 unsigned 输出,所以显示的不是 -2147483648。正确的办法是强制转换: cout << "max_int: " << (int)MAX_INT << "\n" << "min_int: " << (int)MIN_INT << endl; 当然最好的办法还是不要使用#define这个宏,不安全。 (3)针对上面的问题,一个比较好的解决办法是,直接定义常量: const int MAX_INT = ((unsigned)(-1))>>1; const int MIN_INT = ~MAX_INT; 注意:这里的 MAX_INT 是 const int(有符号),与方案 (2) 中 #define 展开后的 unsigned 表达式不同。~MAX_INT 对有符号 int 取反,结果为 -2147483648,printf 用 %d 输出即可正确显示。 ...

2015年3月3日 · 1 分钟 · Jid