Ich habe hier diesen schönen kleinen Code, der ein Skript beendet, wenn eine andere Instanz davon ausgeführt wird:
single_instance(){
if pidof -x "${0##*/}" -o %PPID >/dev/null; then
exit 0
fi
}
Aber was ich suche, ist eine Funktion, die nur beendet wird, wenn das Skriptmit den gleichen Argumenten aufgerufen.
Ich weiß, dass ich mir eine Lösung ausdenken könnte cat | grep | awk | cut | sed | tac | sort | uniq
, aber ich frage mich, ob es dafür eine einfache Möglichkeit mit Dienstprogrammen wie pidof
, ps
usw. gibt.
Wie würden Sie dabei vorgehen?
Antwort1
Sie können etwa Folgendes tun:
#!/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
Antwort2
Ich bin darauf gekommen, nachdem ich man ps
Code von @goldilocks studiert und hinzugefügt hatte. Es ist gut im Umgang mit Argumenten mit Leerzeichen und funktioniert auch, wenn das Skript folgendermaßen aufgerufen wird bash scriptname
:
single_instance(){
if ps -efww | grep "$(ps -o cmd= -p $$)$" | grep -vq " $$ "; then
exit 0
fi
}
Antwort3
fn() { IFS='
'; set -- $(ps -o args= -C "${0##*/}")
unset IFS
[ $(($(printf $(printf %s\\n "$@" | sort | uniq -c | sort -rn)))) -gt 1 ] &&
exit 0
}
Dies ist der Fall exit 0
, wenn derzeit zwei oder mehr $0
Prozesse ausgeführt werden, die mit denselben Argumenten aufgerufen wurden.
Antwort4
Verwenden von/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
}
Es führt einen genauen Vergleich zwischen Befehlszeilen ohne den Startpfad durch (wie Sie es in Ihrem Skript getan haben). Die /proc/*/cmdline
Werte enthalten keine Leerzeichen, sodass Sie sie direkt vergleichen können. Wenn sich jedoch die Parameterreihenfolge ändert, wird dies nicht bemerkt.