Gzip 大量符号链接文件

Gzip 大量符号链接文件

我有一个包含大量符号链接文件的文件夹。这些文件的大小均为 10-11GB(具体为 fastq 文件)。它们来自各种源文件夹,但我确保只有一层符号链接。

我试图通过简单地执行以下操作来压缩它们:

gzip *.fastq

这会导致一堆

too many levels of symbolic links

因此失败了。

但是,当我这样做时:

for i in `ls | egrep *.fastq$`; do gzip -c $i > $i.gz; done;

它确实有效。我的问题很简单。它们之间有什么区别? AFAIK,唯一的区别是第二种方法为每个文件启动一个新的 gzip 进程,而第一种方法应该在一个进程中完成所有操作。 gzip 一次只能处理一个符号链接文件吗?在包含普通文件的测试文件夹上执行相同的操作是双向的。

答案1

快速检查 gzip 源代码(具体来说,Ubuntu 14.04 中包含的 gzip 1.6)表明观察到的行为来自该函数打开和统计,从 gzip.c 的第 1037 行开始:

static int
open_and_stat (char *name, int flags, mode_t mode, struct stat *st)
{
  int fd;

  /* Refuse to follow symbolic links unless -c or -f.  */
  if (!to_stdout && !force)
    {
      if (HAVE_WORKING_O_NOFOLLOW)
        flags |= O_NOFOLLOW;
      else
        {
#if HAVE_LSTAT || defined lstat
          if (lstat (name, st) != 0)
            return -1;
          else if (S_ISLNK (st->st_mode))
            {
              errno = ELOOP;
              return -1;
            }
#endif
        }
    }

  fd = OPEN (name, flags, mode);
  if (0 <= fd && fstat (fd, st) != 0)
    {
      int e = errno;
      close (fd);
      errno = e;
      return -1;
    }
  return fd;
}

请注意,注释行指出 gzip 不会遵循符号链接,除非使用 -c 或 -f 标志调用它,并且在 #if ... #endif 内,errno 变量设置为 ELOOP(遇到太多符号链接),如果要压缩的文件实际上是一个符号链接。

现在,从 gzip(1) 手册页来看,-c 和 -f 标志是:

   -c --stdout --to-stdout
         Write  output  on  standard output; keep original files unchanged.  If there are
         several input files, the output consists of a  sequence  of  independently  com‐
         pressed  members.  To  obtain  better  compression,  concatenate all input files
         before compressing them.


  -f --force
         Force compression or decompression even if the file has multiple  links  or  the
         corresponding  file  already  exists,  or if the compressed data is read from or
         written to a terminal. If the input data is not in a format recognized by  gzip,
         and  if the option --stdout is also given, copy the input data without change to
         the standard output: let zcat behave as cat.  If -f is not given, and  when  not
         running  in  the  background,  gzip  prompts  to verify whether an existing file
         should be overwritten.

将所有内容放在一起并回到最初的问题:

  • 第一个示例失败,因为它试图压缩实际的符号链接(即使它是不是实际的链接循环)
  • 第二个使用 -c 标志,因此它读取原始文件的内容,然后将压缩输出写入 stdout,因此成功。
  • 第三种情况是使用 -f 而不是 -c。在这种情况下,gzip 在尝试压缩符号链接时不会抱怨,但解压后它会变成常规文件,如下所示:
$ ls -l
总计 4
-rw-rw-r-- 1 x86tux x86tux 13 六月 16 13:10 realfile.txt
lrwxrwxrwx 1 x86tux x86tux 12 六月 16 23:40 symlink.txt -> realfile.txt
$ gzip 符号链接.txt
gzip: symlink.txt: 符号链接级别太多
$ gzip -f 符号链接.txt
$ ls -l
总计 8
-rw-rw-r-- 1 x86tux x86tux 13 六月 16 13:10 realfile.txt
-rw-rw-r-- 1 x86tux x86tux 45 六月 16 13:10 symlink.txt.gz
$gunzip 符号链接.txt.gz
$ ls -l
总计 8
-rw-rw-r-- 1 x86tux x86tux 13 六月 16 13:10 realfile.txt
-rw-rw-r-- 1 x86tux x86tux 13 六月 16 13:10 symlink.txt
$ md5sum *
618f486e0225d305d16d0648ed44b1eb realfile.txt
618f486e0225d305d16d0648ed44b1eb 符号链接.txt

答案2

如果每个文件的单个进程可能会阻碍您的操作,那么它可能会造成一些伤害,但在 10-11 GB 的情况下,很难想象任何场景会阻碍exec进度gzip

同样,如果它们是一堆小文件,那么gzip很可能无法压缩它们,因为每个文件可供比较的数据较少,但同样,每次压缩操作 10-11 GB,这不会成为问题。

我认为发现错误的原因会很有趣。我建议尝试应用lsof到后台gzippid 并找出发生了什么。

相关内容