Linux ls 命令实现(简化版)

在学习linux系统编程的时候,实现了ls命令的简化版本。

实现的功能如下

1. 每种文件类型有自己的颜色 (- 普通文件, d 目录文件, l 链接文件, c 字符设备文件, b 快设备文件, p 管道文件, s socket文件。共7种)

2. 支持的参数有 -hali (a: 显示隐藏文件, i: 显示inode节点号,l: 以列表形式显示文件的详细信息,h: 人类可读的文件大小显示)

3. 对于符号链接,显示出其指向的文件。

4. 设备文件,显示主设备号和次设备号,不显示文件大小(设备文件没有大小属性,对于设备号,不同的 *nix 存储方式可能不同)

5. 文件按照字典序排序显示。

程序说明

1. 程序中大部分使用的都是linux系统调用和c标准库函数,只有文件排序用到了c++ stl 的vector和sort算法(好吧,我又偷懒了!)

2. stat(): 获取文件的详细信息,inode, 权限, 连接数, uid, gid, size, time 等

opendir(), readdir(), closedir(): 读取目录信息

程序编译运行(见下图)

程序源码

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#include <dirent.h>
#include <grp.h>
#include <pwd.h>

// c++
#include <vector>
#include <algorithm>
#include <string>
using namespace std;

#define BUF_SIZE 1024

#define COLOR_R	(char*)"\33[0m"
#define COLOR_D	(char*)"\33[01m\33[34m"
#define COLOR_L	(char*)"\33[01m\33[36m"
#define COLOR_P	(char*)"\33[40m\33[33m"
#define COLOR_B	(char*)"\33[40m\33[33m"
#define COLOR_C	(char*)"\33[40m\33[33m"
#define COLOR_S	(char*)"\33[02m\33[35m"
#define RESET_CLOLR	(char*)"\33[0m"

int get_option(const char *opt);
int show_ls();
int show_ls_one_path(const char *path);
int show_ls_file(const char *path, const char *name);
int show_ll_part(struct stat *p_stat, int bHuman);
void to_humen_size(char *buf, off_t size);
char get_file_type(mode_t st_mode);
void get_mode(char *buf, mode_t st_mode);

// global var
enum EOPT
{
	E_a, E_i, E_l, E_h, E_num
};
int g_opt[E_num] = {0}; // order: -ailh
char *g_scolor;
vector<string> gv_path;

/* ls: ./a.out argv... */
int main(int argc, char const *argv[])
{
	int i;
	for (i = 1; i < argc; ++i)
	{
		if (‘-‘ == argv[i][0])
		{
			if (-1 == get_option(argv[i]+1))
			{
				fprintf(stderr, "bad option!\n");
				return 1;
			}
		}
		else
		{
			gv_path.push_back(argv[i]);
		}
	}

	if (0 == gv_path.size())
	{
		gv_path.push_back(".");
	}

	show_ls();

	return 0;
}

/* -ailh */
int get_option(const char *opt)
{
	while (*opt != ‘\0‘)
	{
		switch (*opt)
		{
			case ‘a‘:
				g_opt[E_a] = 1;
				break;
			case ‘i‘:
				g_opt[E_i] = 1;
				break;
			case ‘l‘:
				g_opt[E_l] = 1;
				break;
			case ‘h‘:
				g_opt[E_h] = 1;
				break;
			default:
				return -1;
		}
		opt++;
	}
	return 0;
}

int show_ls()
{
	for (vector<string>::iterator it = gv_path.begin();
		 it != gv_path.end(); ++it)
	{
		show_ls_one_path(it->c_str());
	}
	return 0;
}

