Descobri que meus limites de tamanho não estão necessariamente no comprimento de um comando, mas sim no comprimento do argumento. Os comandos do shell podem ter entre 100.000 e 200.000 caracteres de comprimento. No entanto, os argumentos estão limitados a algumas centenas de caracteres, dependendo do sistema, conforme descoberto usando getconf ARG_MAX
.
Isso me leva ao problema de falta de espaço quando adiciono muitas exclusões de pastas aos meus argumentos rsync
.
Para contornar esse problema, eu preciso dividir programaticamente o processo rsync
de uma execução longa para várias mais pequenas.
Isso requer "construir como eu vou" até atingir um limite. O programa tentará criar uma cadeia de todas as exclusões individuais, cada uma dentro de uma lista (matriz). Se o limite de tamanho de args for excedido, ele irá reparar a lista atual para fazer exclusões mais amplas, reduzindo o total e armazenando as exclusões excluídas.
Veja um exemplo da lista de exclusões, conforme está sendo criada:
Esta lista é chamada excludes
(long list items...)
--exclude $Home/.wine
--exclude $Home/.cache/somefolders/*
--exclude $Home/.cache/somefolders/*
--exclude $Home/.cache/somefolders/*
--exclude $Home/.cache/somefolders/*
--exclude $Home/.cache/google-chrome/Default/Cache/*
--exclude $Home/.cache/google-chrome/Default/Media\ Cache/*
**LIMIT EXCEEDED**
Agora, nosso limite de ARGS foi excedido. O programa reparará essa lista procurando pastas comuns e criará uma segunda lista a ser salva para a próxima execução de rsync
.
Após a análise, excludes
é recriado em uma lista como esta:
(long list items...)
--exclude $Home/.wine
--exclude $Home/.cache/*
Como foi analisado, as linhas que foram removidas foram colocadas em outra lista, vamos chamá-lo de excludesnext
e é assim:
--exclude $Home/.cache/somefolders/*
--exclude $Home/.cache/somefolders/*
--exclude $Home/.cache/somefolders/*
--exclude $Home/.cache/somefolders/*
--exclude $Home/.cache/google-chrome/Default/Cache/*
--exclude $Home/.cache/google-chrome/Default/Media\ Cache/*
Assim, todas as pastas repetitivas são removidas de excludes
e colocadas em excludesnext
. À medida que os itens são movidos e as pastas amplas abreviadas são substituídas em excludes
, uma nova lista chamada cutlist
é criada com essas novas pastas mais curtas.
Portanto, a lista cutlist
inclui:
--exclude $Home/.cache/*
rsync
é executado usando a lista excludes
como argumentos.
Depois que rsync
for concluído, a lista excludes
será esvaziada e a lista excludesnext
será copiada para a lista excludes
.
Em seguida, o rsync
é executado em um loop usando a nova lista abreviada cutlist
como a origem, e todas as subpastas correspondentes de excludes
são usadas como exclusões.
É claro que pode haver muitos itens na lista cutlist
, e o programa passará por cada um deles. Esta segunda execução de rsync
é executada em um loop. Mas neste loop, quando os comprimentos máximos são atingidos, a excludes
lista é analisada da mesma forma que antes, exceto que as novas pastas encurtadas são adicionadas a cutlist
em vez de irem para excludes
. Dessa forma, enquanto o loop passa pela lista de corte, ela pode se expandir à medida que passa pela lista. Como os itens da lista excludesnext
são usados, eles são removidos.
Eventualmente, isso faz com que todas as pastas e subpastas sejam copiadas com todas as exclusões incluídas, independentemente de quantas delas existirem. Completar o último item em cutlist
significa que tudo foi executado.
Esse método pode fazer com que rsync
seja executado várias ou até várias vezes, dependendo de quantas exclusões você tem, mas nunca repete as pastas.
Desculpas por não postar código real, mas é um trabalho confuso em andamento e não me sinto à vontade para postar meu código antes de poder liberar um serviço de trabalho.