CP: argumentos máximos de número de arquivos de origem para o utilitário de cópia

11

Considere que há um número incontável de arquivos em / src /

cp /src/* /dst/

Quantos arquivos cpserão processados ​​com êxito?

Mike
fonte
2
Se a lista de argumentos for muito longa (lembre-se, o que * faz é expandir para uma lista de todos os arquivos que correspondem ao glob), você pode contorná-lo usando, por exemplo, IFS="\n" for file in /src/*; do mv "$file" /dst/; doneou rsync -a /src/ /dst/.
DopeGhoti

Respostas:

18

Isso depende muito do sistema e da versão, do número e tamanho dos argumentos e do número e tamanho dos nomes de variáveis ​​de ambiente.

Tradicionalmente no Unix, o limite (conforme relatado por getconf ARG_MAX) era mais ou menos no tamanho cumulativo de:

  • O comprimento das sequências de argumentos (incluindo a finalização '\0')
  • O comprimento da matriz de ponteiros para essas cadeias, normalmente 8 bytes por argumento em um sistema de 64 bits
  • O comprimento das seqüências de caracteres do ambiente (incluindo a terminação '\0'), sendo uma sequência de ambiente por convenção algo parecido var=value.
  • O comprimento da matriz de ponteiros para essas cadeias, normalmente 8 bytes por argumento em um sistema de 64 bits

Tendo em mente que cptambém conta como argumento (é o primeiro argumento).

No Linux, isso depende da versão. O comportamento mudou recentemente, onde não é mais um espaço fixo.

A verificação no Linux 3.11 getconf ARG_MAXagora relata um quarto do limite definido no tamanho da pilha, ou 128kiB, se for menor que 512kiB).

( zshsintaxe abaixo):

$ limit stacksize
stacksize       8MB
$ getconf ARG_MAX
2097152
$ limit stacksize 4M
$ getconf ARG_MAX
1048576

Esse limite está no tamanho cumulativo das seqüências de argumento e ambiente e em algumas sobrecargas (suspeito devido à consideração do alinhamento nos limites da página). O tamanho dos ponteiros não é levado em consideração.

Procurando pelo limite, recebo:

$ /bin/true {1..164686}
$ /bin/true {1..164687}
zsh: argument list too long: /bin/true
$ x= /bin/true {1..164686}
$ x=1 /bin/true {1..164686}
zsh: argument list too long: /bin/true

O tamanho cumulativo máximo antes da quebra nesse caso é:

$ (env _=/bin/true x=;print -l /bin/true {1..164686}) | wc -c
1044462

Agora, isso não significa que você pode transmitir 1 milhão de argumentos vazios. Em um sistema de 64 bits, 1 milhão de argumentos vazios formam uma lista de ponteiros de 8 MB, que estaria acima do tamanho da minha pilha de 4MiB.

$ IFS=:; /bin/true ${=${(l.1000000..:.)${:-}}}
zsh: killed     /bin/true ${=${(l.1000000..:.)${:-}}}

(você notou que não é um erro E2BIG. Não sei em que momento o processo será morto lá, se estiver dentro da execvechamada do sistema ou posterior).

Observe também (ainda no Linux 3.11) que o tamanho máximo de um único argumento ou sequência de ambiente é 128kiB, independentemente do tamanho da pilha.

$ /bin/true ${(l.131071..a.)${:-}} # 131072 OK
$ /bin/true ${(l.131072..a.)${:-}} # 131073 not
zsh: argument list too long: /bin/true
$ /bin/true ${(l.131071..a.)${:-}} ${(l.131071..a.)${:-}} # 2x 131072 OK
Stéphane Chazelas
fonte
Você pode compartilhar por favor, como você criou o 164686número? ou seja, como você calculou que a sequência estaria no 2097152tamanho ARG_MAX?
Sergiy Kolodyazhnyy
14

Isso dependerá do valor de ARG_MAX que pode mudar entre os sistemas. Para descobrir o valor da execução do seu sistema (mostrando o resultado no meu como um exemplo):

$ getconf ARG_MAX
2097152

Isso não tem nada a ver com o cpseu shell, é um limite imposto pelo kernel, não executará exec()comandos ( ) se seus argumentos forem maiores que ARG_MAX. Portanto, se o comprimento da lista de argumentos que você forneceu cpfor maior que ARG_MAX, o cpcomando não será executado.

Para responder à sua pergunta principal, cpo processo não será processado, pois nunca será executado com tantos argumentos. Devo também mencionar que isso não depende do número de argumentos, mas de seu comprimento. É possível que você possa ter o mesmo problema com nomes de arquivos muito poucos, mas muito longos.


A maneira de contornar esses erros é executar seu comando em um loop:

for file in /src/*; do cp "$file" /dst/; done
terdon
fonte
Isso significa que mesmo idiomas de nível inferior Cpodem ter problemas com ARG_MAX e nomes de arquivos realmente longos?
Harold Fischer