Is there a way I can do the following in a unix terminal:
- Start a long running process
- Add another long running process to start when the previous is done
- Repeat step 2 until I have queued the processes I need to have run
Reason I ask is that I have some long running stuff I need to do. I could put all the commands in a simple bash script and just execute that, but the problem is that I am not always sure exactly what I need to run. So if I start the script and then remember another one I should run, I need to hit ^C a bunch of times until all the processes are killed, edit the script and add my new process and then start the whole thing again.
What I specifically am doing right now is to copy a lot of large files on to various external hard drives, and since I don't know exactly which ones I need to copy and to where right now I'd like to start the ones I do know I need to copy, and then add to the queue as I figure out the rest.
Hope that made sense... Is anything like this possible?
The shell is perfect for that.
Ctrl-z
to suspend the program.Now run the queue like this:
You may not suspend this while loop or exit bash until the queue is done.
If you will need to log out (e.g. the programs will run for many days) then consider running the above steps in
screen
.Not very elegant, but quick and dirty:
You would need to substitute actual PIDs for
$!
if you've run intervening background jobs.The answer to your general question is: Absolutely. In the early days of computing, batch processing was the only way to do anything, and even when multi-user interactive systems were invented, batch-processing capability was the norm for large jobs. And it's still commonly done today in medium and large-scale environments using systems like Sun Grid Engine or Torque.
However, that's probably overkill for what you need. You could set up a more lightweight system to run scripts in a serial queue, but I don't think that approach is particularly well-suited to your specific task. Presuming parallel copies to different drives are acceptable, I think I'd attack it like this:
Create directory structure corresponding to your your target drives:
~/copysystem/drive1/
~/copysystem/drive2/
~/copysystem/drive3/
Install Incron.
Set up an incrontab entry for each of these directories, which runs your copy script automatically on IN_MOVED_TO.
Make your script either a) kill any previous instances of the same script when it starts or b) use a
mkdir
-based lockfile and block until the lock is cleared.Then, all you need to do is move files to the various
~/copysystem/drive#
directories, and they're all copied magically to your destination.Especially in case of 4a, you probably want to use
rsync -aP
to copy your files, so that you can restart partial transfers from the middle. (Possibly in combination with--remove-sent-files
, if you want to get rid of the originals.)If you want to skip the complication of using incron, you can still take advantage of making your scripts block on a lock file. That works something like this:
This works because
mkdir
is an atomic operation — if it succeeds, you know the directory didn't exist. That's important, because if you use something like! -f && touch
, there's a race condition. (Same with scanning the process table for rsync commands, or the like.)If this is something you'll be doing regularly, then its worth setting up some sort of scheduler to manage it for you.
I like the elegance of Aleksandr's solution - and it addresses all the points you originally raised - but I can see it does have limitations.
I've previously used the BSD lpd as a method for queueing jobs - the 'printer driver' is just a shell script so its easy to adapt to different tasks (in my case that meant managing 4 modems for polling data, sending faxes, SMS and other stuff).
What you want is a non-interactive command queue. Good news! I wrote one for you.
enqueue_cmd
:dequeue_cmd
:First, run
nohup ./dequeue_cmd &
, Then add your commands like so:The output appears in
/var/tmp/job_out
: