Perigos de usar o comando rm com variáveis

1

Estou criando um crontab que compacta clipes de 15 minutos da minha câmera de segurança em um arquivo (24 horas de duração) e, depois, os clipes são excluídos.

avimerge -o /media/jmartin/Cams/video/Full_$(date +%F --date "Yesterday") -i /media/jmartin/Cams/video/$(date +%F --date "Yesterday")* # Converts files from the past 24 hours into one .avi

rm /media/jmartin/Cams/video/$(date +%F --date "Yesterday")* # Removes old clips that have already been compressed

Minha pergunta é qual é o perigo de usar a variável $ date. Alguma coisa poderia acontecer onde ele apaga todos os arquivos em / video /? O que você recomendaria como uma alternativa mais segura?

Exemplo de nomes de arquivos (Sim, esses são espaços no nome do arquivo):

2016-04-25 00:00:01.avi  
2016-04-25 00:15:02.avi 
2016-04-25 00:30:02.avi  
2016-04-25 00:45:01.avi  
    
por SimplePi 25.04.2016 / 17:09

4 respostas

2

Duas coisas surgem:

  1. Você não tem verificação de falha da substituição
  2. Existe uma condição de corrida se a data for alterada entre os usos do comando date .

Você poderia resolvê-los assim:

#/bin/bash

# Exit if any command fails
set -e

dir='/media/jmartin/Cams/video'
day=$(date +%F --date Yesterday)

# Conbine files from the past 24 hours into a single AVI file
avimerge -o "$dir/Full_$day" -i "$dir/$day"*

# Remove old clips that have already been compressed
rm "$dir/$day"*
    
por 25.04.2016 / 17:23
5

O $(date +%F --date "Yesterday") tecnicamente não é uma variável, é uma substituição de comando, mas isso é tangencial à sua pergunta. Essa construção pode se mostrar problemática se, por algum motivo, o comando date não estiver no seu $PATH e, portanto, não retornar nada - nesse ponto, ele excluiria tudo em /video/ . Se, em vez disso, você tomar essa substituição de comando e atribuí-la a uma variável anterior ao comando avimerge , use essa variável nos comandos avimerge e rm , não apenas garantindo que a sequência de datas seja operada não muda, mas você também é capaz de testar uma variável de comprimento zero antes que qualquer um dos comandos e (se você tiver uma cadeia de comprimento zero) saia antes de fazer algo que você não deseja.

    
por 25.04.2016 / 17:14
1

Contanto que você tenha acertado o roteiro e não o execute em um ambiente estranho, tudo ficará bem.

Mas se algo quebra a saída esperada de date , todas as apostas estão desativadas. Por exemplo, se você executar este snippet com IFS=- , estará executando algo como

rm /media/… 04 26*

i.e. exclua os arquivos que começam com 26 no diretório atual. É claro que isso é devido a um erro de novato em seu script: você esqueceu as aspas duplas em torno da substituição do comando .

rm "/media/jmartin/Cams/video/$(date +%F --date "Yesterday")"*

Isso, pelo menos, garante a não exclusão de arquivos fora do diretório de destino.

Uma abordagem mais segura aqui seria fazer uma limpeza preparada. Então, se algo der errado, você tem algum tempo para notar.

#!/bin/sh
set -e
cd /media/jmartin/Cams/video
if [ -d yesterday ]; then
  find yesterday -type f -delete
else
  mkdir yesterday
fi
mv "$(date +%F --date "Yesterday") "* yesterday/
    
por 26.04.2016 / 01:21
1

Como há sempre um espaço em seus nomes de arquivos, incluo isso em seu comando:

rm "$(date +%F --date "Yesterday") "* # Removes old clips

Essa deve ser uma maneira fácil de evitar a exclusão de todos os arquivos no diretório, pois mesmo que date não retorne nada, ele excluirá apenas os arquivos que começam com um caractere de espaço (que, esperamos, não existam).

No entanto, existem vários outros perigos, por exemplo

  • avimerge pode falhar de alguma forma e você acaba excluindo arquivos que não foram mesclados ...
  • avimerge pode levar um tempo considerável e no momento em que rm é executado, ontem é hoje e você acaba excluindo as coisas erradas ...

Basicamente, é uma má idéia confiar cegamente em que esse comando fez o que você queria. Para a exclusão automática, você deve verificar e checar tudo e usar suas variáveis adequadamente.

Você deve colocar o resultado de date em uma variável real, verificar com o que a variável se parece e, em seguida, usar a mesma variável para ambos os comandos, para que não seja possível mudar entre eles.

Você deve verificar os códigos de retorno (códigos de saída) dos comandos que você chama e somente prosseguir quando não houver erros retornados por eles (ou manipular especificamente os erros esperados).

Você deve verificar se o arquivo mesclado foi criado e se tem um tamanho de arquivo realista.

    
por 25.04.2016 / 17:24

Tags