osx: seletivamente zipar grande número de arquivos: - @ option OK?

4

Eu preciso fazer um arquivo zip arquivando ~ 100k arquivos de um diretório contendo ~ 500k arquivos. Eu recebo erros "lista de argumentos muito longa" quando tento os comandos óbvios:

zip archive.zip *pattern*.txt                        # fails
zip archive.zip 'find . -name "*pattern*.txt"'       # fails

Uma abordagem é usar a opção -@ para alimentar uma lista de arquivos no via stdin:

find . -name "*pattern*.txt" | zip -@ archive.zip

No entanto, a página zip man diz:

If a file list is specified as -@ [Not on MacOS], zip takes the list of input files from standard input instead of from the command line.

É o "Não no MacOS" que está me incomodando. Eu fui em frente e tentei a opção -@ , e parece funcionar; mas estou me sentindo nervoso sobre se está realmente fazendo o trabalho certo (arquivando todos os arquivos, intactos).

Aqui estão minhas perguntas:

  1. Por que -@ não está correto no MacOS?
  2. Existem algumas versões do MacOS / bash / zip em que esse aviso é verdadeiro e outras não? Este é um aviso obsoleto e, em caso afirmativo, onde está a linha divisória?
  3. Qual seria uma abordagem viável para esse problema sem usar -@ ?

Note que a solução dada aqui zip: Argument lista muito longa (80.000 arquivos no total) não funcionará; Eu preciso estar arquivando alguns, não todos, os arquivos no diretório.

Estou executando o Mac OS 10.7.5. Aqui estão algumas informações sobre a versão:

$ bash --version
GNU bash, version 3.2.48(1)-release (x86_64-apple-darwin11)
$ zip --version
This is Zip 3.0 (July 5th 2008), by Info-ZIP.
...
Compiled with gcc 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2335.15.00) for Unix (Mac OS X) on Jun 24 2011.
    
por andrewtinka 29.03.2013 / 17:00

3 respostas

6

Primeiro de tudo,

zip archive.zip 'find . -name "*pattern*.txt"'

é nunca uma boa ideia. Os nomes de arquivo podem conter espaços, caractere de novas linhas, partes que poderiam ser interpretadas como comutadores e outros itens.

Para executar uma ação para cada arquivo encontrado, você pode usar o -exec mude ou xargs .

find . -name "*pattern*.txt" -exec zip archive.zip {} +

adicionará os arquivos um por um ao arquivo zip. Aqui, {} simboliza o arquivo atualmente processado.

Encerrar o argumento -exec com um + em vez de ; faz com que o find processe vários arquivos de uma só vez (o máximo possível sem gerar os mesmos erros que você recebe), que deve ser consideravelmente mais rápido um grande número de arquivos.

find . -name "*pattern*.txt" -print0 | xargs -0 zip archive.zip

faz essencialmente o mesmo. O xargs processa vários arquivos de uma só vez por padrão.

A opção -print0 para localizar e a -0 para os xargs fazem com que usem caracteres nulos como separadores de arquivos para lidar adequadamente com nomes de arquivos estranhos.

Não sei por que o -@ não é recomendado para o Mac OS 1 , mas find ... | zip -@ não não lidará com nomes de arquivos estranhos (especificamente, nomes de arquivos contendo caracteres de nova linha) corretamente. Isso é verdade, independentemente do sistema operacional.

1 Estou adivinhando se aplica somente ao Mac OS até a versão 9.x, já que o Mac OS usava retornos de carro como caracteres de nova linha, enquanto zip -@ esperava linefeeds.

    
por 29.03.2013 / 17:23
3

Dennis estava certo, é uma coisa do OS 9. Eu dei uma olhada no código fonte do Zip 3.0. No diretório da plataforma macos/ , há uma observação que diz:

This port is for Mac versions before Mac OS X. As Mac OS X is build on Unix, use the Unix port for Mac OS X. - 7 June 2008

Além disso, o arquivo zip.c agrupa a declaração da opção de linha de comando em #ifndef MACOS . Em outras palavras, se eu estivesse executando a porta "MacOS" de zip , a opção -@ simplesmente falharia.

Dennis também forneceu a resposta para "uma maneira viável de realizar a tarefa sem -@ ", ou seja,

find . -name "*pattern*.txt" -print0 | xargs -0 zip archive.zip

Concordo que esta é a melhor maneira de proceder para estar seguro contra nomes de arquivos "estranhos" (nomes de arquivos com espaços, novas linhas, etc). No entanto, há uma penalidade de desempenho. xargs chamará zip várias vezes, com um grande conjunto de nomes de arquivos passados como parâmetros de linha de comando a cada vez. zip adicionará esses arquivos em archive.zip em cada chamada. Mas zip precisará ler o sempre maior archive.zip em cada chamada, o que leva mais e mais tempo à medida que o trabalho progride.

Se você sabe com certeza que os nomes dos arquivos em questão não possuem caracteres patológicos como espaços ou novas linhas, então o single-pass

find . -name "*pattern*.txt" | zip -@ archive.zip

será mais rápido; e funciona muito bem no OS X, porque zip no OS X é realmente a porta Unix. O aviso na manpage não se aplica.

    
por 30.03.2013 / 15:31
0

Como as informações da sua versão mostram, o código base (e, portanto, presumivelmente, a documentação) é bem antigo, o MacOS mudou bastante nesse meio tempo. Além disso, a compilação é muito mais nova que o código de base, pode haver alterações no código / configuração para a compilação que simplesmente nunca foi incluída na documentação.

Em qualquer caso, é melhor verificar (com um pequeno exemplo, talvez) que o comando funciona e realmente armazena os arquivos solicitados. Se for importante, não acredite em quadrados coloridos com peças faltando em sites da Internet aleatórios ...

    
por 29.03.2013 / 17:40