一、ls命令实现总结
本程序要实现的功能是ls命令和ls命令-a(列出所有的文件)、-l(列出文件的详细信息)、-c(按照文件的ctime排序)、-g(输出除所有者外的所有信息)、-U(不排序输出文件)、-R(递归输出路径下所有文件)、-r(按名字排序后逆置输出)、-i(输出文件的i-node节点)。以及一些参数的简单组合,如:-al、la等。
大体思路就是将从终端传进来的参数和路径进行判断,找出参数列表和路径列表,经当前工作目录转到传进来的路径下,将路径下的所有文件读取到文件中,然后对参数列表进行解析,不同的参数输出不同的文件信息。对于其他参数没有什么难度,就是加上一定的判断条件然后对链表中的文件的参数进行选择性的输出就可以实现功能。难点在于如何将文件夹中的所有文件都存进内存再解析显示出来。
思路一:开辟两条链表,链表一存储当前路径下的所有文件,链表二存储当前路径下所有文件夹下的文件存起来,同时将路径信息和存起来,将链表一释放,然后按照路径信息将链表二中的文件信息分路径打印出来。依次循环解析到不含文件夹为止。
思路二:写一个函数show_all(),传进去路径信息和存有文件列表信息的链表,然后先将链表信息输出,再对链表进行遍历判断,当判断到该节点为文件夹时就将文件夹下所有信息都存进另一条链表然后在原路径基础上加上该文件夹名字组成新路径,将该新路径和新链表作为函数参数传进show_all()递归。递归结束条件为传进来的链表遍历完。
符几张效果图:
然而思路一在真正编码的时候出现了好多麻烦,第一个麻烦就是一个文件夹下可能存在好多的文件夹,要将这些文件夹全部都存进一条链表很容易,但是要将这些文件夹下的文件和文件夹再存起来那么就不太容易了,首先路径的转换就搞的人很头疼。第二个麻烦在于每个文件夹和文件在存的时候还要对应存储一个路径信息,而且好多路径信息都是没有必要的,但还是必须得存储起来,这就让人感觉到有点淡淡的蛋疼。第三个麻烦就是循环的条件也不太好控制。所以只能走第二条思路了,第二条思路在编码的时候确实没有任何难度,事实证明这条路确实是可行的,只是有些消耗内存,运行速度也略显捉急。(ps:贴上代码 )
二、myshell程序总结
祭奠linux C进程部分的学习是自己实现一个shell程序--myshell,最终的要求是要实现后台运行、管道、重定向输入输出和cd命令等功能。
因为有了之前书写ls和课程设计的经验这次写起来myshell略显得心应手。本次程序存储命令的数据结构为单向非循环链表,完成了链表相关操作。按照书上的提示完成了寻找命令、解析命令、执行命令等函数。
具体实现:解析终端传进来的命令从空格处断开,将每段存入链表的每个节点中,然后将命令分为可执行程序和参数信息,将解析的可执行程序放在命令数组的第零个元素中,将命令所用的参数依次放在命令数组的其他元素中,将最后一个元素赋值为NULL,再在./、/bin/、/usr/bin/目录下查找命令若找到则调用fork函数创建一个子进程再用execvp函数将解析的命令和参数通过数组元素和数组的形式传进去执行命令,若未找到则输出错误提示。
1)、后台运行:当检测到有后台运行符&存在时就在执行命令函数中父进程不等待子进程自己先结束,然后再在主函数中等待子进程结束,最后当用户输入回车是输出后台运行的进程号和已完成的提示。
2)、重定向输出:当检测到有重定向输出符号时打开要重定向过去的文件(若不存在则先创建)然后将要重定向过去的文件的标识符复制为标准输出的文件标识符,然后再调用execvp函数执行命令。
3)、重定向输入:当检测到有重定向输入符号时打开要重定向的文件(不存在则提示错误),然后将文件描述符复制为标准输入文件描述符,调用execvp函数执行命令。
4)、管道实现:当检测到有管道符存在时将命令分为两个数组,管道符以前为一个数组,管道符以后为一个数组,然后将管道符处赋值为NULL,开辟子进程,让子进程执行前边的命令,将执行结果写入/tmp/myshell文件中,然后父进程等待子进程结束,父进程时打开/tmp/myshell文件,将文件符复制为标准输入,然后执行后门命令。
5)、cd命令:或许cd命令是最好实现的了,把从命令行传进来的命令进行判断然后调用chdir函数将工作目录转到传进来的参数路径中去,若不存在则输出错误提示。
在程序编写过程最痛苦的事莫过于段错误了,因为GDB调试用的还不是很灵活,所以在调试的时候很痛苦,本身那个BUG隐藏的也比较深,跟踪调试都要看好几遍才能找到。后来求助于学长才解决了这个BUG,也学到了一些GDB调试的技巧。(ps:贴上代码)
附上几张效果图: