*. jpg se expande para uma lista maior do que o shell pode manipular. Tente isso ao invés
find /home/ftpuser/public_html/ftparea/ -name "*.jpg" -exec cp -uf "{}" /your/destination \;
Estou usando o seguinte comando:
\cp -uf /home/ftpuser1/public_html/ftparea/*.jpg /home/ftpuser2/public_html/ftparea/
E estou recebendo o erro:
-bash: /bin/cp: Argument list too long
Eu também tentei:
ls /home/ftpuser1/public_html/ftparea/*.jpg | xargs -I {} cp -uf {} /home/ftpuser2/public_html/ftparea/
Ainda tenho -bash: / bin / ls: Lista de argumentos muito longa
Alguma idéia?
Existe um limite máximo de quanto tempo uma lista de argumentos pode ser para os comandos do sistema - este limite é específico da distribuição baseado no valor de MAX_ARG_PAGES
quando o kernel é compilado e não pode ser alterado sem recompilar o kernel.
Devido à forma como o globbing é tratado pelo shell, isso afetará a maioria dos comandos do sistema quando você usar o mesmo argumento ("* .jpg"). Como o glob é processado pelo shell primeiro e depois enviado para o comando, o comando:
cp -uf *.jpg /targetdir/
é essencialmente o mesmo para o shell, como se você escrevesse:
cp -uf 1.jpg 2.jpg ... n-1.jpg n.jpg /targetdir/
Se você está lidando com muitos jpegs, isso pode se tornar incontrolável muito rápido. Dependendo da sua convenção de nomenclatura e do número de arquivos que você realmente precisa processar, é possível executar o comando cp em um subconjunto diferente do diretório por vez:
cp -uf /sourcedir/[a-m]*.jpg /targetdir/
cp -uf /sourcedir/[n-z]*.jpg /targetdir/
Isso pode funcionar, mas exatamente o quão eficiente seria com base em quão bem você pode dividir sua lista de arquivos em blocos convenientes que podem ser convertidos em blocos.
Globbable. Eu gosto dessa palavra.
Alguns comandos, como find e xargs , podem manipular listas de arquivos grandes sem fazer listas de argumentos com tamanho considerável.
find /sourcedir/ -name '*.jpg' -exec cp -uf {} /targetdir/ \;
O argumento -exec executará o restante da linha de comando uma vez para cada arquivo encontrado por find , substituindo o {} por cada nome de arquivo encontrado. Como o comando cp é executado apenas em um arquivo por vez, o limite da lista de argumentos não é um problema.
Isso pode ser lento devido ao processamento de cada arquivo individualmente. A utilização de xargs poderia fornecer uma solução mais eficiente:
find /sourcedir/ -name '*.jpg' -print0 | xargs -0 cp -uf -t /destdir/
xargs pode pegar a lista de arquivos completa fornecida por find e dividi-la em listas de argumentos de tamanhos gerenciáveis e executar cp em cada dessas sublistas.
Naturalmente, há também a possibilidade de apenas recompilar seu kernel, definindo um valor maior para MAX_ARG_PAGES
. Mas recompilar um kernel é mais trabalho do que estou disposto a explicar nesta resposta.
Isso acontece porque sua expressão curinga ( *.jpg
) excede o limite de comprimento do argumento da linha de comando quando expandida (provavelmente porque você tem muitos arquivos .jpg em /home/ftpuser/public_html/ftparea
).
Existem várias maneiras de contornar essa limitação, como usar find
ou xargs
. Dê uma olhada no artigo para obter mais detalhes sobre como faça isso.
Existe um número máximo de argumentos que podem ser especificados para um programa, o bash expande * .jpg para muitos argumentos para o cp. Você pode resolvê-lo usando find, xargs ou rsync etc.
Dê uma olhada aqui sobre xargs e encontre
Como GoldPseudo comentou, há um limite para quantos argumentos você pode passar para um processo que está gerando. Veja a resposta dele para uma boa descrição desse parâmetro.
Você pode evitar o problema ignorando o processo ou reduzindo o número de argumentos que está passando.
Um loop for no shell, find e ls, grep e um loop while fazem a mesma coisa nessa situação -
for file in /path/to/directory/*.jpg ;
do
rm "$file"
done
e
find /path/to/directory/ -name '*.jpg' -exec rm {} \;
e
ls /path/to/directory/ |
grep "\.jpg$" |
while
read file
do
rm "$file"
done
todos têm um programa que lê o diretório (o próprio shell, o find e o ls) e um programa diferente que realmente recebe um argumento por execução e percorre toda a lista de comandos.
Agora, isso será lento porque o rm precisa ser bifurcado e executado para cada arquivo que corresponda ao padrão * .jpg.
É aqui que o xargs entra em jogo. O xargs toma a entrada padrão e para cada N (para o freebsd é por padrão 5000) linhas, ele gera um programa com N argumentos. O xargs é uma otimização dos loops acima, porque você só precisa separar os programas 1 / N para percorrer todo o conjunto de arquivos que lê os argumentos da linha de comando.
Usar a opção +
para find -exec
acelerará bastante a operação.
find /home/ftpuser/public_html/ftparea/ -name "*jpg" -exec cp -uf -t /your/destination "{}" +
A opção +
requer que {}
seja o último argumento, portanto, usar a opção -t /your/destination
(ou --target-directory=/your/destination
) para cp
faz com que funcione.
De man find
:
-exec command {} +
This variant of the -exec action runs the specified command on the selected files, but the command line is built by appending each selected file name at the end; the total number of invoca‐ tions of the command will be much less than the number of matched files. The command line is built in much the same way that xargs builds its command lines. Only one instance of ‘{}’ is allowed within the command. The command is executed in the starting directory.
Editar : argumentos rearranjados para cp
Parece que você tem muitos arquivos *.jpg
nesse diretório para colocá-los todos na linha de comando de uma só vez. Você poderia tentar:
find /home/ftpuser/public_html/ftparea1 -name '*.jpg' | xargs -I {} cp -uf {} /home/ftpuser/public_html/ftparea2/
Você pode precisar verificar man xargs
para sua implementação para ver se a opção -I
está correta para o seu sistema.
Na verdade, você está realmente pretendendo copiar esses arquivos para o mesmo local onde eles já estão?
O '*' glob está expandindo para muitos nomes de arquivos. Use find / home / ftpuser / public_html -name '* .jpg' em seu lugar.
Ir para a pasta
cd /home/ftpuser1/public_html/
e execute o seguinte:
cp -R ftparea/ /home/ftpuser2/public_html/
Desta forma, se a pasta 'ftparea' tiver subpastas, isso pode ser um efeito negativo se você quiser apenas os arquivos '* .jpg', mas se não houver subpastas, essa abordagem será definitivamente muito mais rápido do que usando find e xargs
Tags bash linux unix-shell