Gzip una gran cantidad de archivos con enlaces simbólicos

Gzip una gran cantidad de archivos con enlaces simbólicos

Tengo una carpeta que contiene una gran cantidad de archivos con enlaces simbólicos. Cada uno de estos archivos es del orden de 10 a 11 GB (archivos fastq para ser específicos). Provienen de una variedad de carpetas de origen, pero me aseguré de que solo haya un nivel de enlaces simbólicos.

Estoy intentando comprimirlos simplemente haciendo:

gzip *.fastq

Eso resulta en un montón de

too many levels of symbolic links

Y así fracasa.

Sin embargo, cuando lo hago:

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

funciona. Mi pregunta es sencilla. ¿Cuál es la diferencia entre esos? AFAIK, la única diferencia es que el segundo enfoque inicia un nuevo proceso gzip para cada archivo, mientras que el primero debería hacer todo en un solo proceso. ¿Gzip solo puede manejar un archivo con enlace simbólico a la vez? Hacer lo mismo en una carpeta de prueba con archivos normales funciona en ambos sentidos.

Respuesta1

Una verificación rápida de la fuente de gzip (específicamente, gzip 1.6 incluido en Ubuntu 14.04) muestra que el comportamiento observado proviene de la funciónabierto_y_stat, comenzando en la línea 1037 de gzip.c:

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

Tenga en cuenta que la línea de comentario indica que gzip no seguirá enlaces simbólicos a menos que se llame con los indicadores -c o -f, y dentro de #if... #endif la variable errno está configurada en ELOOP (se encontraron demasiados enlaces simbólicos) if el archivo a comprimir es en realidad un enlace simbólico.

Ahora, desde la página del comando man gzip(1), los indicadores -c y -f son:

   -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.

Juntando todo y volviendo a la pregunta original:

  • El primer ejemplo falla porque intenta comprimir el enlace simbólico real (incluso si esnoun bucle de enlace real)
  • El segundo usa el indicador -c, por lo que lee el contenido del archivo original y luego escribe la salida comprimida en la salida estándar, por lo que tiene éxito.
  • Un tercer escenario es utilizar -f en lugar de -c. En este caso, gzip no se queja al intentar comprimir un enlace simbólico, pero al descomprimirlo se convierte en un archivo normal, como se muestra:
$ ls-l
total 4
-rw-rw-r-- 1 x86tux x86tux 13 16 de junio 13:10 realfile.txt
lrwxrwxrwx 1 x86tux x86tux 12 16 de junio 23:40 symlink.txt -> realfile.txt
$ gzip enlace simbólico.txt
gzip: symlink.txt: Demasiados niveles de enlaces simbólicos
$ gzip -f enlace simbólico.txt
$ ls-l
total 8
-rw-rw-r-- 1 x86tux x86tux 13 16 de junio 13:10 realfile.txt
-rw-rw-r-- 1 x86tux x86tux 45 16 de junio 13:10 symlink.txt.gz
$ gunzip enlace simbólico.txt.gz
$ ls-l
total 8
-rw-rw-r-- 1 x86tux x86tux 13 16 de junio 13:10 realfile.txt
-rw-rw-r-- 1 x86tux x86tux 13 16 de junio 13:10 symlink.txt
$ md5suma *
618f486e0225d305d16d0648ed44b1eb archivo real.txt
618f486e0225d305d16d0648ed44b1eb enlace simbólico.txt

Respuesta2

El proceso único por parte de archivo podría perjudicar a algunos si existiera alguna posibilidad de que obstaculizara su operación, pero con 10-11 gigabytes es muy difícil imaginar cualquier escenario en el que sea la execllamada gzipla que obstaculice el progreso.

En el mismo sentido, si fueran un montón de archivos pequeños, gzipprobablemente no podrían comprimirlos y tendrían menos datos para comparar por archivo, pero, nuevamente, a 10-11 gigabytes por operación de compresión eso no será un problema. .

Sin embargo, creo que descubrir la causa del error sería interesante. Sugeriría intentar aplicar lsofa un gzippid en segundo plano y descubrir qué está sucediendo.

información relacionada