tail 源码分析

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

使用tail查看日志时可以使用-f选项实时输出日志中新加入的内容,即follow该文件的内容。像这样,new line是新加入到文件中的内容,tail可以发现这点并显示给用户:

$ tail -f t1 t2
==> t1 <==
hello


==> t2 <==
hello

==> t1 <==
new line
new line

==> t2 <==
new line

那么底层是如何实现的呢?

下载了tail的源码,根据选项-f定位到parse_options。使用F时,follow_mode为Follow_name; 使用f或follow时,默认是Follow_descriptor,否则可以自行指定一种模式。

// parse_options 函数中

    case 'F':
          forever = true;
          follow_mode = Follow_name;
          reopen_inaccessible_files = true;
          break;
    ...
    case 'f':
    case LONG_FOLLOW_OPTION:
      forever = true;
      if (optarg == NULL)
        follow_mode = DEFAULT_FOLLOW_MODE;
      else
        follow_mode = XARGMATCH ("--follow", optarg,
                                 follow_mode_string, follow_mode_map);
      break;
    ...

前面提到的follow的两种模式:Follow_name, Follow_descriptor。Follow_name的意思是,如果文件被重命名了(renamed),那么就用新的文件名重新打开该文件,并跟踪(track)该文件的尾部,适用于日志文件;而Follow_descriptor是说,即便跟踪的文件被重命名或删除也会继续follow该文件。

/* FIXME: make Follow_name the default?  */
#define DEFAULT_FOLLOW_MODE Follow_descriptor // 默认模式

enum Follow_mode
{
  /* Follow the name of each file: if the file is renamed, try to reopen
     that name and track the end of the new file if/when it's recreated.
     This is useful for tracking logs that are occasionally rotated.  */
  Follow_name = 1,

  /* Follow each descriptor obtained upon opening a file.
     That means we'll continue to follow the end of a file even after
     it has been renamed or unlinked.  */
  Follow_descriptor = 2
};

tail将管理的文件放到一个数组中,每个元素的结构定义为:

struct File_spec
{
  char *name; // 文件名

  /* 上次检查时文件的一些属性,包括大小、inode等*/
  off_t size; 
  struct timespec mtime;
  dev_t dev;
  ino_t ino;
  mode_t mode;
  ...
  /* 文件描述符,打开失败时为-1 */
  int fd;
  ...
};

tail的主循环为tail_forever, 每隔若干事件对管理的文件数组进行检查,通过fstat检查文件大小或者dev/ino是否改变了。如果都没变,就sleep若干时间后,继续检查:

/* Tail N_FILES files forever, or until killed.
   The pertinent information for each file is stored in an entry of F.
   Loop over each of them, doing an fstat to see if they have changed size,
   and an occasional open/fstat to see if any dev/ino pair has changed.
   If none of them have changed size in one iteration, sleep for a
   while and try again.  Continue until the user interrupts us.  */
static void tail_forever (struct File_spec *f, size_t n_files, double sleep_interval)
{
...
}

总结一下,tail 实际上是一个循环,每次循环都检测文件是否发生变化,然后把变化告诉用户。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值