Realizo várias tarefas sysadmin para limpar meus discos, como (mas não limitado a):
find /media/me/disk_with_huge_inode_count -type d -empty | xargs rmdir -p
e a rmdir
peça é muito lenta, enquanto find
produz uma enorme quantidade de saída em comparação.
Qual seria o comportamento do find
sob tal cenário?
Não procuro aconselhamento específico para esta operação porque tenho esta preocupação com outros trabalhos semelhantes. O que eu quero entender é como o kernel Linux (ou shell?) lida com estouros de pipeline quando o produtor e o consumidor têm uma incompatibilidade de carga.
Caso específico
Sim,
find
bloqueará pelo tempo que for necessário. Um teste "simples" é como:Aqui estão os
find
-print
nomes de caminho para um pipe (find
no seu código faz o mesmo, ele usa implícito-print
). Cada nome de caminho é impresso adicionalmente em/dev/tty
, para que você o veja depois-print
de ser bem- sucedido. Em algum momento a saída que você vê irá bloquear, é quando o buffer do pipe está (quase) cheio. Pressione Enterpara dispararread from_find
a leitura do tubo e liberar espaço no buffer.Provavelmente você precisará pressionar várias vezes Enter(na prática é bom segurar e ser paciente) até
find
imprimir outro monte de nomes de caminho para/dev/tty
. No entanto, ao não pressionar, Entervocê podefind
bloquear por um tempo arbitrariamente longo.Caso Geral
Você escreveu:
O shell é responsável por configurar as coisas: criar processos com descritores (incluindo descritores padrão: stdin, stdout, stderr) conectados aos respectivos arquivos (fifos sem nome, ou seja, pipes; ou arquivos de outros tipos ). Os dados que fluem por um tubo entre processos (como seu
find
exargs
) não fluem pelo shell. O shell não atua como um relé.Para entender como os estouros de pipeline são tratados, em geral, você pode obter algumas informações dos seguintes fragmentos da especificação POSIX de
write()
:Isso significa que um thread de escrita pode:
O_NONBLOCK
e em caso de espaço insuficiente no buffer, ele obterá[EAGAIN]
, poderá continuar (com outras tarefas) e, eventualmente, tentar escrever novamente; ouO_NONBLOCK
e em caso de espaço insuficiente no buffer, ele será bloqueado.Se uma thread de um programa usa
write()
comO_NONBLOCK
set, o programa deve rastrear o que foi escrito com sucesso e o que requer outra tentativa. ComO_NONBLOCK
clear, um buffer de pipe estar cheio não é uma preocupação: o thread apenas usawrite()
e fica bloqueado pelo tempo que for necessário; esse bloqueio acontecewrite()
e não requer nenhum esforço adicional (código), como polling, trap ou qualquer coisa.read()
pode bloquear comowrite()
, a situação é bastante semelhante e não vou elaborar separadamente.Esse design permite que os programas usem tubos de maneira confiável e fácil. A ideia do pipe é que os escritores esperam por espaço no respectivo buffer, os leitores esperam por algo no respectivo buffer; assim, os dados acabarão fluindo mesmo se houver um gargalo.
É possível escrever um programa impaciente que sairá se não conseguir escrever (quase) imediatamente (ou ler, no caso de um leitor). Programas projetados para trabalhar com tubos devem ser infinitamente pacientes. As ferramentas padrão *nix (incluindo
find
) por design são infinitamente pacientes¹. É preciso um esforço adicional para criar um programa impaciente ou envolver uma ferramenta padrão do paciente em algo que implemente um tempo limite.O impasse pode acontecer se o "encanamento" for circular ( exemplo ) ou se ele se ramificar e convergir posteriormente (como aqui ). É um problema separado que tem pouco (ou nada) a ver com a rapidez com que os programas processam dados. Não ocorre em um arranjo linear de tubos.
Consideramos as especificações POSIX de
write()
eread()
. O Linux é classificado como "principalmente compatível com POSIX" . Não é "totalmente compatível", mas não espero que se desvie significativamente do POSIX na área em questão. Tubos de trabalho confiável são muito importantes.¹ Não espero que as implementações consigam bloquear até o fim do Universo, ou além do ano 2038 ou 2147485547 . Por "programa infinitamente paciente" quero dizer um programa que não é deliberadamente impaciente por si só.
Conclusão
Seu comando está bem como um pipeline. (É falho por outro motivo, veja abaixo.)
Nota
Você
find … | xargs rmdir -p
se comportará mal para nomes de caminho contendo espaços em branco (como espaços), novas linhas, aspas simples ou duplas, barras invertidas. Isso ocorre porquexargs
sem opções específicas interpreta estes.Uma maneira confiável é por
find … -print0 | xargs -0 …
ou porfind … -exec …
. Este último é portátil.(AFAIK
find
também é infinitamente paciente ao esperar para-exec
terminar.)