У меня есть вот этот прекрасный маленький код, который завершит работу скрипта, если запущен другой его экземпляр:
single_instance(){
if pidof -x "${0##*/}" -o %PPID >/dev/null; then
exit 0
fi
}
Но я ищу функцию, которая выйдет только в том случае, если скрипт был завершен.вызван с теми же аргументами.
Я знаю, что я мог бы придумать решение cat | grep | awk | cut | sed | tac | sort | uniq
, но мне интересно, есть ли простой способ сделать это с помощью таких утилит, как pidof
, ps
и т. д.
Как бы вы это сделали?
решение1
Вы можете сделать что-то вроде этого:
#!/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
решение2
Я придумал это после изучения man ps
и добавления некоторого кода из @goldilocks. Он хорошо справляется с обработкой аргументов с пробелами, а также работает, если скрипт вызывается как bash scriptname
:
single_instance(){
if ps -efww | grep "$(ps -o cmd= -p $$)$" | grep -vq " $$ "; then
exit 0
fi
}
решение3
fn() { IFS='
'; set -- $(ps -o args= -C "${0##*/}")
unset IFS
[ $(($(printf $(printf %s\\n "$@" | sort | uniq -c | sort -rn)))) -gt 1 ] &&
exit 0
}
Это произойдет exit 0
, если в данный момент запущены два или более $0
процессов, вызванных с одинаковыми аргументами.
решение4
С использованием/проц:
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
}
Он делает точное сравнение между командными строками без пути запуска (как вы делали в своем скрипте). Значения /proc/*/cmdline
не содержат пробелов, поэтому вы можете сравнивать их напрямую. Однако если порядок параметров изменится, он этого не заметит.