我有一個包含大量符號連結檔案的資料夾。這些檔案的大小均為 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 並找出發生了什麼。