我有一个包含大量符号链接文件的文件夹。这些文件的大小均为 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
到后台gzip
pid 并找出发生了什么。