Como eu apago todos os arquivos em um diretório com extensões específicas, exceto os últimos 5 deles [duplicados]

0

O diretório contém arquivos com diferentes extensões. Eu gostaria de excluir todos os arquivos com extensões .gz, zx, ext4 exceto os últimos 5 arquivos. Posso listar todos esses arquivos com

ls -l | grep '\.gz\|xz\|ext4$'

e eu poderia mostrar os 5 mais antigos:

ls -l | grep '\.gz\|xz\|ext4$' | head -5

Ou liste os últimos 5 arquivos:

ls -l | grep '\.gz\|xz\|ext4$' | tail -5

Mas eu não sei como excluir todos eles, exceto estes 5 arquivos que estão listados no comando acima.

    
por PHA 04.04.2017 / 15:05

5 respostas

3

Se a ordem de classificação normal estiver correta (ou seja, seus arquivos são nomeados pela data), e seu shell suportar matrizes, você pode usá-los para isso, evitando as advertências habituais sobre o uso de ls :

F=(./*.{gz,xz,ext4})          # list files
G=("${F[@]:5}")               # pick all but the first five to another array
G=("${F[@]:0:${#F[@]}-5}")    # or pick all but the last five
rm -- "${G[@]}"               # remove them

zsh pode ordenar por data em si mesmo, então isso pegaria os arquivos correspondentes em uma matriz, classificada por hora de modificação

F=(./*.(gz|xz|ext4)(Om))

( (Om) para o último mais recente, (om) para o primeiro mais recente). Processe a matriz como acima.

Claro, se você precisar ordenar por data de modificação, não pode usar zsh e saber que seus nomes de arquivos são bons , um simples ls -t | tail -n +6 faria. ( tail -n +6 começa a imprimir na sexta linha, ou seja, pula as cinco primeiras. Eu tive um pouco de folga neste momento.)

Com o GNU ls, acho que poderíamos pedir para citar os nomes dos arquivos para criar uma entrada adequada para o shell e, em seguida, preencher o array com a saída:

eval "F=($(ls -t --quoting-style=shell-always ./*.{xz,gz}))"

Mas isso requer confiar que ls e o shell concordam em como aspas são interpretadas.

    
por 04.04.2017 / 15:21
1
ls -1 | grep '\.gz$\|xz$\|ext4$' | tail -n +6 | xargs rm

Advertências:     Seus arquivos não devem ter espaços / citações.

set -f; set ./*.[gx]z ./*.ext4; [ "$#" -gt 5] && shift 5; rm -f "$@"

O abaixo irá funcionar com qualquer tipo de nome de arquivo:

td="'mktemp'" \
   find . -maxdepth 1 -type f \( -name \*.[gx]z -o -name \*.ext4 \) -exec sh -c '
      [ ! -s "$td" ] && [ "$#" -gt 5 ] && { shift 5; echo >> "$td"; }
      rm -f "$@"
   ' x {} +
rm "$td"
    
por 04.04.2017 / 15:32
1

No bash:

ls -1 *.{gz,xz,ext4} | head -n-5 | xargs -r rm

O principal insight é que head -n-5 imprimirá todas as linhas APÓS ANTES do 5º a partir do final (ou seja, todas as linhas, exceto as 5 últimas). Eu acredito que você entenda o resto.

A dupla para tail seria tail -n+6 , que imprime todas as linhas A PARTIR DO 6º (ou seja, todas as linhas, exceto as 5 primeiras).

    
por 04.04.2017 / 17:06
0

O seguinte comando listará todos menos os últimos 5 arquivos:

ls -l | grep '\.gz\|xz\|ext4$' | head -n 'expr \'ls | grep '\.gz\|xz\|ext4$' | wc -l\' - 4'

Você deve ser capaz de convertê-lo em comando para excluir arquivos facilmente.

    
por 04.04.2017 / 15:13
0

Você está quase lá.

Use o formato de opção longo para especificar o número de linhas necessárias e, em seguida, negue-o. (A lógica oposta pode ser usada com tail ).

head --lines=3 imprime a partir das três linhas principais

head --lines=-3 é impresso da cabeça, exceto os três últimos

Veja um exemplo usando um head e um arquivo de oito linhas chamado f

$ cat f
line 1
line 2
line 3
line 4
line 5
line 6
line 7
line 8
$ head -3 f
line 1
line 2
line 3
$ head --lines=3 f
line 1
line 2
line 3
$ head --lines=-3 f
line 1
line 2
line 3
line 4
line 5

Verifique se esta parte produz o que você deseja antes de começar a excluir arquivos.

A opção longa não é estritamente necessária, mas não tem o legado de ter que ser retrocompatível com a evolução dos comandos de cauda e cabeça e eu acho mais fácil de lembrar.

head -n-3 é equivalente à opção longa head --lines=-3 f

Veja abaixo

$ head -3 f #originally
line 1
line 2
line 3
$ head -n3 f #
line 1
line 2
line 3
$ head -n+3 f
line 1
line 2
line 3
$ head -n-3 f
line 1
line 2
line 3
line 4
line 5
$
    
por 04.04.2017 / 16:44