Bru*_*ger 23
几乎就像 nsg 的回答:使用锁定目录。在 linux、unix 和 *BSD 以及许多其他操作系统下,目录创建是原子的。
if mkdir $LOCKDIR
then
    # Do important, exclusive stuff
    if rmdir $LOCKDIR
    then
        echo "Victory is mine"
    else
        echo "Could not remove lock dir" >&2
    fi
else
    # Handle error condition
    ...
fi
Run Code Online (Sandbox Code Playgroud)
您可以将锁定 sh 的 PID 放入锁定目录中的一个文件中以进行调试,但不要陷入认为可以检查该 PID 以查看锁定过程是否仍然执行的陷阱。许多比赛条件都在这条道路上。
小智 21
要添加到Bruce Ediger 的答案中,并受到此答案的启发,您还应该为清理添加更多智能以防止脚本终止:
#Remove the lock directory
function cleanup {
    if rmdir $LOCKDIR; then
        echo "Finished"
    else
        echo "Failed to remove lock directory '$LOCKDIR'"
        exit 1
    fi
}
if mkdir $LOCKDIR; then
    #Ensure that if we "grabbed a lock", we release it
    #Works for SIGTERM and SIGINT(Ctrl-C)
    trap "cleanup" EXIT
    echo "Acquired lock, running"
    # Processing starts here
else
    echo "Could not create lock directory '$LOCKDIR'"
    exit 1
fi
Run Code Online (Sandbox Code Playgroud)
        Set*_*thu 13
确保运行单个 bash 脚本实例的另一种方法:
#!/bin/bash
# Check if another instance of script is running
pidof -o %PPID -x $0 >/dev/null && echo "ERROR: Script $0 already running" && exit 1
...
Run Code Online (Sandbox Code Playgroud)
pidof -o %PPID -x $0 如果现有脚本已在运行,则获取现有脚本的 PID;如果没有其他脚本正在运行,则以错误代码 1 退出
这可能太简单了,如果我错了,请纠正我。还ps不够简单?
#!/bin/bash 
me="$(basename "$0")";
running=$(ps h -C "$me" | grep -wv $$ | wc -l);
[[ $running > 1 ]] && exit;
# do stuff below this comment
Run Code Online (Sandbox Code Playgroud)
        尽管您已经要求无需额外工具的解决方案,但这是我最喜欢的使用方式flock:
#!/bin/sh
[ "${FLOCKER}" != "$0" ] && exec env FLOCKER="$0" flock -en "$0" "$0" "$@" || :
echo "servus!"
sleep 10
Run Code Online (Sandbox Code Playgroud)
这来自 的示例部分man flock,它进一步解释了:
这是 shell 脚本的有用样板代码。把它放在你想要锁定的 shell 脚本的顶部,它会在第一次运行时自动锁定自己。如果 env var $FLOCKER 未设置为正在运行的 shell 脚本,则在使用正确的参数重新执行之前执行 flock 并获取一个排他非阻塞锁(使用脚本本身作为锁文件)。它还将 FLOCKER env var 设置为正确的值,因此它不会再次运行。
需要考虑的要点:
flock,如果找不到,示例脚本会以错误终止更新:如果您的脚本可能通过不同的路径(例如,通过其绝对或相对路径)被$0调用,或者换句话说,如果在并行调用中不同,那么还需要使用realpath:
[ "${FLOCKER}" != "`realpath '$0'`" ] && exec env FLOCKER="`realpath '$0'`" flock -en "$0" "$0" "$@" || :
Run Code Online (Sandbox Code Playgroud)
        这是Anselmo 的答案的修改版本。这个想法是使用 bash 脚本本身创建一个只读文件描述符并用于flock处理锁。
script=`realpath $0`     # get absolute path to the script itself
exec 6< "$script"        # open bash script using file descriptor 6
flock -n 6 || { echo "ERROR: script is already running" && exit 1; }   # lock file descriptor 6 OR show error message if script is already running
echo "Run your single instance code here"
Run Code Online (Sandbox Code Playgroud)
与所有其他答案的主要区别在于,此代码不会修改文件系统,占用空间非常小,并且不需要任何清理,因为一旦脚本完成独立于退出状态,文件描述符就会关闭。因此,脚本失败或成功并不重要。