int show_ls_one_path(const char *path)
{
	DIR *dir;
	dir = opendir(path);
	if (NULL == dir)
	{
		// not a dir
		if (ENOTDIR == errno)
		{
			char *p = rindex((char *)path, ‘/‘);
			if (NULL == p)
			{
				show_ls_file("./", path);
			}
			else
			{
				char sdir[BUF_SIZE] = {‘\0‘};
				strncpy(sdir, path, p-path);
				show_ls_file(sdir, p+1);
			}
			printf("\n");
			return 0;
		}
		perror(path);
		return -1;
	}

	if (gv_path.size() > 1)
	{
		fprintf(stdout, "%s:\n", path);
	}

	struct dirent *entry;
	vector<string> v_name;
	while (1)
	{
		entry = readdir(dir);
		if (NULL == entry)
		{
			break;
		}
		// show conten depends on option(g_opt)
		if (g_opt[E_a] != 1)
		{
			if (‘.‘ == entry->d_name[0])
			{
				continue;
			}
		}
		v_name.push_back(entry->d_name);
	}

	// sort filename
	sort(v_name.begin(), v_name.end());
	for (vector<string>::iterator it = v_name.begin();
		 it != v_name.end(); ++it)
	{
		show_ls_file(path, it->c_str());
	}
	fprintf(stdout, "\n");

	closedir(dir);
}

int show_ls_file(const char *path, const char *name)
{
	// stat
	char full_path[BUF_SIZE];
	int ret;
	struct stat st_stat;
	snprintf(full_path, BUF_SIZE, "%s/%s", path, name);

	ret = lstat(full_path, &st_stat);
	if (-1 == ret)
	{
		perror(full_path);
		return -1;
	}

	if (1 == g_opt[E_i])
	{
		fprintf(stdout, "%7d ", (int)st_stat.st_ino);
	}

	if (1 == g_opt[E_l])
	{
		show_ll_part(&st_stat, g_opt[E_h]);
	}
	else
	{
		get_file_type(st_stat.st_mode);//get file color actually
	}

	// show filename with color
	fprintf(stdout, "%s", g_scolor);
	fprintf(stdout, "%s  ", name);
	fprintf(stdout, RESET_CLOLR);
	if (1 == g_opt[E_l] && ‘l‘ == get_file_type(st_stat.st_mode))
	{
		// -> real file
		char real_file[BUF_SIZE];
		int path_size = readlink(full_path, real_file, BUF_SIZE);
		real_file[path_size] = ‘\0‘;
		fprintf(stdout, "->  %s", real_file);
	}

	if (1 == g_opt[E_l])
	{
		fprintf(stdout, "\n");
	}
	return 0;
}

/* show ll: mode, link num, user, group, size, time */
int show_ll_part(struct stat *p_stat, int bHuman)
{
	// mode
	char buf[BUF_SIZE];
	get_mode(buf, p_stat->st_mode);
	char file_type = buf[0];
	fprintf(stdout, "%s", buf);

	// link num
	fprintf(stdout, "  %d", p_stat->st_nlink);

	// uid gid
	// get_id_name(buf, p_stat->st_uid, "/etc/passwd");
	// fprintf(stdout, "  %s", buf);
	// get_id_name(buf, p_stat->st_gid, "/etc/group");
	// fprintf(stdout, "  %s", buf);
	struct passwd * st_user = getpwuid(p_stat->st_uid);
	fprintf(stdout, "  %s", st_user->pw_name);
	struct group * st_group = getgrgid(p_stat->st_gid);
	fprintf(stdout, "  %s", st_group->gr_name);

	// show dev id
	if (‘c‘ == file_type || ‘b‘ == file_type/* || ‘p‘ == file_type*/)
	{
		// dev_id
		int major = 0xFF00 & p_stat->st_rdev;
		major >>= 8;
		int sub	= 0x00FF & p_stat->st_rdev;
		fprintf(stdout, "\t%4d,%4d", major, sub);
	}
	else // show file size
	{
		// -h bHuman size
		off_t size = p_stat->st_size;
		if (bHuman)
		{
			char buf[BUF_SIZE];
			to_humen_size(buf, size);
			fprintf(stdout, "  %s", buf);
		}
		else
		{
			fprintf(stdout, " %9ld", size);
		}
	}

	// time
	char stime[BUF_SIZE] = {‘\0‘};
	snprintf(stime, 13, "%s", 4+ctime(&p_stat->st_ctime));
	fprintf(stdout, "  %s  ", stime);

	return 0;
}

