Eu tenho uma pasta contendo uma grande quantidade de arquivos com links simbólicos. Cada um desses arquivos tem cerca de 10 a 11 GB (arquivos fastq para ser específico). Eles vêm de uma variedade de pastas de origem, mas me certifiquei de que houvesse apenas um nível de links simbólicos.
Estou tentando compactá-los simplesmente fazendo:
gzip *.fastq
Isso resulta em um monte de
too many levels of symbolic links
E assim falha.
No entanto, quando eu faço:
for i in `ls | egrep *.fastq$`; do gzip -c $i > $i.gz; done;
funciona. Minha pergunta é simples. Qual é a diferença entre eles? AFAIK, a única diferença é que a segunda abordagem inicia um novo processo gzip para cada arquivo, enquanto a primeira deve fazer tudo em um processo. O gzip pode lidar apenas com um arquivo com link simbólico por vez? Fazer o mesmo em uma pasta de teste com arquivos normais funciona nos dois sentidos.
Responder1
Uma verificação rápida da fonte gzip (especificamente, gzip 1.6 incluído no Ubuntu 14.04), mostra que o comportamento observado vem da funçãoopen_and_stat, começando na linha 1037 do 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;
}
Observe que a linha de comentário afirma que gzip não seguirá links simbólicos, a menos que seja chamado com os sinalizadores -c ou -f e dentro de #if ... #endif a variável errno esteja definida como ELOOP (muitos links simbólicos encontrados) se o arquivo a ser compactado é na verdade um link simbólico.
Agora, na página de manual do gzip(1), os sinalizadores -c e -f são:
-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 tudo e voltando à pergunta original:
- O primeiro exemplo falha porque está tentando compactar o link simbólico real (mesmo que sejanãoum loop de link real)
- O segundo usa o sinalizador -c, portanto, lê o conteúdo do arquivo original e, em seguida, grava a saída compactada em stdout, para que seja bem-sucedido.
- Um terceiro cenário é usar -f em vez de -c. Neste caso, o gzip não reclama ao tentar compactar um link simbólico, mas ao descompactá-lo ele se torna um arquivo normal, conforme mostrado:
$ ls -l total 4 -rw-rw-r-- 1 x86tux x86tux 13 16 de junho 13:10 realfile.txt lrwxrwxrwx 1 x86tux x86tux 12 16 de junho 23:40 link simbólico.txt -> arquivo real.txt $ gzip link simbólico.txt gzip: symlink.txt: Muitos níveis de links simbólicos $ gzip -f link simbólico.txt $ ls -l total 8 -rw-rw-r-- 1 x86tux x86tux 13 16 de junho 13:10 realfile.txt -rw-rw-r-- 1 x86tux x86tux 45 16 de junho 13:10 symlink.txt.gz $ gunzip link simbólico.txt.gz $ ls -l total 8 -rw-rw-r-- 1 x86tux x86tux 13 16 de junho 13:10 realfile.txt -rw-rw-r-- 1 x86tux x86tux 13 16 de junho 13:10 link simbólico.txt $md5sum* 618f486e0225d305d16d0648ed44b1eb arquivo real.txt 618f486e0225d305d16d0648ed44b1eb link simbólico.txt
Responder2
O processo único por parte do arquivo pode prejudicar alguns se houver alguma possibilidade de afunilar sua operação, mas com 10 a 11 gigabytes é muito difícil imaginar qualquer cenário em que seja a exec
chamada gzip
que atrapalhe o progresso.
Na mesma linha, se eles fossem um monte de arquivos pequenos, gzip
provavelmente não seriam capazes de compactá-los, tendo menos dados para comparar por arquivo, mas, novamente, de 10 a 11 gigabytes por operação de compactação, isso não será um problema .
Descobrir a causa do erro seria interessante, eu acho. Eu sugeriria tentar aplicar lsof
a um gzip
pid em segundo plano e descobrir o que está acontecendo.