8

I want to make sure that only one script can be run by any regular user of a system at a time. There can be multiple users logged in and each of them should only be able to run a command after any running commands of other users have finished.

A long time ago on UNIX I was using the batch command with a proper "one task only" queue definition to serialize scripts execution. It solved lot of lock management problems (it needed only a simple timeout to set in the scripts).

Now on Linux the batch command performs differently, one task is run at each minute, tasks run in parallel until 1.5 load average is reached.

I made my own lock management shell library to serialize execution but I wonder if there is a standard command for doing that.

8
  • Isn't it just a case of using wait? Dec 5, 2017 at 13:47
  • There's no need for "edit" here, we have the edit history if we need to check it. When editing, try to make it as though the question were written that way from the beginning. Basically, think of someone who reads it for the first time after the edit. I tried to clarify a bit, please check and make sure I didn't get it wrong. You will also have to specify what a "task" is. Presumably, you don't mind if they start multiple shell instances in parallel. So what processes are these? Are you asking for a way for users to submit jobs to a server? A queuing system perhaps?
    – terdon
    Dec 5, 2017 at 14:02
  • @terdon A task is something that is run by the server. I am looking to a way that permit to avoid parallelism of some task. I have control on what the task does but I have no control of when the task will run and by whom. I know that running these tasks in parallel will result of in-predictable situation.
    – Emmanuel
    Dec 5, 2017 at 14:20
  • OK, but what is a task? Is an ssh session a task? A shell session? Can they open a text editor? Can users connect to this server directly or will they be using some job submission system? Do you need to split tasks among multiple nodes? It is starting to sound as though you're after a queuing system. Is that what you mean?
    – terdon
    Dec 5, 2017 at 14:24
  • @terdon one recent example (of many) was : some backup are performed on a server, it can be made on demand by a customer using an application interface and also made manually by a technician or scheduled. That backup triggers snaphosts operation on a disk array that do not support having snapshot build at the same time
    – Emmanuel
    Dec 5, 2017 at 14:26

3 Answers 3

5

flock is really excellent for this. You can use flock in a wrapper around your shell script, use it on the command line, or incorporate it into your script itself.

The best thing about flock is that while it waits, it doesn't wait in a busy loop.

It also always cleans up the lock when your process exits / flock exits.

Methods based on atomic file/directory creation can get locked out if the process exits without cleaning up (or if there is a kernel panic, or power failure, ...).

With flock, the Linux kernel does the cleanup.

From the manual,

(
flock -s 200  
# ... commands executed under lock ...
) 200>/var/lock/mylockfile

In this form you can wrap a specific block of code in your shell script.

Or you can run it like this,

/usr/bin/flock /tmp/lockfile command

If you don't want to block/wait indefinitely, you can specify a timeout:

-w  --timeout <secs>     wait for a limited amount of time

Or just use a non blocking argument:

-n  --nonblock           fail rather than wait
1
  • Great thanks to you my scripts are going to be shorter.
    – Emmanuel
    Dec 8, 2017 at 2:50
1

Maybe what you want here is a hard limit of number of processes your user can run? Make sure you include their shell's process and any other necessary things that will need to be run during their session.

This can be set in /etc/security/limits.conf Add a line like:

testuser hard nproc 2

Note that this will throw an error about not being able to fork if there are too many things trying to run at once. Change 2 to suit your needs and 'testuser' to the user you want to limit.

3
  • I think I misunderstood what you are trying to do. Dec 5, 2017 at 14:31
  • yes but that's interesting anyway
    – Emmanuel
    Dec 5, 2017 at 14:36
  • A process limit would still require some control logic to make sure the batch system reacts sanely to getting EAGAIN from fork(). And a process limit as low as two two would make e.g. doing anything over SSH impossible, and most other things very, very limited.
    – ilkkachu
    Dec 5, 2017 at 15:48
0

Use mkdir which is an atomic process to lock other out. Only one at the time kan make a directory:

#!/bin/bash
if ! mkdir /tmp/TheLock 2> /dev/null ; then
    echo Error, user \'$(stat -c %U /tmp/TheLock)\' has the task
else
    echo Yes, I got it\!
    sleep 1 # do stuff
    rmdir /tmp/TheLock
fi

If you run the script first, it will read out:

Yes, I got it!

If somebody try to run it at the same time, the output would be:

Error, user 'Emmanuel' has the task
2
  • Actually was using also the filesystem for that purpose using while ! ln -s $$ Thelock. Advantage you got the pid of the owner with ls -l TheLock and then you can check in the loop if the lock in orphaned and also manage lock timeout or reset the timeout if owner of lock has changed and many complicated lock management... that's why i was looking for a simple way to queue tasks
    – Emmanuel
    Dec 5, 2017 at 16:36
  • I have not invented that ln -s $$ lockfile. Netscape browser in the 90s was using the same method.
    – Emmanuel
    Dec 5, 2017 at 16:47

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .