Eu tenho várias centenas de PDFs em um diretório no UNIX. Os nomes dos PDFs são realmente longos (aprox. 60 caracteres).
Quando tento excluir todos os PDFs juntos, usando o seguinte comando:
rm -f *.pdf
Estou tendo o erro a seguir:
/bin/rm: cannot execute [Argument list too long]
Qual é a solução para esse erro? Este erro ocorre para mv
e cp
comandos também? Se sim, como resolver esses comandos?
linux
unix
command-line-arguments
Vicky
fonte
fonte
Respostas:
Isso ocorre porque o bash realmente expande o asterisco para todos os arquivos correspondentes, produzindo uma linha de comando muito longa.
Tente o seguinte:
Aviso: esta é uma pesquisa recursiva e também encontrará (e excluir) arquivos em subdiretórios. Prenda
-f
o comando rm apenas se tiver certeza de que não deseja confirmação.Você pode fazer o seguinte para tornar o comando não recursivo:
Outra opção é usar o
-delete
sinalizador de localização:fonte
xargs
divide especificamente a lista e emite vários comandos, se necessário.-maxdepth 1
precisa ser o primeiro argumento após o caminho.-delete
sinalizador para excluir os arquivos que encontra e, mesmo que não o fizesse, ainda seria considerado uma melhor prática usar-exec
para executar rm, em vez de invocar o xargs (que agora é de 3 processos e um canal em vez de um único processo com-delete
ou 2 processos com-exec
).dangerous (broken, exploitable, etc.)
, é bastante ridículo. Sem dúvida, você deve ter cuidado ao usarxargs
, mas não é bem assimeval/evil
.-exec
chamadarm
, o número de processos será 1 + número de arquivos, embora o número de processos simultâneos disso possa ser 2 (talvez o achado execute os processos rm simultaneamente). O número de processos usandoxargs
seria reduzido drasticamente para 2 + n, onde n é um número que processa menos que o número de arquivos (por exemplo, número de arquivos / 10, embora provavelmente mais dependendo do tamanho dos caminhos). Supondo que find faça a exclusão diretamente, use-delete
deve ser o único processo que seria invocado.tl; dr
É uma limitação do kernel no tamanho do argumento da linha de comando. Use um
for
loop em seu lugar.Origem do problema
Este é um problema do sistema, relacionado
execve
eARG_MAX
constante. Há muita documentação sobre isso (veja man execve , wiki do debian ).Basicamente, a expansão produz um comando (com seus parâmetros) que excede o
ARG_MAX
limite. No kernel2.6.23
, o limite foi definido em128 kB
. Essa constante foi aumentada e você pode obter seu valor executando:Solução: Usando
for
LoopUse um
for
loop conforme recomendado no BashFAQ / 095 e não há limite, exceto para RAM / espaço de memória:Execução a seco para verificar se ele excluirá o que você espera:
E execute:
Além disso, esta é uma abordagem portátil, pois a glob possui um comportamento forte e consistente entre os shells ( parte das especificações do POSIX ).
Nota: Como observado por vários comentários, isso é realmente mais lento, mas mais sustentável, pois pode adaptar cenários mais complexos, por exemplo , onde se deseja fazer mais do que apenas uma ação.
Solução: Usando
find
Se você insiste, pode usar,
find
mas realmente não usa xargs , pois "é perigoso (quebrado, explorável etc.) ao ler entradas não delimitadas por NUL" :Usar em
-maxdepth 1 ... -delete
vez de-exec rm {} +
permitefind
simplesmente executar as chamadas necessárias do sistema sem usar um processo externo, portanto, mais rápido (graças ao comentário do @chepner ).Referências
fonte
for
loop. Eu já useifind
antes, mas estou sempre procurando saber como fazê-lo, pois esqueço as opções etc. o tempo todo.for
Parece mais fácil IMHO recordaçãofor f in *; do rm "$f"; done
find -exec
solução parece ser MUITO mais rápida que ofor
loop.4.15.0-1019-gcp
para ser exato) eo limite ainda está em 2097152. Curiosamente, procurando ARG_MAX no linux git repo dá um resultado mostrando ARG_MAX estar em 131702.find
tem uma-delete
ação:fonte
xargs
, conforme a resposta de Dennis, funciona como pretendido.-exec
é remover um monte de arquivos.-exec rm {} +
faria a mesma coisa, mas ainda requer iniciar pelo menos um processo externo.-delete
permitefind
simplesmente executar as chamadas de sistema necessárias sem usar um invólucro externo.Outra resposta é forçar o
xargs
processamento dos comandos em lotes. Por exemplo, paradelete
os arquivos de100
cada vez,cd
no diretório e execute:echo *.pdf | xargs -n 100 rm
fonte
echo
está um shell embutido. Se você acabar usando o comandoecho
, continuará executando o limite de argumentos do programa.Ou você pode tentar:
fonte
find . -maxdepth 1 -name '*.pdf' -exec rm -f {} \;
Se você estiver tentando excluir um número muito grande de arquivos ao mesmo tempo (eu excluí um diretório com mais de 485.000 hoje), provavelmente você encontrará esse erro:
O problema é que, quando você digita algo como
rm -rf *
, o*
é substituído por uma lista de todos os arquivos correspondentes, como “rm -rf arquivo1 arquivo2 arquivo3 arquivo4” e assim por diante. Há um buffer de memória relativamente pequeno alocado para armazenar esta lista de argumentos e, se estiver cheia, o shell não executará o programa.Para contornar esse problema, muitas pessoas usarão o comando find para encontrar todos os arquivos e passá-los um a um para o comando “rm” como este:
Meu problema é que eu precisava excluir 500.000 arquivos e estava demorando muito.
Eu me deparei com uma maneira muito mais rápida de excluir arquivos - o comando “find” tem uma bandeira “-delete” embutida! Aqui está o que eu acabei usando:
Usando esse método, eu estava excluindo arquivos a uma taxa de cerca de 2000 arquivos / segundo - muito mais rápido!
Você também pode mostrar os nomes dos arquivos ao excluí-los:
… Ou até mostrar quantos arquivos serão excluídos e tempo quanto tempo leva para excluí-los:
fonte
sudo find . -type f -delete
para excluir cerca de 485 mil arquivos e funcionou para mim. Demorou cerca de 20 segundos.você pode tentar isso:
EDIT: O comentário do ThiefMaster sugere que eu não divulgue essa prática perigosa aos jedis do jovem shell, então adicionarei uma versão mais "segura" (para preservar as coisas quando alguém tem um arquivo "-rf. ..Pdf")
Após executar o procedimento acima, basta abrir o arquivo /tmp/dummy.sh no seu favorito. editor e verifique se há nomes de arquivos perigosos em todas as linhas, comentando-os, se encontrados.
Em seguida, copie o script dummy.sh no seu diretório de trabalho e execute-o.
Tudo isso por razões de segurança.
fonte
-rf .. .pdf
-rf
tem precedência-i
, portanto, sua segunda versão não é melhor (sem inspeção manual). E é basicamente inútil para exclusão em massa, devido à solicitação de cada arquivo.Você pode usar uma matriz bash:
Dessa forma, ele será apagado em lotes de 1000 arquivos por etapa.
fonte
você pode usar esse elogio
fonte
O comando rm possui uma limitação de arquivos que você pode remover simultaneamente.
Uma possibilidade é removê-los usando várias vezes o comando rm com base em seus padrões de arquivo, como:
Você também pode removê-los através do comando find :
fonte
rm
não existe esse limite no número de arquivos que ele processará (exceto queargc
não pode ser maior queINT_MAX
). É a limitação do kernel no tamanho máximo de toda a matriz de argumentos (é por isso que o tamanho dos nomes dos arquivos é significativo).Se forem nomes de arquivos com espaços ou caracteres especiais, use:
Essa frase pesquisa todos os arquivos no diretório atual (-maxdepth 1) com a extensão pdf (-name '* .pdf') e, em seguida, exclua cada um (-exec rm "{}").
A expressão {} substitui o nome do arquivo e "{}" define o nome do arquivo como string, incluindo espaços ou caracteres especiais.
fonte
-exec
é que você não invoca um shell. As citações aqui não fazem absolutamente nada útil. (Eles evitar qualquer expansão curinga e divisão simbólica na corda no shell onde você digita este comando, mas a corda{}
não contém qualquer espaço em branco ou desembolsar caracteres curinga.)eu estava enfrentando o mesmo problema ao copiar o diretório de origem do formulário para o destino
diretório de origem tinha arquivos ~ 3 lakcs
usei cp com a opção -r e funcionou para mim
cp -r abc / def /
ele copiará todos os arquivos do abc para o def sem avisar por muito tempo a lista de argumentos
fonte
Tente isso também Se você quiser excluir arquivos / pastas acima de 30/90 dias (+) ou abaixo de 30/90 (-) dias, use os comandos ex abaixo
Ex: para 90 dias exclui acima após 90 dias, arquivos / pastas são excluídos, significa 91,92 .... 100 dias
Ex: Apenas para os arquivos mais recentes de 30 dias que você deseja excluir, use o comando abaixo (-)
Se você deseja alterar os arquivos por mais de 2 dias
Se você quiser ver os arquivos / pastas apenas no último mês. Ex:
Acima de mais de 30 dias, apenas liste os arquivos / pastas Ex:
fonte
Estou surpreso que não haja
ulimit
respostas aqui. Toda vez que tenho esse problema, acabo aqui ou aqui . Entendo que esta solução tem limitações, masulimit -s 65536
parece que costuma fazer o truque para mim.fonte
Eu tive o mesmo problema com uma pasta cheia de imagens temporárias que crescia dia a dia e esse comando me ajudou a limpar a pasta
A diferença com os outros comandos é o parâmetro mtime que levará apenas os arquivos com mais de X dias (no exemplo 50 dias)
Usando isso várias vezes, diminuindo a cada execução do período, pude remover todos os arquivos desnecessários
fonte
Eu só sei uma maneira de contornar isso. A idéia é exportar a lista de arquivos pdf que você possui para um arquivo. Em seguida, divida esse arquivo em várias partes. Em seguida, remova os arquivos pdf listados em cada parte.
wc -l é para contar quantas linhas o list.txt contém. Quando você tem a idéia de quanto tempo leva, pode decidir dividi-lo ao meio, para a frente ou algo assim. Usando o comando split -l Por exemplo, divida-o em 600 linhas cada.
isso criará alguns arquivos chamados xaa, xab, xac e assim por diante, dependendo de como você o divide. Agora, para "importar" cada lista desses arquivos no comando rm, use este:
Desculpe pelo meu inglês ruim.
fonte
pdf_format_sucks.docx
isso também será excluído ... ;-) Você deve usar expressões regulares apropriadas e precisas ao grepping para os arquivos pdf.still_pdf_format_sucks.docx
será excluído. O ponto.
na".pdf"
expressão regular corresponde a qualquer caractere. Eu sugeriria em"[.]pdf$"
vez de.pdf
.Eu me deparei com esse problema algumas vezes. Muitas das soluções executam o
rm
comando para cada arquivo individual que precisa ser excluído. Isso é muito ineficiente:Acabei escrevendo um script python para excluir os arquivos com base nos 4 primeiros caracteres no nome do arquivo:
Isso funcionou muito bem para mim. Consegui limpar mais de 2 milhões de arquivos temporários em uma pasta em cerca de 15 minutos. Eu comentei o tar do pouco código, para que qualquer pessoa com um conhecimento mínimo ou nenhum de python possa manipular esse código.
fonte
E um outro:
printf
é um shell embutido e, tanto quanto eu sei, sempre foi assim. Agora, como esseprintf
não é um comando do shell (mas um interno), ele não está sujeito a "argument list too long ...
" erro fatal.Assim, podemos usá-lo com segurança com padrões de globbing do shell, como
*.[Pp][Dd][Ff]
, em seguida, canalizamos sua saída para remover (rm
) o comandoxargs
, o que garante que ele se ajuste a nomes de arquivos suficientes na linha de comando para não falhar norm
comando, que é um shell comando.O
\0
inprintf
serve como um separador nulo para os nomes de arquivo que são processados porxargs
comando, usando-o (-0
) como separador, pararm
que não falhe quando houver espaços em branco ou outros caracteres especiais nos nomes de arquivo.fonte
printf
não houver um shell embutido, ele estará sujeito à mesma limitação.Você pode criar uma pasta temporária, mover todos os arquivos e subpastas que deseja manter para a pasta temporária, excluir a pasta antiga e renomear a pasta temporária para a pasta antiga. Tente este exemplo até ter certeza de fazê-lo ao vivo:
o
rm -r big_folder
removerá todos os arquivos,big_folder
não importa quantos. Você só precisa ter muito cuidado, primeiro tem todos os arquivos / pastas que deseja manter, neste caso, foifile1.pdf
fonte
Para excluir tudo
*.pdf
em um diretório/path/to/dir_with_pdf_files/
Excluir arquivos específicos
rsync
usando o curinga é provavelmente a solução mais rápida, caso você tenha milhões de arquivos. E isso resolverá o erro que você está recebendo.(Etapa opcional): EXECUÇÃO SECA. Para verificar o que será excluído sem excluir. `
. . .
Clique em dicas e truques do rsync para obter mais hacks do rsync
fonte
Eu descobri que, para listas extremamente grandes de arquivos (> 1e6), essas respostas eram muito lentas. Aqui está uma solução usando processamento paralelo em python. Eu sei, eu sei, isso não é linux ... mas nada aqui funcionou.
(Isso me salvou horas)
fonte
Eu enfrentei um problema semelhante quando havia milhões de arquivos de log inúteis criados por um aplicativo que preenchia todos os inodes. Eu recorri ao "localizar", coloquei todos os arquivos "localizados" d em um arquivo de texto e os removi um a um. Demorou um pouco, mas fez o trabalho!
fonte
locate
novamente quando ainda havia espaço no disco.Uma versão um pouco mais segura do que usar xargs, também não recursiva:
ls -p | grep -v '/$' | grep '\.pdf$' | while read file; do rm "$file"; done
Filtrar nossos diretórios aqui é um pouco desnecessário, pois 'rm' não o exclui de qualquer maneira, e pode ser removido por simplicidade, mas por que executar algo que definitivamente retornará erro?
fonte
ls
é um antipadrão comum que definitivamente deve ser evitado e adiciona vários bugs adicionais aqui. Ogrep | grep
não é apenas muito elegante.find
são boas e bem documentadas aqui e em outros lugares. Veja, por exemplo, o mywiki.wooledge.org, para muito mais sobre este e outros tópicos relacionados.Usar o GNU paralelo (
sudo apt install parallel
) é super fácilEle executa os comandos multithread onde '{}' é o argumento passado
Por exemplo
ls /tmp/myfiles* | parallel 'rm {}'
fonte
ls
diretamente para outros comandos é um antipadrão perigoso - isso e o fato de a expansão do curinga causar a mesma falha ao executarls
como experimentado norm
comando original .parallel
deixa algumas pessoas que preferem evitar a complexidade desconfortável - se você olhar por baixo do capô, é bem opaco. Veja o tópico da lista de discussão em lists.gnu.org/archive/html/bug-parallel/2015-05/msg00005.html entre Stephane (um dos homens cinzentos do Unix e Linux StackExchange ) e Ole Tange (autor do Parallel).xargs -P
também paraleliza, mas o faz de maneira mais simples e mais burra, com menos partes móveis, tornando seu comportamento muito mais fácil de prever e raciocinar.Para remover os 100 primeiros arquivos:
rm -rf 'ls | cabeça -100 '
fonte
A opção abaixo parece simples para esse problema. Eu recebi essas informações de algum outro tópico, mas isso me ajudou.
Basta executar o comando acima e ele fará a tarefa.
fonte