关于linux的一点好奇心(四):tail -f文件跟踪实现

本文探讨了如何实现文件跟踪,包括定时扫描和基于异步通知的跟踪方法。详细分析了`tail -f`命令的源码,揭示其在Linux系统中的工作方式,以及如何优雅地处理文件变化,对于系统运维和计算机知识的理解具有参考价值。
摘要由CSDN通过智能技术生成

🚀 优质资源分享 🚀

学习路线指引(点击解锁) 知识定位 人群定位
🧡 Python实战微信订餐小程序 🧡 进阶级 本课程是python flask+微信小程序的完美结合,从项目搭建到腾讯云部署上线,打造一个全栈订餐系统。
💛Python量化交易实战💛 入门级 手把手带你打造一个易扩展、更安全、效率更高的量化交易系统
目录

关于文件跟踪,我们有很多的实际场景,比如查看某个系统日志的输出,当有变化时立即体现,以便进行问题排查;比如查看文件结尾的内容是啥,总之是刚需了。

返回顶部### 1. 自己实现的文件跟踪

我们平时做功能开发时,也会遇到类似的需求,比如当有人传输文件到某个位置后,我们需要触发后续处理操作。

那么,我们自己实现的话,也就只能通过定时检查文件是否变化,比如检测最后修改时间,从而感知到变化。如果要想让文件传输完成之后,再进行动作,则一般需要用户上传一个空的done文件,以报备事务处理完成。

那么,如果是系统实现呢?如题,tail -f 的文件跟踪,是否也是这样实现呢?想想感觉应该不会这么简单,毕竟操作系统肯定会比自己厉害此的。

返回顶部### 2. tail -f的源码位置

我们知道,每个linux系统安装之后,都会有很多的基础命令可用,比如cat/vi/sh/top/tail… 那么,是否这些命令就是内核提供的东西呢?实际上不是的,linux kernel 部分,并未提供相应的实现,即这些工具类的都不是在kernel中实现的,而是作为外部核心工具包组件实现。即 coreutils 。 这也是我们想分析一些工具类实现时需要注意的,因为它可能在你找不到的地方。

源码访问路径: http://git.savannah.gnu.org/cgit/coreutils.git/tree/src/tail.c

返回顶部### 3. tail -f 实现

tail -f 作为核心工具,虽与操作系统一起出现,但毕竟是独立实现,所以还是需要考虑具体的操作系统环境,所以它的实现往往需要分情况进行处理。

即它有多种实现,一种是和我们一样,定时去检测文件化,然后输出到控制台;第二种则高级些,利用操作系统提供的文件通知功能,进行实时内容输出。具体如下:

int
main (int argc, char **argv)
{
 enum header\_mode header\_mode = multiple\_files;
 bool ok = true;
 /* If from\_start, the number of items to skip before printing; otherwise,
 the number of items at the end of the file to print. Although the type
 is signed, the value is never negative. */
 uintmax\_t n\_units = DEFAULT\_N\_LINES;
 size\_t n\_files;
 char **file;
 struct File\_spec *F;
 size\_t i;
 bool obsolete\_option;

 /* The number of seconds to sleep between iterations.
 During one iteration, every file name or descriptor is checked to
 see if it has changed. */
  double sleep\_interval = 1.0;

 initialize\_main (&argc, &argv);
 set\_program\_name (argv[0]);
 setlocale (LC\_ALL, "");
 bindtextdomain (PACKAGE, LOCALEDIR);
 textdomain (PACKAGE);

 atexit (close\_stdout);

 have\_read\_stdin = false;

 count\_lines = true;
 forever = from\_start = print\_headers = false;
 line\_end = '\n';
 obsolete\_option = parse\_obsolete\_option (argc, argv, &n\_units);
 argc -= obsolete\_option;
 argv += obsolete\_option;
 parse\_options (argc, argv, &n\_units, &header\_mode, &sleep\_interval);

 /* To start printing with item N\_UNITS from the start of the file, skip
 N\_UNITS - 1 items. 'tail -n +0' is actually meaningless, but for Unix
 compatibility it's treated the same as 'tail -n +1'. */
  if (from\_start)
 {
 if (n\_units)
 --n\_units;
 }

 if (optind < argc)
 {
 n\_files = argc - optind;
 file = argv + optind;
 }
 else
 {
 static char *dummy\_stdin = (char *) "-";
 n\_files = 1;
 file = &dummy\_stdin;
 }

 {
 bool found\_hyphen = false;

 for (i = 0; i < n\_files; i++)
 if (STREQ (file[i], "-"))
 found\_hyphen = true;

 /* When following by name, there must be a name. */
    if (found\_hyphen && follow\_mode == Follow\_name)
 die (EXIT\_FAILURE, 0, \_("cannot follow %s by name"), quoteaf ("-"));

 /* When following forever, and not using simple blocking, warn if
 any file is '-' as the stats() used to check for input are ineffective.
 This is only a warning, since tail's output (before a failing seek,
 and that from any non-stdin files) might still be useful. */
    if (forever && found\_hyphen)
 {
 struct stat in\_stat;
 bool blocking\_stdin;
 blocking\_stdin = (pid == 0 && follow\_mode == Follow\_descriptor
 && n\_files == 1 && ! fstat (STDIN\_FILENO, &in\_stat)
 && ! S\_ISREG (in\_stat.st\_mode));

 if (! blocking\_stdin && isatty (STDIN\_FILENO))
 error (0, 0, \_("warning: following standard input"
                         " indefinitely is ineffective"));
 }
 }

 /* Don't read anything if we'll never output anything. */
  if (! n\_units && ! forever && ! from\_start)
 return EXIT\_SUCCESS;

 F = xnmalloc (n\_files, sizeof *F);
 for (i = 0; i < n\_files; i++)
 F[i].name = file[i];

 if (header\_mode == always
 || (header\_mode == multiple\_files && n\_files > 1))
 print\_headers = true;

 xset\_binary\_mode (STDOUT\_FILENO, O\_BINARY);

 for (i = 0; i < n\_files; i++)
 ok &= tail\_file (&
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值