`
stride
  • 浏览: 59732 次
  • 性别: Icon_minigender_1
  • 来自: 长春
社区版块
存档分类
最新评论

在windows下编写tail命令,提供源码和exe下载

阅读更多

本程序编写于32位win7旗舰版,测试也是在这个系统下,欢迎朋友们提出修改意见。

 

功能:

显示指定文本文件的最后n行,支持自动读取及手动按回车读取。

 

格式说明:

tail <fileName> [-b <Number>] [-l <Number>] [-f <Number>] 

 

标志说明:

-b <Number>

从末尾倒数 Number 表示的 512 字节块位置开始读取指定文件(无此参数则默认最后512字节),若要读取大量文本请将此值调大,例如:tail -b 10 filename.txt

-l <Number>

显示末尾Number行(无此参数则默认显示最后30行)

-f <Number>

每隔多少秒自动显示(无此参数则手动按回车显示下一次)

 

下面是调用例子:

 

tail -f 1 -b 2 -l 10 t.txt  

每一秒自动显示一次(-f 1),最多从末尾读取512*2个字节(-b 2),从这些字节中读取最后10行(-l 10)

 

tail -b 2 -l 50 t.txt

最多从末尾读取512*2个字节(-b 2),从这些字节中读取最后50行(-l 50),手动按回车显示(省略[-f])

 

tail -b 2 t.txt

最多从末尾读取512*2个字节(-b 2),从这些字节中读取最后30行(省略[-l Number]默认读取最后30行),手动按回车显示(省略[-f])

 

#include <windows.h>
#include <iostream>  
#include <fstream>
#include <string>
#include <malloc.h>
#include <stdlib.h>   

using namespace std;

/**
 * 格式说明:
 *	tail <fileName> [-b <Number>] [-l <Number>] [-f <Number>] 
 *
 * 标志说明:
 *	-b <Number>
 *		从末尾倒数 Number 表示的 512 字节块位置开始读取指定文件(无此参数则默认最后512字节)
 *	-l <Number>
 *		显示末尾Number行(无此参数则默认显示最后30行)
 *	-f <Number>
 *		每隔多少秒自动显示(无此参数则手动按回车显示下一次)
 * 
 * 例:
 *	tail -f 1 -b 2 -l 10 t.txt  
 *	每一秒自动显示一次(-f 1),最多从末尾读取512*2个字节(-b 2),从这些字节中读取最后10行(-l 10)
 *
 *	tail -b 2 -l 50 t.txt
 *	最多从末尾读取512*2个字节(-b 2),从这些字节中读取最后50行(-l 50),手动按回车显示(省略[-f])
 * 
 *	tail -b 2 t.txt
 *	最多从末尾读取512*2个字节(-b 2),从这些字节中读取最后30行(省略[-l Number]默认读取最后30行),手动按回车显示(省略[-f])
 */

// 检查字符数组的内容是否是标志
bool isFlag(char * charArr)
{
	string temp = charArr;
	if(charArr[0] == '-')
	{
		// 是以减号开头
		if(temp!="-b" && temp!="-f" && temp!="-l")
		{
			// 非法标志
			return false;
		}
		return true;
	}
	else
		return false;
}
// 检查字符数组的内容是否是正整数,不是正整数则返回零
int isNum(char * charArr)
{
	try
	{
		int v = atoi(charArr);
		// 将当前参数转整数
		if( atoi(charArr) < 1 )
			return 0;
		return v;
	}
	catch(...)
	{
		return 0;
	}
}

/**
 * 检查参数是否正确
 * @param argc 一共有几个参数(从1开始)
 * @param arg 用户输入的参数
 *
 * @return int (1:验证通过|-1:验证失败)
 */
int checkArg(int argc, char ** arg, int * b, int * l, int * f, char ** filename)
{
	// 返回值
	int ret = 1;

	// 前一个参数是否是标志
	bool preArgIsFlag = false;

	// 是否已经读到文件名
	bool readedFileName = false;

	// 是否已经读到-b
	bool readedB = false;

	// 是否已经读到-l
	bool readedL = false;
	
	// 是否已经读到-f
	bool readedF = false;
	
	// 一维数组下标
	int x = 0, v = 0;

	string temp, temp1, temp2;

	// 按元素个数从1开始循环
	for(int i=1; i<argc; i++)
	{
		temp1 = arg[i];
		if(i < argc-1)
		{
			temp2 = arg[i+1];
		}
		// 检查当前循环到的是不是最后一个元素
		if(i < argc-1) // 如果当前循环到的不是最后一个元素
		{
			if(isFlag(arg[i])) // 如果当前元素是标志
			{
				if(!isFlag(arg[i+1])) // 如果下一个元素不是标志
				{
					// 如果当前元素是标志、下一个元素不是标志
					v = isNum(arg[i+1]);
					if(v < 1)
						return 0;
					if(temp1 == "-b")
					{
						if(readedB) // 如果已经读到-b则返加零
							return 0;
						*b = v;
						readedB = true;
					}
					else if(temp1 == "-l")
					{
						if(readedL) // 如果已经读到-l则返加零
							return 0;
						*l = v;
						readedL = true;
					}
					else if(temp1 == "-f")
					{
						if(readedF) // 如果已经读到-f则返加零
							return 0;
						*f = v;
						readedF = true;
					}else{ // 非法标志
						return 0;
					}
					i++;
				}
				else // 如果下一个元素是标志
				{
					return 0;
				}
			}else{ // 如果当前元素不是标志则认定当前元素是文件名
				if(readedFileName) // 如果已经读到文件名则返回零
					return 0;
				strcpy(*filename, arg[i]); // 修改传入参数中的文件名
				readedFileName = true;
			}
		} // if(i < argc-1) // 如果当前循环到的不是最后一个元素
		else // 如果当前循环到的是最后一个元素
		{
			if(isFlag(arg[i])){ // 如果当前元素是标志
				return 0;
			}
			else // 如果当前元素不是标志
			{
				if(readedFileName) // 如果已经读到文件名则返回零
					return 0;
				strcpy(*filename, arg[i]); // 修改传入参数中的文件名
				readedFileName = true;
			}
		}
	} // for(int i=1; i<argc; i++)

	if(!readedB) // 如果没有读到-b则赋默认值
	{
		*b = 1;
	}
	if(!readedL) // 如果没有读到-l则赋默认值
	{
		*l = 30;
	}
	if(!readedF) // 如果没有读到-f则赋默认值
	{
		*f = 0;
	}
	// 判断是否有文件名
	if(!readedFileName)
		return 0;

	return ret;
}

int main(int argc, char ** argv)
{
	// 
	int b; // 缓冲区大小(是几个512)
	int l; // 要末尾读多少行
	int f; // 每隔几秒自动显示
	char * filename = new char[512];

	// 检查参数是否正确
	int result = checkArg(argc, argv, &b, &l, &f, &filename);
	if(!result)
	{
		printf("出现错误,请参照以下说明修改命令参数:\n");
		printf("格式说明:\n");
		printf("	tail <fileName> [-b <Number>] [-l <Number>] [-f <Number>] \n");
		printf("	其中fileName最长512字节\n\n");
		printf("标志说明:\n");
		printf("	-b <Number>\n");
		printf("		从末尾倒数 Number 表示的 512 字节块位置开始读取指定文件(无此参数则默认最后512字节)\n");
		printf("	-l <Number>\n");
		printf("		显示末尾Number行(无此参数则默认显示最后30行)\n");
		printf("	-f <Number>\n");
		printf("		每隔多少秒自动显示(无此参数则手动按回车显示下一次)\n\n");
		printf("例:\n");
		printf("	tail -f 1 -b 2 -l 10 t.txt  \n");
		printf("	每一秒自动显示一次(-f 1),最多从末尾读取512*2个字节(-b 2),从这些字节中读取最后10行(-l 10)\n\n");
		printf("	tail -b 2 -l 50 t.txt\n");
		printf("	最多从末尾读取512*2个字节(-b 2),从这些字节中读取最后50行(-l 50),手动按回车显示(省略[-f])\n\n");
		printf("	tail -b 2 t.txt\n");
		printf("	最多从末尾读取512*2个字节(-b 2),从这些字节中读取最后30行(省略[-l Number]默认读取最后30行),手动按回车显示(省略[-f])\n");
		return 1;
	}

	// 要显示多少行
	int showCount = l, showLineCount;

	// 文件总大小
	int count;
	char * charArr;
	while(true)
	{
		showLineCount = showCount;
		ifstream ifs;  
		// 按二进制读取文本
		ifs.open (filename, ios::binary);

		if(ifs.fail())
		{
			cout<<"错误:文件不存在。"<<endl;
			return 1;
		}

		// 将文件指针移动到末尾
		ifs.seekg (0, ios::end);
		
		// 读取文件总大小
		count = ifs.tellg();
		
		// 根据文件总大小计算应该读取多少字节
		int shouldReadLength = (count>=512*b)?512*b:count;

		// 按指定大小分配内存,加1是为了能在最后添加结束符'\0'
		charArr = new char[shouldReadLength+1];

		int i;
		// 已读取字节数
		int readed = 0;

		// 将文件指针移动到距末尾-shouldReadLength个字节的位置
		ifs.seekg (-shouldReadLength, ios::end);

		// 读取指定大小的内容
		ifs.read (charArr,shouldReadLength);

		// 添加结束符
		charArr[shouldReadLength] = '\0';

		for(i=shouldReadLength-1; i>=0 && showLineCount>0; i--,readed++)
		{
			if(charArr[i] == '\n'){
				showLineCount--;
			}
		}

		// 输出

		printf("%s\n", charArr + shouldReadLength - readed); // 这种方法可以输出到控制台
		//cout.write (charArr + shouldReadLength - readed,readed);// 这种方法也可以输出到控制台
		
		// 释放字符数组的内存空间
		delete [] charArr;
		// 关闭文件流
		ifs.close();

		if(f==0) // 用户没有输入-f参数,等待用户再次敲回车
		{
			// 如果用手动的就用cin---------- 开始
			cout<<"按Ctrl+C退出或按回车继续:";
			// 用户按回车时进行下一次显示
			cin.get();
			//system("PAUSE");
			// 如果用手动的就用cin---------- 结束
		}
		else // 用户输入了-f参数,按用户输入的秒数睡眠
		{
			// 如果要自动的就用Sleep-------- 开始
			Sleep(1000*f);
			// 如果要自动的就用Sleep-------- 结束
		}

	}

	return 0;
}
 

 

附件tail.rar中是exe可执行文件,下面是校验码:

大小: 66070 字节

修改时间: 2011年8月10日, 15:19:51

MD5: 0CAB365E4A42F83FDABAA5AB011DC0A9

SHA1: 3F0972645F15BA6DB8F70A7EF3F9C760607B684B

CRC32: 8F22B704

 

转载请注明出处

分享到:
评论
1 楼 stride 2011-08-10  
原来atoi函数不抛异常,那个try写多余了

相关推荐

    windows下tail 文件

    在Windows操作系统中,"tail"命令通常用于查看文件的末尾部分,这在Linux系统中是一个常见的工具,但在Windows环境下并不内置。为了在Windows上实现类似的功能,我们可以使用一些第三方工具或者编写脚本来完成。标题...

    Tail for windows日志读取跟踪工具

    它特别强调了"模仿Linux中的Tail",意味着它试图复制Linux `tail`命令的核心特性,使用户在Windows环境下也能享受到类似的使用体验。另外,该工具的源代码是使用Visual Studio 2015(VS 2015)编写的,这是一款由...

    让cmd拥有Linux的tail功能

    在Windows的CMD中实现Linux的`tail`功能,可以借助`more`命令的组合技巧,也可以使用专门为CMD设计的第三方工具,如提供的`tail.exe`。了解这些工具的工作原理和用途,对于提升系统管理和故障排查能力至关重要。在...

    简单的linux驱动源码(成功加载)

    本篇将详细介绍一个简单的Linux驱动程序的编写过程,以及如何在CentOS Linux系统中成功加载和运行。 首先,我们需要一个开发环境。这里选择的是Windows 7 64位系统作为宿主机,通过VMware虚拟机安装CentOS Linux...

    从Windows转向Linux教程E3000基础学习.pdf

    tail命令**:介绍了tail命令的使用场景。 - **9. grep命令**:说明了grep命令的功能。 - **10. chmod命令**:讲解了chmod命令的作用。 - **11. cp命令**:介绍了cp命令的用途。 - **12. mv命令**:解释了mv命令...

    Linux基础知识命令

    理解Linux命令行操作是有效管理服务器的关键,如使用`service`或`systemctl`控制服务状态,用`vi`或`nano`编辑配置文件,通过`chown`和`chmod`调整文件权限,以及利用`grep`、`tail`等命令查看和分析日志。...

    Linux最常用 150 个命令汇总

    `whereis` 命令与 `which` 类似,但是它可以同时查找命令的二进制文件、源码文件和手册页。 4. **locate** - **功能说明**:从数据库 (`/var/lib/mlocate/mlocate.db`) 查找命令,使用 `updatedb` 更新库。`locate`...

    信息安全技术—入侵检测系统的设计与实现—检测基本dos攻击 关键词:入侵检测系统 洪水攻击 拒绝服务 用途:检测洪水攻击

    4、在nmap中输入自己主机windows的IP地址(也可在nmap文件中用命令扫描nmap -A ip);5、日志生成在 /var/log/syslog里面,用tail -f /var/log/syslog可实时检测文件内容。6可以查看下自己虚拟机的ip地址,进行完第...

    控制台分页

    在Windows系统中,`more`命令同样存在,但在PowerShell中,用户更常使用`Get-Content -Wait -Tail`命令来实现类似的功能。 `more`和`less`这两个工具的工作原理是通过读取标准输入(stdin)或指定文件的内容,然后...

    实验一Linux基础及LKM编程.pdf

    在Linux下,开发内核模块涉及到对内核源码的理解,使用`make`命令编译模块,并通过`insmod`或`rmmod`命令加载或卸载模块。这些技能是Linux系统管理员和驱动开发者的基础。 至于LKM(Linux Kernel Module,Linux内核...

    skyeye仿真工具的使用

    解决方案是在第39行将命令`tail +${SKIP}${SCRIPT}|gunzip|tarxvf-`改为`tail -n+${SKIP} ${SCRIPT}|gunzip|tarxvf–`。 - 同时,在脚本的最后一行添加一个空行。 3. **编译并运行Hello World程序**: - 使用`arm...

    linux入门linux入门linux入门linux入门

    Linux系统日志记录在 `/var/log` 目录下,如`/var/log/syslog`和`/var/log/messages`。通过`less`或`tail`命令查看日志。 12. 故障排除 学会使用`dmesg`查看内核消息,`journalctl`(Systemd系统中)查阅系统日志,...

    linux 新手管理员手册(PDF).7z

    1. **Linux简介**:Linux是一种自由和开放源码的操作系统,其内核由林纳斯·托瓦兹创建,如今已发展成为全球范围内广泛使用的服务器平台。了解Linux的历史、哲学以及与其他操作系统(如Windows和macOS)的区别对于新...

    Prophet 安装过程

    在Windows环境下,首先确保已经安装了Python(推荐3.6或更高版本)和pip。打开命令提示符,输入以下命令来安装Prophet: ``` pip install fbprophet ``` 2. **macOS安装** 对于macOS用户,同样需要Python和pip...

    LINUX操作系统(电子教案,参考答案)

    Linux的树型结构,Linux的文本编辑,Linux的安装和启动,用户管理,Shell编程技术,进程管理,C编译器,系统扩充,维护与监视,Linux的图形界面,网络的基本概念与设置,Linux在网络资源共享和电子邮件方面的应用,...

Global site tag (gtag.js) - Google Analytics