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 並找出發生了什麼。

相關內容