Today I learned from the flock(1) man page (on Debian) that you can put this line at the top of a shell script to prevent more than one copy of it from ever running at a time:

[ "${FLOCKER}" != "$0" ] && exec env FLOCKER="$0" flock -en "$0" "$0" "$@" || :

This is an extremely clever hack and I don't know how I've never stumbled upon it in 38 years of writing shell scripts.
#unix #linux #scripting #shellScripting

[ $(pgrep -x $(basename $0) | wc -l) -gt 1 ] && exit
@kostikov This alternative solution has several problems:
1) It will do the wrong thing if multiple scripts on your system have the same basename.
2) It won't work for scripts whose names are more than 15 characters long.
3) At least in Debian, pgrep is not available on every system but flock is.
It also has a behavior difference: it will treat symlinks to a script as different commands, though that may actually be the behavior you want, so it's not necessarily wrong.
@Jonathan Kamens
pgrep
No problem, we can always use ps + grep.
@kostikov I still don't see how this is in any way superior to the original flock solution I posted above.
@Jonathan Kamens
I still don't see how this is in any way superior to the original flock solution I posted above
Easy. It's because you don't need to use a non-standard flock.
@kostikov Your original proposed alternative used pgrep, which is even more non-standard than flock.
As I noted above, flock is included in all Debian installs; it is in util-linux, which is an essential package. Pgrep is in procps, which isn't.
And I pointed out several ways your solution doesn't work, only one of which you addressed, and a way in which it behaves differently from the solution I posted.
I do not feel like you are adding anything useful here.
@Jonathan Kamens
Your original proposed alternative used pgrep, which is even more non-standard than flock.
I just showed how to do it in a more obvious and shorter way.
To summarize, I'm sure that if you think about it a bit you can write an expression that will work on most UNIX-like systems (yes, there is life beyond Debian and even Linux) using the most general tools available in any of them, which in my opinion is always better than using system-specific utilities.

@kostikov "I just showed how to do it in a more obvious and shorter way."

…a way which, as I've already explained, is wrong.

"To summarize, I'm sure that if you think about it a bit…"

Or maybe you could have thought about it a bit before wasting my time and others' posting an incorrect solution which is inferior to the one I posted.

Blocking you now, you've proved yourself to be not worth my time.

@Jonathan Kamens I wish you don't burst with a sense of self-importance and grandeur 
@Jonathan Kamens
…a way which, as I've already explained, is wrong.
For the rest of you, I inform you that the above arguments are ridiculous.
And that's why.

1) It will do the wrong thing if multiple scripts on your system have the same basename.
Yes, it's a colossal problem. After all, we can't not use basename.  

2) It won't work for scripts whose names are more than 15 characters long.
Really?  
# ps auxw | grep test0123456789123456.sh
root      835628  0.0  0.0   2892   940 pts/0    S    15:28   0:00 /bin/sh ./test0123456789123456.sh
root      835657  0.0  0.0   6628  2448 pts/0    S+   15:28   0:00 grep --color=auto test0123456789123456.sh
# echo test0123456789123456.sh | wc -c
24

3) At least in Debian, pgrep is not available on every system but flock is.
This is a huge problem.  
Since my opponent doesn't want to think and apparently doesn't know how to think very well, I'll do it for him.
[ $(ps auxw | grep $0 | grep -v grep | wc -l) -gt 1 ] && exit
or shorter but less obvious
[ $(ps auxw | grep $0 | wc -l) -gt 2 ] && exit
Works on any UNIX-like system.

In general, it saddens me to see this level of incompetence, particularly if the opponent's stated seniority is consistent with reality.
@jik I have put this into a script before that's job is to generate a zone file #dns.
@jik at the cost of a sub- and a sub-sub-process if I understood correctly, right?
@nils_ballmann The flock process replaces the original shell process thanks to the exec, and yes, flock runs the shell script itself as a subprocess, so there's one level of subprocess, not two.
@jik ah true, I overlooked the exec. I think because of the env. 🤔