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 exec
llamada gzip
la que obstaculice el progreso.
En el mismo sentido, si fueran un montón de archivos pequeños, gzip
probablemente 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 lsof
a un gzip
pid en segundo plano y descubrir qué está sucediendo.