Uso da memória de um shell script infinitamente em loop

3

Então, eu tenho um shell script para atualizar um banco de dados MySQL que se parece com isso:

#!/bin/sh
mysql -h "localhost" -u "root" "-p********" "database" < "update.sql"
sleep 5
sh $0

Ele dorme por 5 segundos e, em seguida, o sh $0 executa novamente o script infinitamente, sem minha intervenção. No entanto, minha pergunta é sobre memória:

Eu sou relativamente novo em scripts de shell, mas a memória está se acumulando lentamente em um loop como esse? O servidor remoto recicla a memória ou o roteiro chegará a um ponto final? (Ou vai falhar de um vazamento de memória?)

    
por adamdesign 07.08.2015 / 21:20

2 respostas

5

Isso não é um loop, mas a recursão e a memória aumentam linearmente ao longo do tempo, que é o que você não quer.

Se você quiser um loop com uso constante de memória, poderá fazê-lo desta maneira:

#!/bin/sh
while 1; do
  mysql -h "localhost" -u "root" "-p********" "database" < "update.sql"
  sleep 5
done
    
por 07.08.2015 / 21:28
1

Depende do shell. Alguns fazem otimização de chamada de cauda, outros não. Você pode testar isso facilmente executando SHELL -c 'ps $$' . Se ps se ver, o shell executou o último comando no mesmo processo. Se ps vir o shell, o shell executará o último comando em um subprocesso, como ocorre com os comandos que não são o último.

$ for s in dash bash mksh ksh zsh; do echo -n "$s "; $s -c 'ps -o comm= $$'; done 
dash dash
bash ps
mksh mksh
ksh ps
zsh ps

Então bash, ksh e zsh do tail chamam otimização, dash e mksh não.

Otimização de chamada de cauda só pode ser feita para o último comando em um script. Por exemplo, se houver uma armadilha ativa, ela não será uma chamada final, já que o shell precisa ficar para trás caso a armadilha seja acionada.

Você pode forçar uma chamada final colocando exec na frente do comando. O exec builtin executa o comando especificado no mesmo processo. Comandos adicionais no script não serão executados desde que o shell tenha desaparecido.

A recursão não é idiomática em scripts de shell. Seria mais idiomático usar um loop:

#!/bin/sh
while true; do
  mysql -h "localhost" -u "root" "-p********" "database" < "update.sql"
  sleep 5
done

ou, se você quiser que o script seja encerrado se o comando sleep for eliminado por um sinal:

#!/bin/sh
while
  mysql -h "localhost" -u "root" "-p********" "database" < "update.sql"
  sleep 5
do
  :
done

ou, se você quiser que o script seja encerrado se mysql falhar:

#!/bin/sh
while
  mysql -h "localhost" -u "root" "-p********" "database" < "update.sql"
do
  sleep 5
done
    
por 10.08.2015 / 01:21