Usando um diretório de bloqueio:
#!/bin/sh
lockdir=${TMPDIR:-/tmp}/mylock
if ! mkdir "$lockdir" 2>/dev/null; then
exit 1
fi
trap 'rmdir "$lockdir" 2>/dev/null' EXIT HUP INT TERM
# The rest of code goes here.
Usar um diretório de bloqueio é mais seguro do que usar um arquivo de bloqueio. Se estiver usando um arquivo, você teria que fazer um teste separado para a existência do arquivo antes de criá-lo. No intervalo entre essas duas operações, outra instância do script pode tentar fazer o mesmo. O utilitário mkdir
fornece uma operação atômica "create-if-not-exist".
Ressalva: O código acima não detecta se o script já está em execução, mas se o diretório de bloqueio existe. Se o script terminar de forma anormal, por ex. por ser morto por SIGKILL
, o diretório de bloqueio será deixado para trás e nenhuma nova instância do script poderá ser iniciada.
A seguinte variação tenta detectar um diretório de bloqueio que foi deixado para trás por um script finalizado anormalmente. Apenas detecta o bloqueio que sobrou, mas não tenta fazer qualquer limpeza (isto introduziria novas condições de corrida).
#!/bin/sh
lockdir=${TMPDIR:-/tmp}/mylock
if { read pid <"$lockdir/pid" && ! kill -0 "$pid"; } 2>/dev/null then
printf 'Detected left-over lock "%s"\n' "$lockdir" >&2
exit 1
fi
if ! mkdir "$lockdir" 2>/dev/null; then
echo 'Could not get lock' >&2
exit 1
fi
printf '%d\n' "$$" >"$lockdir/pid"
trap '{ rm "$lockdir/pid" && rmdir "$lockdir"; } 2>/dev/null' EXIT HUP INT TERM
# The rest of code goes here.
O comando ! kill -0 "$pid"
será verdadeiro se $pid
não referir-se a um ID de processo alocado atualmente para um processo em execução.