Justificação
Esta é minha tentativa de criar um comando que funcione com qualquer diretório e nome (s) de arquivo. Em geral, os caminhos no Linux (e nomes nos sistemas de arquivos) podem conter qualquer caractere, mas nulo ( 0x00
) e /
. Caracteres problemáticos podem ser "
" (espaço), qualquer outro caractere branco, '
, "
, nova linha, outros caracteres não imprimíveis. Portanto, é importante:
- abandonam ferramentas que substituem alguns caracteres por outras (por exemplo, muitas implementações de
ls
imprimem ?
para não-imprimíveis);
- passa todos os nomes como sequências terminadas em nulo (escolha ferramentas que possam analisá-las);
- cite corretamente.
Eu fui inspirado pela discussão em esta outra resposta .
Comandos reais
Versão de teste, serão apenas ls
os arquivos que seriam removidos:
find -type d -exec sh -c 'find "$0" -maxdepth 1 -mindepth 1 -type f -exec stat --printf "%s %nfind -type d -exec sh -c 'find "$0" -maxdepth 1 -mindepth 1 -type f -exec stat --printf "%s %nfind -type d -exec '# Find all directories under (and including) the current one.' \
sh -c ' '# In every directory separately...' \
find "$0" -maxdepth 1 -mindepth 1 -type f -exec '# ...find all files,...' \
stat --printf "%s %nfind -type d -exec sh -c 'find "$0" -maxdepth 1 -mindepth 1 -type f -exec stat --printf "%s %nfind -type d -exec sh -c 'find "$0" -maxdepth 1 -mindepth 1 -type f -exec stat --printf "%s %nfind -type d -exec '# Find all directories under (and including) the current one.' \
sh -c ' '# In every directory separately...' \
find "$0" -maxdepth 1 -mindepth 1 -type f -exec '# ...find all files,...' \
stat --printf "%s %n%pre%" \{\} + | # ...get their sizes and names,...
sort -znr | # ...sort by size...
tail -zn +2' '# ...and discard the "biggest" entry.' \
{} \
\; | # (All the directories have been processed).
cut -zf 2- -d " " | # Then extract filenames...
xargs -0r ls -l # ...and ls them (rm in the working version).
" \{\} + | sort -znr | tail -zn +2' {} \; | cut -zf 2- -d " " | xargs -0r rm
" \{\} + | sort -znr | tail -zn +2' {} \; | cut -zf 2- -d " " | xargs -0r ls -l
" \{\} + | # ...get their sizes and names,...
sort -znr | # ...sort by size...
tail -zn +2' '# ...and discard the "biggest" entry.' \
{} \
\; | # (All the directories have been processed).
cut -zf 2- -d " " | # Then extract filenames...
xargs -0r ls -l # ...and ls them (rm in the working version).
" \{\} + | sort -znr | tail -zn +2' {} \; | cut -zf 2- -d " " | xargs -0r rm
" \{\} + | sort -znr | tail -zn +2' {} \; | cut -zf 2- -d " " | xargs -0r ls -l
Sim, estou usando ls
aqui, apesar do que acabei de dizer. Isso ocorre porque ls
output não está sendo analisado mais. Estou usando apenas para exibir o resultado. Se acontecer de você ter diretórios ou arquivos com caracteres problemáticos em seus nomes, você observará o comportamento de ls
, que deve convencê-lo a nunca analisar ls
(a menos que você saiba que está absolutamente seguro disso). Ainda assim, os nomes problemáticos passarão até ls
e esse é o ponto.
Entenda a versão de teste (veja abaixo algumas explicações) e experimente antes de deixar a versão de trabalho (logo abaixo) remover seus arquivos. Lembre-se de que sou apenas um cara aleatório na Internet.
Versão de trabalho, ele removerá seus arquivos:
%pre%
Explicação
Aqui está a versão de testes dividida em várias linhas (embora ainda seja uma linha para bash
; note que eu uso esse truque para comentários inline):
%pre%
Técnicas usadas, obstáculos superados:
- As ferramentas que analisam strings são instruídas a trabalhar com sequências terminadas com nulo:
-
stat --printf "…sort -z
"
;
-
tail -z
, cut -z
, xargs -0 …
;
-
find -print0
;
-
sh -c '…'
(não é necessário neste exemplo, mas é muito comum em geral, portanto eu menciono isso de qualquer maneira).
-
find -exec
é o caminho para usar pipes dentro de find -type d -exec sh -c 'find "{}" …
.
-
"
será quebrado para o nome do diretório contendo find -type d -exec sh -c 'find "$0" … ' {} \;
; {}
funciona bem.
-
find
na instrução \{\}
interna tem escape ( find
) para evitar que o% externocut
os substitua.
-
tail
poderia seguir imediatamente cut
, ele executaria um find
por diretório. Colocá-lo fora do exterior cut
faz com que um único -r
faça todo o corte de uma só vez.
- A opção
xargs
para ls
impede que rm
( xargs
na versão de trabalho) seja executado quando não há entrada para %code% .