Eu tenho este pequeno código lindo aqui que sairá de um script se houver outra instância dele em execução:
single_instance(){
if pidof -x "${0##*/}" -o %PPID >/dev/null; then
exit 0
fi
}
Mas o que estou procurando é uma função que só sairá se o script tiver sidochamado com os mesmos argumentos.
Eu sei que poderia hackear uma cat | grep | awk | cut | sed | tac | sort | uniq
solução, mas me pergunto se existe uma maneira simples de fazer isso com utilitários como pidof
, ps
etc.
Como você faria isso?
Responder1
Você pode fazer algo assim:
#!/bin/bash
single_instance() {
pid=$(pidof -x "${0##*/}" -o %PPID)
if [[ $(xargs -0 < /proc/$pid/cmdline) == $@ ]]
then
echo QUITTING
exit 1
fi
}
single_instance $(xargs -0 < /proc/$$/cmdline)
while :
do
sleep 10
done
Responder2
Eu descobri isso depois de estudar man ps
e adicionar alguns códigos de @goldilocks. Ele faz um bom trabalho ao lidar com argumentos com espaços e também funciona se o script for chamado como bash scriptname
:
single_instance(){
if ps -efww | grep "$(ps -o cmd= -p $$)$" | grep -vq " $$ "; then
exit 0
fi
}
Responder3
fn() { IFS='
'; set -- $(ps -o args= -C "${0##*/}")
unset IFS
[ $(($(printf $(printf %s\\n "$@" | sort | uniq -c | sort -rn)))) -gt 1 ] &&
exit 0
}
Isso ocorrerá exit 0
se dois ou mais $0
processos estiverem em execução e foram invocados com os mesmos argumentos.
Responder4
Usando/proc:
single_instance(){
local tl=$(cat /proc/$$/cmdline)
local l
tl=${tl##*/}
for pid in $(pidof -x "${0##*/}" -o %%PPID); do
l=$(cat /proc/$pid/cmdline)
if [ ${l##*/} = $tl ]; then
echo "already running..."
exit 0
fi
done
}
Ele faz uma comparação exata entre linhas de comando sem o caminho de inicialização (como você fez no seu script). Os /proc/*/cmdline
valores não possuem espaço, então você pode compará-los diretamente. Se a ordem dos parâmetros mudar, ele não notará isso.