// -h option
void to_humen_size(char *buf, off_t size)
{
	double tmp = size;
	if (size >= 1024*1024*1024)
	{
		tmp /= 1024*1024*1024;
		snprintf(buf, BUF_SIZE, "%5.1fG", tmp);
	}
	else if (size >= 1024*1024)
	{
		tmp /= 1024*1024;
		snprintf(buf, BUF_SIZE, "%5.1fM", tmp);
	}
	else if (size >= 1024)
	{
		tmp /= 1024;
		snprintf(buf, BUF_SIZE, "%5.1fK", tmp);
	}
	else
	{
		snprintf(buf, BUF_SIZE, "%6ld", size);
	}
}

char get_file_type(mode_t st_mode)
{
	if (S_ISREG(st_mode))
	{
		g_scolor = COLOR_R;
		return ‘-‘;
	}
	if (S_ISDIR(st_mode))
	{
		g_scolor = COLOR_D;
		return ‘d‘;
	}
	if (S_ISCHR(st_mode))
	{
		g_scolor = COLOR_C;
		return ‘c‘;
	}
	if (S_ISBLK(st_mode))
	{
		g_scolor = COLOR_B;
		return ‘b‘;
	}
	if (S_ISFIFO(st_mode))
	{
		g_scolor = COLOR_P;
		return ‘p‘;
	}
	if (S_ISLNK(st_mode))
	{
		g_scolor = COLOR_L;
		return ‘l‘;
	}
	if (S_ISSOCK(st_mode))
	{
		g_scolor = COLOR_S;
		return ‘s‘;
	}
	g_scolor = COLOR_R;
	return ‘-‘;
}

// -rwx---...
void get_mode(char *buf, mode_t st_mode)
{
	buf[0] = get_file_type(st_mode);

	int i;
	mode_t bit;
	for (i = 3; i > 0; --i)
	{
		bit = st_mode & 0x01;
		buf[i*3] = (1 == bit ? ‘x‘ : ‘-‘);
		st_mode >>= 1;

		bit = st_mode & 0x01;
		buf[i*3-1] = (1 == bit ? ‘w‘ : ‘-‘);
		st_mode >>= 1;

		bit = st_mode & 0x01;
		buf[i*3-2] = (1 == bit ? ‘r‘ : ‘-‘);
		st_mode >>= 1;
	}
	buf[10] = ‘\0‘;
}

Linux ls 命令实现(简化版)

时间: 2024-11-15 05:09:26

Linux ls 命令实现(简化版)的相关文章

linux ls命令教程,ls命令怎么用,全部招数都教你

linux ls命令的用法大全 学习linux这么久了,最常用的命令莫属 ls命令了,今天就总结下ls命令的用法与经验技巧. ls命令按文件大小查看文件 a.降序:ls -lsh [email protected]:~$ ls -lsh total 20M 20M -rw-r--r-- 1 moudaen 65536  20M Nov 11 17:44 Gender.war 4.0K drwxr-xr-x 2 moudaen 65536 4.0K Nov 11 17:44 test 8.0K -

Linux - Linux ls命令参数详解

-a — 全部(all).列举目录中的全部文件,包括隐藏文件(.filename).位于这个列表的起首处的 .. 和 . 依次是指父目录和你的当前目录.-l — 长(long).列举目录内容的细节,包括权限(模式).所有者.组群.大小.创建日期.文件是否是到系统其它地方的链接,以及链接的指向.-F — 文件类型(File type).在每一个列举项目之后添加一个符号.这些符号包括:/ 表明是一个目录:@ 表明是到其它文件的符号链接:* 表明是一个可执行文件.-r — 逆向(reverse).从后

Linux ls命令参数详解

