Tengo este pequeño y hermoso código aquí que saldrá de un script si hay otra instancia ejecutándose:
single_instance(){
if pidof -x "${0##*/}" -o %PPID >/dev/null; then
exit 0
fi
}
Pero lo que estoy buscando es una función que salga sólo si el script ha sidollamado con los mismos argumentos.
Sé que podría abrirme camino con una cat | grep | awk | cut | sed | tac | sort | uniq
solución, pero me pregunto si hay una forma sencilla de hacerlo con utilidades como pidof
, ps
etc.
¿Cómo harías para hacer esto?
Respuesta1
Puedes hacer algo como esto:
#!/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
Respuesta2
Se me ocurrió esto después de estudiar man ps
y agregar código de @goldilocks. Hace un buen trabajo manejando argumentos con espacios y también funciona si el script se llama como bash scriptname
:
single_instance(){
if ps -efww | grep "$(ps -o cmd= -p $$)$" | grep -vq " $$ "; then
exit 0
fi
}
Respuesta3
fn() { IFS='
'; set -- $(ps -o args= -C "${0##*/}")
unset IFS
[ $(($(printf $(printf %s\\n "$@" | sort | uniq -c | sort -rn)))) -gt 1 ] &&
exit 0
}
Esto sucederá exit 0
si actualmente se están ejecutando dos o más $0
procesos que fueron invocados con los mismos argumentos.
Respuesta4
Usando/proceso:
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
}
Hace una comparación exacta entre líneas de comando sin la ruta de inicio (como lo hizo en su secuencia de comandos). Los /proc/*/cmdline
valores no tienen ningún espacio, por lo que puedes compararlos directamente. Sin embargo, si el orden de los parámetros cambia, no lo notará.