複数のシンボリックリンクファイルをGzipに圧縮

複数のシンボリックリンクファイルをGzipに圧縮

多くのシンボリックリンクファイルを含むフォルダがあります。ファイルサイズはすべて10〜11GBです(特にfastqファイル)。さまざまなソースフォルダからインポートされますが、シンボリックリンクレベルは1つだけです。

単に以下を実行して圧縮しようとしています。

gzip *.fastq

これはいくつかの結果をもたらします。

too many levels of symbolic links

だから失敗しました。

しかし、私がこうすれば:

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

実際に働く。私の質問は簡単です。それらの違いは何ですか? AFAIKの唯一の違いは、2番目の方法は各ファイルに対して新しいgzipプロセスを開始することですが、最初の方法は1つのプロセスですべての操作を実行する必要があることです。 gzipは一度に1つのシンボリックリンクファイルしか処理できませんか?通常のファイルを含むテストフォルダで同じことを行うと、双方向で動作します。

答え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;
}

コメントアウトされた行では、-cまたは-fフラグを使用して呼び出されない限り、gzipはシンボリックリンクに従わず、#if ...を表します。圧縮するファイルは実際にシンボリックリンクです。

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.

すべてをまとめて元の質問に戻ると、次のようになります。

  • 最初の例は、実際のシンボリックリンクを圧縮しようとするため失敗します。いいえ実際のリンクループ)
  • 2番目は-cフラグを使用しているため、元のファイルの内容を読み取り、圧縮された出力をstdoutに書き込むことで成功します。
  • 3番目のケースは、-cの代わりに-fを使用することです。この場合、gzipはシンボリックリンクを圧縮しようとすると文句を言うことはありませんが、解凍した後は次のように一般的なファイルになります。
$ls -l
合計4個
-rw-rw-r-- 1 x86tux x86tux 13 6月16日 13:10 realfile.txt
lrwxrwxrwx 1 x86tux x86tux 12 6月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 6月16日 13:10 realfile.txt
-rw-rw-r-- 1 x86tux x86tux 45 6月16日 13:10 symlink.txt.gz
$gunzipシンボリックlink.txt.gz
$ls -l
合計8個
-rw-rw-r-- 1 x86tux x86tux 13 6月16日 13:10 realfile.txt
-rw-rw-r-- 1 x86tux x86tux 13 6月16日 13:10 Symlink.txt
$md5sum*
618f486e0225d305d16d0648ed44b1eb 物理ファイル.txt
618f486e0225d305d16d0648ed44b1ebシンボリックリンク.txt

答え2

ファイルごとに1つのプロセスが作業を妨げる可能性がある場合は少し害を及ぼす可能性がありますが、10〜11 GBではexec進行が妨げられるシナリオを想像するのは難しいですgzip

同様に、小さなファイルの束の場合、gzip各ファイルの比較するデータが少ないため、圧縮できない可能性がありますが、圧縮操作ごとに10〜11 GBを使用すると圧縮できません。問題。

エラーの原因を突き止めるのは興味深いと思いました。lsof背景PIDに適用しgzip、何が起こっているのかを調べることをお勧めします。

関連情報