script BASH - executa o comando na variável

1

Estou fazendo um script bash para fazer backup do banco de dados diariamente (no Mac OS X) e quero salvar os 7 diretórios de backup mais recentes. Aqui está o fragmento problemático do meu script (para listar tudo, exceto os diretórios mais recentes):

# Assigning a value to a variable named NUMBEROFFOLDERS. 
NUMBEROFFOLDERS=7

# Command that leaves the newest NUMBEROFFOLDERS and removes everything else. 
TOBEDELETED='(ls -t|head -n $(($NUMBEROFFOLDERS));ls)|sort|uniq -u|sed -e 's,.*,"&",g'|xargs rm -rfv'

# Executing the TOBEDELETED command. 
eval "$TOBEDELETED"

P.S. O comando designado no TOBEDELETED funciona quando eu o insiro em uma janela do Terminal, mas quando executo o script, nada acontece.

EDITAR: i) O script deve listar todos os diretórios em um destino específico duas vezes de maneira diferente; sort deveria analisá-los e apenas os diretórios mais recentes serão retirados da lista; O sed deve tratar todos os espaços corretamente e o rm -rfv irá deletar todos os diretórios das listas (diretórios a serem deletados) com todos os seus arquivos.

ii) O script deve deixar as pastas $ NUMBEROFFOLDERS mais recentes.

iii) Eu não recebi um erro. Eu acredito que o problema é quando me refiro à variável do comando atribuído.

    
por Anton Todorov 21.03.2015 / 15:44

3 respostas

1

Uma solução de trabalho não tão elegante (confira seu ambiente:
Vamos começar com uma abordagem dividi e impera porque é mais claro:

ListToSave=$(ls -dt */ |head -n $NUMBEROFFOLDERS| cut -f1 -d'/';)

Esta linha armazena a lista de pastas a serem salvas na variável ListToSave , talvez reciclável posteriormente no script ...

echo "$ListToSave"| awk 'BEGIN{printf("find . -maxdepth 1 -not -path \".\" ")}\
 {printf ("-not -path \"./"$0"\" ") } \
 END{print " -exec /bin/rm -rvf \"{}\" \; "}' | /bin/sh

Com este comando de 3 linhas abrangidas, você constrói um comando find para excluir todos os diretórios, exceto os que serão salvos, e executá-lo em um shell (neste caso, /bin/sh ).
Você pode verificar a construção do comando apagando o pipe para o shell | /bin/sh .
Por razões de segurança, é sempre mais seguro executar o comando com o caminho completo. (melhor /bin/rm then rm , apenas para evitar algum trojan)

Comentário: Não é seguro analisar a saída de ls quando você planeja fazer um script. Acontece com frequência que você começa com uma situação limitada e sob controle; depois de algum tempo, quando você já esqueceu, você deve tentar usar em um caso mais complexo e menos sob controle. Quando finalmente você está convencido de que tudo funciona bem ... acontece alguma coisa e você percebe tarde demais.

Notas:

  1. Não é seguro analisar a saída de ls ... verifique aqui, ou seja,
  2. ls -dt */ | cut -f1 -d'/' deve listar apenas os diretórios e nem mesmo os arquivos.
  3. xargs executa imediatamente a linha de comando, como você pode ler em sua página de manual

    xargs - build and execute command lines from standard input

Eu sugiro que você evite fazer o que segue .
Se você quiser, no entanto, analisar ls , você pode escrever como uma modificação mínima da sua tentativa anterior algo semelhante a este

TOBEDELETED='(ls -dt */ |head -n $NUMBEROFFOLDERS | cut -f1 -d'/'; ls)| sort | uniq -u | xargs echo "rm -rfv"'

desta forma você terá a saída armazenada em TOBEDELETED que você pode executar mais tarde no script enquanto escreve.

Observação: não funciona com nomes de arquivos kind como espaços, \t , \n ... e pode criar efeitos colaterais imprevisíveis. Imagine que você tenha que deletar o diretório "1 bis", mas não o diretório "1" que existe também. Você irá deletar o diretório "1" e você terá um erro quando tentar deletar o diretório "bis" se isso não existir.

    
por 21.03.2015 / 17:33
4

Você não está fazendo o que acha que está fazendo

# Command that leaves the newest NUMBEROFFOLDERS and removes everything else. 
TOBEDELETED='(ls -t|head -n $(($NUMBEROFFOLDERS));ls)|sort|uniq -u|sed -e 's,.*,"&",g'|xargs rm -rfv'

Os backticks significam que o pipeline é realmente executado, e a saída do comando rm é capturada na variável. Esta saída não contém comandos, é apenas a saída rm -v .

Eu simplificaria esse comando:

stat -f "%m %N" * | sort -nr | sed -e "1,${numfolders}d" | cut -d " " -f 2 | xargs rm -rfv

Eu não tenho um sistema BSD para brincar, então não tenho certeza se a string stat está correta.

    
por 21.03.2015 / 17:09
0

Eu adiciono outra resposta com um construtor ambiente de teste . Eu criei um projeto executável compartilhado aqui .
Siga o link escreva no shell bash main.sh . Funciona. Depois copie o script em seu sistema e verifique se funciona. Se não postar o erro que você recebe.

#!/bin/bash
printf "\n\n\n# Let's we create your test directory\n" 
TESTDIR="tmptmp"
    rm -rf $TESTDIR
    mkdir $TESTDIR
    cd $TESTDIR
      printf "\n### Now we are in \n"
        pwd 
        mkdir -p 1 2 3 4 5 6 7 8 9 "1 bis";
      printf "\n### Here the list in the creation order\n"
         ls -dt */
         sleep 1.5s             # Take your time ...
         touch 1 2 3 4 5 6 8;   # Make those the last modified
      printf "\n### Here the list with modified order\n"
         ls -dt */

printf "\n\n# Let's go with your script \n\n"

#
# It follows your script. You can put it where you prefer but not in the 
# directory that you want to delete else you can delete it too...
# If you put in the upper directory you can run it with: 
# /bin/bash ../myscript.sh
#
# If you do one time 'chmod u+x myscript.sh' you can execute it with
# ../myscript 
# Remember to put as a 1st line "#!/bin/bash"
# Note: check the path of all the executable... 
#

#!/bin/bash
NUMBEROFFOLDERS=7
ListToSave=$(ls -dt */ |head -n $NUMBEROFFOLDERS| cut -f1 -d'/';)
printf "This is the list of directories to be saved:\n%s\n" "$ListToSave"

printf "\n# That's the command that you'll execute piping it into a shell\n"
echo "$ListToSave" \
     | awk 'BEGIN{printf("find . -maxdepth 1 -not -path \".\" ")}\
     {printf ("-not -path \"./"$0"\" ") } \
     END{print " -exec /bin/rm -rvf \"{}\" \; "}' 
  sleep 1 ; 

printf "\n# NOW we execute those commands with \"the power of piping\" \n\n"
 echo "$ListToSave" \
      | awk 'BEGIN{printf("find . -maxdepth 1 -not -path \".\" ")}\
 {printf ("-not -path \"./"$0"\" ") } \
 END{print " -exec /bin/rm -rvf \"{}\" \; "}' | /bin/sh


printf "\n# That's the list of the survived as 'ls -d *' says to us\n\n"
ls -d *
printf "\n\n ### It worked like a charm ###\n\n"

exit 0

Observação: se você executá-lo com bash -f main.sh , isso não funcionará porque você pedirá a bash para evitar a Expansão de nome de caminho . Pesquise sobre isso em man bash .

    
por 25.03.2015 / 09:18