下面是一个与 ls 一起使用的一些常用选项的简短列表.请记住,你可以通过阅读 ls 的说明书页(man ls)来获得选项的完整列表. -a – 全部(all).列举目录中的全部文件,包括隐藏文件(.filename).位于这个列表的起首处的 .. 和 . 依次是指父目录和你的当前目录. -l – 长(long).列举目录内容的细节,包括权限(模式).所有者.组群.大小.创建日期.文件是否是到系统其它地方的链接,以及链接的指向. -F – 文件类型(File type).在每一个列举项目之后添加一

linux ls命令

ls命令是linux下最常用的命令.ls命令就是list的缩写,缺省下ls用来打印出当前目录的清单,如果ls指定其他目录那么就会显示指定目录里的文件及文件夹清单. 通过ls 命令不仅可以查看linux文件夹包含的文件,而且可以查看文件权限(包括目录.文件夹.文件权限),查看目录信息等等.ls 命令在日常的linux操作中用的很多! 1. 命令格式: ls [选项] [目录名] 2. 命令功能: 列出目标目录中所有的子目录和文件.          3. 常用参数: (1) -a --all 显示

linux ls 命令

ls 命令是 Linux 下最常用的命令之一,用来查询目录下的内容(list directory contents).本文将介绍其基本的用法和一些典型的用例.笔者使用的测试环境为 ubuntu 16.04. 基本输出 直接在命令行中输入 ls 并回车.这是最精简的用法,因为我们省略了所有的选项和参数,输出的结果是当前目录下的文件名和目录名: 文件名和目录名称被按照字母序混排在一起,以列为单位从左到右排列.需要注意的是此时的输出并不包含隐藏文件和隐藏的目录.如果想要调整输出结果的排序方式,可以使用

夺命雷公狗---夺命雷公狗---linux NO:4 Linux ls命令参数详解

下面是一个与 ls 一起使用的一些常用选项的简短列表.请记住,你可以通过阅读 ls 的说明书页(man ls)来获得选项的完整列表. -a — 全部(all).列举目录中的全部文件,包括隐藏文件(.filename).位于这个列表的起首处的 .. 和 . 依次是指父目录和你的当前目录.-l — 长(long).列举目录内容的细节,包括权限(模式).所有者.组群.大小.创建日期.文件是否是到系统其它地方的链接,以及链接的指向.-F — 文件类型(File type).在每一个列举项目之后添加一个符

Linux ls命令参数详解 &lt;转&gt;

下面是一个与 ls 一起使用的一些常用选项的简短列表.请记住,你可以通过阅读 ls 的说明书页(man ls)来获得选项的完整列表. -a – 全部(all).列举目录中的全部文件,包括隐藏文件(.filename).位于这个列表的起首处的 .. 和 . 依次是指父目录和你的当前目录. -l – 长(long).列举目录内容的细节,包括权限(模式).所有者.组群.大小.创建日期.文件是否是到系统其它地方的链接,以及链接的指向. -F – 文件类型(File type).在每一个列举项目之后添加一

Linux ls命令详解

ls 命令可以说是Linux下最常用的命令之一. -a 列出目录下的所有文件,包括以 . 开头的隐含文件.(后有详解)-b 把文件名中不可输出的字符用反斜杠加字符编号(就象在c语言里一样)的形式列出.-c 输出文件的 i 节点的修改时间,并以此排序.-d 将目录象文件一样显示,而不是显示其下的文件.-e 输出时间的全部信息,而不是输出简略信息.-f -U 对输出的文件不排序.-g 无用.-i 输出文件的 i 节点的索引信息.-k 以 k 字节的形式表示文件的大小.-l 列出文件的详细信息.(后有

Linux ls命令+文件类型+alias命令

ls命令 #ls -l    显示详细信息 #ls -i    显示inode号 #ls -a    显示所有的文件+目录,包含隐藏的 #ls -t    按照时间顺序排序显示(第一个即为你刚刚编辑过的) #ls -h    在-l的时候人性化的显示文件的大小,例如自动使用合适的Kb,Mb,Gb等 #ls -d    directory 只显示某个目录下的目录 文件类型 像这种的第一行显示的drwxr-xr-x       crw------- 其中首字母: d    directory