Acabei de fazer uma pergunta relacionada a como posso contar os arquivos de uma extensão específica. Agora eu quero cp
esses arquivos para um novo dir
.
Eu estou tentando,
cp *.prj ../prjshp/
e
cp * | grep '\.prj$' ../prjshp/
mas eles estão dando o mesmo erro,
bash: / bin / cp: lista de argumentos muito longa
Como eu os copio?
command-line
files
Sam007
fonte
fonte
Respostas:
cp *.prj ../prjshp/
é o comando certo, mas você encontrou um caso raro em que ocorre uma limitação de tamanho. O segundo comando que você tentou não faz sentido.Um método é executar
cp
nos arquivos em pedaços. Ofind
comando sabe como fazer isso:find
percorre o diretório atual e os diretórios abaixo dele recursivamente.-maxdepth 1
significa parar na profundidade de 1, ou seja, não recursar em subdiretórios.-name '*.prj'
significa agir apenas nos arquivos cujo nome corresponde ao padrão especificado. Observe as aspas ao redor do padrão: ele será interpretado pelofind
comando, não pelo shell.-exec … {} +
significa executar o comando especificado para todos os arquivos. Ele chama o comando várias vezes, se necessário, tomando cuidado para não exceder o limite da linha de comandos.mv -t ../prjshp
move os arquivos especificados para../prjshp
. A-t
opção é usada aqui devido a uma limitação dofind
comando: os arquivos encontrados (simbolizados por{}
) são passados como o último argumento do comando, você não pode adicionar o destino depois dele.Outro método é usar
rsync
.rsync -r … . ../prjshp
copia o diretório atual para../prjshp
recursivamente.--include='*.prj' --exclude='*'
significa copiar arquivos correspondentes*.prj
e excluir todo o resto (incluindo subdiretórios, para que os.prj
arquivos nos subdiretórios não sejam encontrados).fonte
cp * | grep '\.prj$' ../prjshp/
não faz nenhum sentido, mas pode ser sintaticamente válido, se for*
expandido para a lista de arquivos com o último sendo um diretório (akacp SOURCE1 SOURCE2....DEST
). O pipe não faz nenhum sentido, com certeza, mas também permanece sintaticamente válido no que diz respeito ao shell -dup()
os descritores de arquivo funcionam muito bem, mas o terminal do leitor não obtém dados porquecp
não grava nenhum .Este comando copia os arquivos um por um e funcionará mesmo se houver muitos deles para
*
expandir em um únicocp
comando:fonte
Lembre-se de três pontos principais ao enfrentar um
Argument list too long
erro:O comprimento dos argumentos da linha de comando é limitado pela
ARG_MAX
variável, que, por definição do POSIX, é "... [m] comprimento máximo do argumento para as funções exec, incluindo dados do ambiente" (ênfase adicionada) ". Ou seja, quando o shell executa um comando não comando -built-it, ele deve chamar um dosexec()
para gerar o processo desse comando, e é aí queARG_MAX
entra em cena.Além disso, o nome ou o caminho do próprio comando (por exemplo/bin/echo
) desempenha um papel.Os comandos internos do shell são executados pelo shell, o que significa que o shell não usa a
exec()
família de funções e, portanto, não é afetado pelaARG_MAX
variável.Certos comandos, como
xargs
efind
conhecem asARG_MAX
variáveis e executam ações repetidamente sob esse limitePelos pontos acima e como mostrado na excelente resposta de Kusalananda sobre questões relacionadas, isso
Argument list too long
também pode ocorrer quando o ambiente é grande. Portanto, levando em consideração que o ambiente de cada usuário pode variar e o tamanho do argumento em bytes é relevante, é difícil criar um único número de arquivos / argumentos.Como lidar com esse erro?
O principal é não se concentrar no número de arquivos, mas se o comando que você vai usar envolve ou não uma
exec()
família de funções e tangencialmente - o espaço da pilha.Use built-ins do shell
Como discutido anteriormente, os embutidos no shell são imunes ao
ARG_MAX
limite, ou seja,for
loops,while
loops, embutidosecho
e embutidosprintf
- todos terão bom desempenho.Em questões relacionadas à exclusão de arquivos, havia uma solução como essa:
Observe que isso usa o shell interno
printf
. Se estivermos chamando o externoprintf
, isso envolveráexec()
, portanto, falhará com grande número de argumentos:matrizes de bash
De acordo com uma resposta de jlliagre,
bash
não impõe limites às matrizes, portanto, a criação de uma matriz de nomes de arquivos e o uso de fatias por iteração de loop também podem ser feitos, como mostra a resposta de danjpreron :Isso, no entanto, tem limitações de ser específico do bash e não POSIX.
Aumentar o espaço da pilha
Às vezes você pode ver as pessoas sugerem aumentar o espaço de pilha com
ulimit -s <NUM>
; no Linux, o valor ARG_MAX é 1/4 do espaço da pilha para cada programa, o que significa que aumentar o espaço da pilha aumenta proporcionalmente o espaço para argumentos.De acordo com a resposta de Franck Dernoncourt , que cita o Linux Journal, também é possível recompilar o kernel do Linux com maior valor para o máximo de páginas de memória para argumentos, no entanto, isso é mais trabalhoso do que o necessário e abre potencial para explorações, conforme mencionado no artigo do Linux Journal.
Evite concha
Outra maneira, é usar
python
oupython3
que vem por padrão com o Ubuntu. O exemplo python + here-doc abaixo, é algo que eu pessoalmente usei para copiar um grande diretório de arquivos em algum lugar na faixa de 40.000 itens:Para percursos recursivos, você pode usar os.walk .
Veja também:
fonte
IMHO, as ferramentas ideais para lidar com hordas de arquivos são
find
exargs
. Vejaman find
. Vejaman xargs
.find
, com sua-print0
opção, produz umaNUL
lista separada de nomes de arquivos (os nomes de arquivos podem conter qualquer caractere executadoNUL
ou/
) quexargs
compreenda, usando a-0
opção.xargs
então cria o comando mais longo permitido (a maioria dos nomes de arquivos, sem meio nome de arquivo no final) e o executa.xargs
repete isso até quefind
não forneça mais nomes de arquivos. Corraxargs --show-limits </dev/null
para ver os limites.Para resolver seu problema (e depois de verificar
man cp
para encontrar--target-directory=
):fonte