AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / unix / Perguntas / 565637
Accepted
Mike
Mike
Asked: 2020-02-04 17:22:21 +0800 CST2020-02-04 17:22:21 +0800 CST 2020-02-04 17:22:21 +0800 CST

Como posso contar o número de arquivos em um diretório e excluir o mais antigo se o número exceder 5

  • 772

Criei um script para executar backups automatizados no meu servidor CentOS 7. Os backups são armazenados no diretório /home/backup. O script funciona, mas agora gostaria de incorporar uma forma de contar os arquivos após o backup acontecer e se o número for maior que 5, excluir o backup mais antigo.

Abaixo está o que eu tenho para o meu script de backup.

#!/bin/bash

#mysqldump variables

FILE=/home/backup/databasebk_!`date +"Y-%m-%d_%H:%M"`.sql
DATABASE=database
USER=root
PASS=my password

#backup command process

mysqldump --opt --user=${USER} --password=${PASS} ${DATABASE} > ${FILE}

#zipping the backup file

gzip $FILE

#send message to the user with the results

echo "${FILE}.gz was created:"
ls -l ${FILE}.gz

# This is where I would like to count the number of files 
# in the directory and if there are more than 5 I would like
# to delete the oldest file. Any help is greatly appreciated

Obrigado -Mike

shell-script variable
  • 7 7 respostas
  • 6296 Views

