这周要写一个小项目,利用《linux C 编程实战》第6章的内容实现一个简单的 ls
命令,写的时候出现很多问题,现在将问题总结一下。
要实现的ls命令需要实现 -l, -a , -A 等参数。
我们在终端测试一下系统的ls命令:
可以发现系统的ls可以根据终端的宽度来调整输出列数,而不至于输出的内容由于终端大小的限制显示不全。
如果想要实现类似的功能,首先需要获取终端的宽度,然后计算输出文件列表的最大列数,最后按列将文件输出到屏幕上。
####终端宽度的获取
查了很多,发现书上提到的 int ioctl(int fd, int cmd, ...)
可以实现这个功能, 先放出代码:
// 获取终端宽度
int get_ter_size (void)
{
struct winsize w;
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
return w.ws_col;
}
ioctl
可以控制特殊设备文件的属性,第一个参数是一个以及打开的文件描述符,STDOUT_FILENO
是标准输出的POSIX 名称,他的文件描述符是1,可以在 unistd.h
找到它的宏定义。使用man 2 ioctl_tty
可以查询到其他两个参数的信息:
TIOCGWINSZ
是一个获取终端大小的命令,w是一个struct winsize
,其中的 w.ws_col
就存储了我们想得到的终端宽度。
计算输出列表的最大列数
没想出来有什么比较好的方法来通过已经给定的一系列字符串和一个限制宽度来求出在这个宽度限制内输出的最大列数。
所以最后决定暴力穷举,将列数从大到小一个一个的尝试。
int Cal_Print(char b[][NAME_MAX + 10], int a[], int n) // 暴力运算, 求出打印的列数
{
// b 是一个二维数组,存储了要计算宽度的文件名
int t = get_ter_size(); // 终端宽度
int i = n < MAX_C ? n : MAX_C; // 设定最大列数初始值
int length; // 计算字符串长度
for (int j