Jat*_*rya 34 bash shell concurrency
GNU bash,版本1.14.7(1)
我有一个脚本被称为" abc.sh"我必须从abc.sh脚本中检查这个...在其中我写了以下语句
status=`ps -efww | grep -w "abc.sh" | grep -v grep | grep -v $$ | awk '{ print $2 }'`
if [ ! -z "$status" ]; then
echo "[`date`] : abc.sh : Process is already running"
exit 1;
fi
Run Code Online (Sandbox Code Playgroud)
我知道这是错的,因为每次它退出,因为它在'ps'中找到了自己的进程如何解决它?如何检查脚本是否已经运行from that script?
Aus*_*ips 48
检查已经执行的进程的更简单方法是pidof命令.
if pidof -x "abc.sh" >/dev/null; then
echo "Process already running"
fi
Run Code Online (Sandbox Code Playgroud)
或者,让脚本在执行时创建一个PID文件.然后,这是一个检查PID文件是否存在的简单练习,以确定该进程是否已在运行.
#!/bin/bash
# abc.sh
mypidfile=/var/run/abc.sh.pid
# Could add check for existence of mypidfile here if interlock is
# needed in the shell script itself.
# Ensure PID file is removed on program exit.
trap "rm -f -- '$mypidfile'" EXIT
# Create a file with current PID to indicate that process is running.
echo $$ > "$mypidfile"
...
Run Code Online (Sandbox Code Playgroud)
更新:
现在问题已更改为从脚本本身进行检查.在这种情况下,我们希望总能看到至少一次abc.sh运行.如果有多个abc.sh,那么我们知道该进程仍在运行.我仍然建议使用该pidof命令,如果进程已经运行,它将返回2个PID.您可以使用grep过滤掉当前PID,在shell中循环,甚至还可以恢复为仅计数PID wc来检测多个进程.
这是一个例子:
#!/bin/bash
for pid in $(pidof -x abc.sh); do
if [ $pid != $$ ]; then
echo "[$(date)] : abc.sh : Process is already running with PID $pid"
exit 1
fi
done
Run Code Online (Sandbox Code Playgroud)
Aba*_*Aba 24
我想要"pidof"方法,这就是诀窍:
if pidof -o %PPID -x "abc.sh">/dev/null; then
echo "Process already running"
fi
Run Code Online (Sandbox Code Playgroud)
凡-o %PPID参数告诉省略调用shell或shell脚本的PID.pidof手册页中的更多信息.
Mac*_*dav 13
if [[ `pgrep -f $0` != "$$" ]]; then
echo "Another instance of shell already exist! Exiting"
exit
fi
Run Code Online (Sandbox Code Playgroud)
编辑:我最近查看了一些评论,所以我尝试尝试进行一些调试。我也会解释一下。
因此,pgrep 检查您的脚本 PID ($0) 是否等于当前运行的脚本 ($$)。如果是,则脚本正常运行。如果不是,则意味着有另一个具有相同文件名的 PID 正在运行,因此它会退出。pgrep -f $0我使用而不是的原因pgrep bash是你可以运行多个 bash 实例,从而返回多个 PID。根据文件名,它仅返回单个 PID。
bash script.shnot,./script.sh因为除非你有 shebang,否则它不起作用。
#!/bin/bash一开始就使用shebang。if [[ `pgrep -f $0` != "$$" ]]; then
echo "Another instance of shell already exist! Exiting"
exit
fi
Run Code Online (Sandbox Code Playgroud)
vim script.sh然后运行bash script.sh,它会失败,因为 vim 用相同的文件名打开
twa*_*erg 10
这是你在各个地方看到的一个技巧:
status=`ps -efww | grep -w "[a]bc.sh" | awk -vpid=$$ '$2 != pid { print $2 }'`
if [ ! -z "$status" ]; then
echo "[`date`] : abc.sh : Process is already running"
exit 1;
fi
Run Code Online (Sandbox Code Playgroud)
围绕[a](或选择不同的字母)的括号可防止grep发现自己.这使得这个grep -v grep位不必要.我也删除grep -v $$并修复了awk部分以完成同样的事情.
如果我在这里错了,有人请把我击倒
我知道该mkdir操作是原子操作,因此您可以创建一个锁定目录
#!/bin/sh
lockdir=/tmp/AXgqg0lsoeykp9L9NZjIuaqvu7ANILL4foeqzpJcTs3YkwtiJ0
mkdir $lockdir || {
echo "lock directory exists. exiting"
exit 1
}
# take pains to remove lock directory when script terminates
trap "rmdir $lockdir" EXIT INT KILL TERM
# rest of script here
Run Code Online (Sandbox Code Playgroud)
小智 6
我发现@Austin Phillips 的答案恰到好处。我要做的一个小改进是添加 -o(忽略脚本本身的 pid)并使用 basename 匹配脚本(即相同的代码可以放入任何脚本中):
if pidof -x "`basename $0`" -o $$ >/dev/null; then
echo "Process already running"
fi
Run Code Online (Sandbox Code Playgroud)
这是我在bash脚本中执行的操作:
if ps ax | grep $0 | grep -v $$ | grep bash | grep -v grep
then
echo "The script is already running."
exit 1
fi
Run Code Online (Sandbox Code Playgroud)
这使我可以将此片段用于任何bash脚本。我需要grep bash,因为与cron一起使用时,它创建了另一个使用/ bin / sh执行它的进程。
小智 5
pidof不适合我,所以我又搜索了一些,发现了pgrep
for pid in $(pgrep -f my_script.sh); do
if [ $pid != $$ ]; then
echo "[$(date)] : my_script.sh : Process is already running with PID $pid"
exit 1
else
echo "Running with PID $pid"
fi
done
Run Code Online (Sandbox Code Playgroud)
部分摘自上面的答案和https://askubuntu.com/a/803106/802276