7 respostas

  • Voted
  1. BoppreH
    2020-02-05T01:56:37+08:002020-02-05T01:56:37+08:00

    Em Bash puro sem loops:

    ls -t | tail -n +6 | xargs -d '\n' rm
    

    Explicação:

    • ls -timprime todos os arquivos no diretório atual, ordenados por hora de modificação, os mais novos primeiro.
    • tail -n +6ignora as primeiras 5 linhas e imprime as linhas 6 em diante.
    • xargs -d '\n' rmremove os arquivos passados ​​para ele, um por linha. Se você tem certeza absoluta de que não há espaços ou aspas nos nomes dos arquivos, você pode usar apenas xargs rm.

    Observe que isso exclui quantos arquivos forem necessários para deixar apenas 5 arquivos no diretório. Se você deseja excluir apenas o arquivo mais antigo, substitua +6por 1.

    • 21
  2. Best Answer
    Stephen Harris
    2020-02-04T17:47:20+08:002020-02-04T17:47:20+08:00

    Você pode olhar set -- /home/backup/databasebk_*e enquanto $#for maior que cinco, excluir um arquivo.

    Assim, o código seria semelhante a

    set -- /home/backup/databasebk_*
    while [ $# -gt 5 ]
    do
      echo "Removing old backup $1"
      rm "$1"
      shift
    done
    

    Isso funciona porque os nomes de arquivos que você escolheu estão automaticamente na ordem "mais antigos primeiro".

    Para consistência, eu definiria uma variável (eu normalmente a chamo, BASEmas você pode chamá-la como quiser)

    Então

    BASE=/home/backup/databasebk_
    FILE=${BASE}!`date +"%Y-%m-%d_%H:%M"`.sql
    ....
    set -- ${BASE}*
    while [ $# -gt 5 ]
    do
      echo "Removing old backup $1"
      rm "$1"
      shift
    done
    
    • 12
  3. Heysus Escobar
    2020-02-04T18:47:16+08:002020-02-04T18:47:16+08:00

    Acho que uma abordagem melhor seria usar o logrotate, pois esse aplicativo já executa as ações que você está tentando realizar com seu script. Eu testei os seguintes scripts no meu servidor de teste.

    1. Faça backup manual do banco de dados, isso é necessário porque o logrotate não será executado se o arquivo não existir.
        $ mysqldump -uroot -pmy5trongpass database > mydatabase.sql
        $ ls
        $ mydatabase.sql
    

    Exemplo de erro se o primeiro banco de dados não foi criado.

        #**logrotate -f** will force our new rule to run now and backup the database
        #this is for testing purposes.
    
        $ logrotate -f /etc/logrotate.d/mysql_backup
        error: stat of /home/backups/mydatabase.sql failed: No such file or directory
    
    1. Crie um arquivo/regra logrotate. Aqui está o que eu criei com base em outras regras localizadas em /etc/logrotate.d/
        $ cat /etc/logrotate.d/mysql_backup
        /home/backups/mydatabase.sql{
                create 640 root mysql
               daily
                rotate 2
                nocompress
            postrotate
                mysqldump -uroot -pmy5trongpass test > mydatabase.sql;
                echo "done"
            endscript
        }
    
    1. Teste sua configuração usando
    $ logrotate -f /etc/logrotate.d/mysql_backup
    
    $ logrotate -f /etc/logrotate.d/mysql_backup
    done
    $ ll
    total 16
    -rw-r-----. 1 root mysql 1261 Feb  3 21:46 mydatabase.sql
    -rw-r-----. 1 root mysql 1261 Feb  3 21:44 mydatabase.sql.1
    -rw-r-----. 1 root mysql 1261 Feb  3 21:44 mydatabase.sql.2
    

    você verá que um novo arquivo será criado seguido por um número, isso pode ser alterado para mostrar as datas usando as seguintes opções

    https://linux.die.net/man/8/logrotate
    
    dateext
    Archive old versions of log files adding a daily extension like YYYYMMDD instead of simply adding a number. The extension may be configured using the dateformat option.
    
    dateformat format_string
    Specify the extension for dateext using the notation similar to strftime(3) function. Only %Y %m %d and %s specifiers are allowed. The default value is -%Y%m%d. Note that also the character separating log name from the extension is part of the dateformat string. The system clock must be set past Sep 9th 2001 for %s to work correctly. Note that the datestamps generated by this format must be lexically sortable (i.e., first the year, then the month then the day. e.g., 2001/12/01 is ok, but 01/12/2001 is not, since 01/11/2002 would sort lower while it is later). This is because when using the rotate option, logrotate sorts all rotated filenames to find out which logfiles are older and should be removed.
    
    • 12
  4. Kusalananda
    2020-02-04T21:46:32+08:002020-02-04T21:46:32+08:00

    Usando o zshescudo:

    rm -f /home/backup/databasebk_*.sql.gz(.om[6,-1])
    

    Isso criaria uma lista de nomes de caminho de arquivos regulares correspondentes /home/backup/databasebk_*.sql.gz, classificaria a lista nos carimbos de data e hora de modificação dos arquivos (modificados mais recentemente primeiro) e extrairia os elementos 6 até o final. Esses arquivos seriam então passados rm -f​​para exclusão.

    É o qualificador de glob , (.om[6,-1]), no final do padrão de globbing de nome de arquivo que especifica arquivos regulares ( .), ordenando por hora de modificação ( om), e que a 6ª até a última correspondência deve ser retornada ( [6,-1]).

    • 6
  5. Jasen
    2020-02-04T17:48:04+08:002020-02-04T17:48:04+08:00
    files=( /home/backup/* )
    # files is now an array containing file names in the directory
    
    oldest=""
    if (( ${#files[@]} > 5 ))  ## are there more than five?
    then 
      for name in "${files[@]}" ## loop to find oldest
      do
        a=$( stat --printf=%Y "$name" )
        if  [ -z "$oldest" ] || (( a < age ))
        then 
           age="$a"
           oldest="$name"
        fi
      done
      rm "$oldest"
    fi
    

    Alguns comentários:

    Eu digo /home/backup/*que encontra todos os arquivos nesse diretório, eu poderia dizer /home/backup/databasebk_*.sql.gzapenas para encontrar despejos compactados

    Estou usando 'stat' para encontrar o arquivo mais antigo de acordo com o sistema de arquivos, pois suas datas estão na ordem do formato YMDhm, eu poderia comparar os nomes dos arquivos

     if  [ -z "$oldest" ] || [ "$name" -lt "$oldest" ]
    

    a presença de subdiretórios em /home/backup/ quebrará este script

    • 2
  6. Hopping Bunny
    2020-02-05T23:42:57+08:002020-02-05T23:42:57+08:00

    Antes de começar, gostaria de dizer que tenho em alta estima as outras respostas e elas refletem uma boa compreensão do processo.

    Agora vou me colocar no seu lugar e procurar algo simples para começar, então construir sobre isso. Deixe-me primeiro reafirmar seu problema:

    1. Determine se o número de arquivos é maior que 5.
    2. Se for menor ou igual a 5, não faça nada.
    3. Se tiver mais de 5, encontre e exclua o arquivo com mais de 5 (apenas 1 arquivo).

    Aqui está minha abordagem:

    1. Use ls -1 |wc -lpara contar o número de arquivos.
    2. Verifique se o número de listagens é maior que 5, usando uma instrução if.
    3. Se for maior que 5, use o comando find com as opções adequadas para excluir os que tiverem mais de 5 dias.

    Aqui está o código:

    if [[ $(ls -1|wc -l) -gt 5 ]]; then 
    
      ls -1t |tail -n1 |xargs -n1 rm -f  
    
    fi
    

    Explicação da primeira linha: Verifica se o número de arquivos nesse diretório ultrapassa 5.

    Explicação da segunda linha: Será executado apenas o número de arquivos superior a 5 (se houver 4 arquivos e deles um tiver uma data de 100 dias atrás, não será executado). Ele os classificará por data e executará o tailcomando para obter o mais antigo (o último da lista). Em seguida, ele passará esse nome de arquivo para o xargscomando que usará rm -f(forçar) para excluir o arquivo.

    Obrigado a todos os outros que contribuíram com uma solução! Eu sei que há casos em que isso não funcionará (como mais de 6 arquivos, 2 arquivos da mesma data, etc), mas tentei mantê-lo simples, pois Mike é novo :)

    • 2
  7. Luchostein
    2020-02-07T10:22:28+08:002020-02-07T10:22:28+08:00

    Criar rm-except-last.sh:

    #!/bin/bash -
    
    set -o nounset
    
    if ! (($#)); then
      echo Usage: "$BASH_SOURCE" N_NOT_TO_DELETE FILES_TO_DELETE...
      exit 1
    fi
    
    declare N="${1:?Missing N_NOT_TO_DELETE.}"
    if ! [[ "$N" =~ ^[0-9]+$ ]]; then
      echo 1>&2 -E Not a number: "$N"
      exit 1
    fi
    shift
    
    declare -a roll=()
    while ((${#roll[@]} < N)); do
      roll+=('')
    done
    
    if ! ((N)); then
      rm -rfv -- "$@"
      exit $?
    fi
    
    declare n=0 file=''
    for file in "$@"; do
      declare rmfile="${roll[n]}"
      [ -n "$rmfile" ] && rm -rfv -- "$rmfile"
      roll[n]="$file"
      ((n = (n + 1) % N))
    done
    

    Então:

    $ rm-except-last.sh 5 /home/backup/databasebk_*.sql

    • 1

relate perguntas

  • Um script que imprime as linhas de um arquivo com seu comprimento [fechado]

  • exportar variáveis ​​​​env programaticamente, via stdout do comando [duplicado]

  • Dividir por delimitador e concatenar problema de string

  • Como salvar um caminho com ~ em uma variável?

  • MySQL Select com função IN () com array bash

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Possível firmware ausente /lib/firmware/i915/* para o módulo i915

    • 3 respostas
  • Marko Smith

    Falha ao buscar o repositório de backports jessie

    • 4 respostas
  • Marko Smith

    Como exportar uma chave privada GPG e uma chave pública para um arquivo

    • 4 respostas
  • Marko Smith

    Como podemos executar um comando armazenado em uma variável?

    • 5 respostas
  • Marko Smith

    Como configurar o systemd-resolved e o systemd-networkd para usar o servidor DNS local para resolver domínios locais e o servidor DNS remoto para domínios remotos?

    • 3 respostas
  • Marko Smith

    apt-get update error no Kali Linux após a atualização do dist [duplicado]

    • 2 respostas
  • Marko Smith

    Como ver as últimas linhas x do log de serviço systemctl

    • 5 respostas
  • Marko Smith

    Nano - pule para o final do arquivo

    • 8 respostas
  • Marko Smith

    erro grub: você precisa carregar o kernel primeiro

    • 4 respostas
  • Marko Smith

    Como baixar o pacote não instalá-lo com o comando apt-get?

    • 7 respostas
  • Martin Hope
    user12345 Falha ao buscar o repositório de backports jessie 2019-03-27 04:39:28 +0800 CST
  • Martin Hope
    Carl Por que a maioria dos exemplos do systemd contém WantedBy=multi-user.target? 2019-03-15 11:49:25 +0800 CST
  • Martin Hope
    rocky Como exportar uma chave privada GPG e uma chave pública para um arquivo 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Evan Carroll status systemctl mostra: "Estado: degradado" 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim Como podemos executar um comando armazenado em uma variável? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S Por que /dev/null é um arquivo? Por que sua função não é implementada como um programa simples? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 Como ver as últimas linhas x do log de serviço systemctl 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - pule para o final do arquivo 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla Por que verdadeiro e falso são tão grandes? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis Substitua a string em um arquivo de texto enorme (70 GB), uma linha 2017-12-30 06:58:33 +0800 CST

Hot tag

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve