有没有一种方法可以将长时间运行的任务排队?

有没有办法在unixterminal中执行以下操作:

  1. 开始一个漫长的运行过程
  2. 添加另一个长时间运行的过程,以便在上一次完成时启动
  3. 重复第2步,直到我排队我需要运行的进程

我要问的原因是我有一些我需要做的很长时间的事情。 我可以把所有的命令放在一个简单的bash脚本中,然后执行它,但问题是我并不总是确定我需要运行什么。 因此,如果我启动脚本,然后记住另一个脚本,那么我需要多次敲击^ C,直到所有进程都被终止,编辑脚本并添加我的新进程,然后再次启动整个过程。

我现在特别在做的是将很多大文件复制到各种外部硬盘驱动器上,因为我不知道我需要复制哪些内容,现在要在哪里启动我知道我需要复制,然后添加到队列中,我找出其余的。

希望这是有道理的…有这样的可能吗?

壳是完美的。

  1. 开始第一个程序。
  2. 按下Ctrl-z暂停程序。
  3. 开始下一个程序。
  4. 重复步骤2和3将更多的程序添加到队列中。 所有的程序将处于暂停模式。
  5. 现在运行这样的队列:

     while fg; do :; done 

    在循环或退出bash之前,您可能不会暂停此操作,直到队列完成。

如果您需要注销(例如程序将运行多天),请考虑在screen运行上述步骤。

不是很优雅,但又快又脏:

 process1 & while kill -0 $! ; do sleep 1; done && process2 & while kill -0 $! ; do sleep 1; done && process3 & 

你需要用实际的PID代替$! 如果您已经运行了干预后台作业。

你的一般问题的答案是:当然。 在计算的早期,批处理是唯一可以做任何事情的方法,即使在多用户交互系统发明的时候,批量处理能力也是大型工作的常态。 目前在大中型环境中仍然普遍采用Sun Grid Engine或Torque系统 。

但是,这可能是你所需要的矫枉过正。 你可以设置一个更轻量级的系统来在串行队列中运行脚本,但是我不认为这种方法特别适合你的特定任务。 假设并行拷贝到不同的驱动器是可以接受的,我想我会这样攻击它:

  1. 创build与您的目标驱动器相对应的目录结构:

    ~/copysystem/drive1/ ~/copysystem/drive2/ ~/copysystem/drive3/

  2. 安装Incron 。

  3. 为这些目录中的每一个设置一个incrontab条目,这些目录在IN_MOVED_TO上自动运行您的副本脚本。

  4. 使你的脚本或者 a)当它启动时杀死同一个脚本的任何以前的实例,或者b)使用一个基于mkdir的锁文件,并阻塞,直到锁被清除。

然后,所有你需要做的就是将文件移动到各种~/copysystem/drive#目录,并且它们都被神奇地复制到你的目的地。

特别是在4a的情况下,您可能想要使用rsync -aP来复制您的文件,以便您可以从中间重新启动部分传输。 (可能与--remove-sent-files ,如果你想摆脱原件。)

如果你想避免使用incron的复杂性,你仍然可以利用脚本阻塞locking文件。 这是这样的:

 #!/bin/bash LOCKDIR="/var/run/copysystem/copysystem.lock" while ! mkdir $LOCKDIR ; do echo "waiting for lock" sleep 5 done trap rmdir $LOCKDIR EXIT rsync commands go here.... 

这是可行的,因为mkdir是一个primefaces操作 – 如果成功,就知道该目录不存在。 这很重要,因为如果你使用类似的东西! -f && touch ! -f && touch ,有一个竞赛条件。 (与扫描rsync命令的进程表等相同。)

如果这是你经常做的事情,那么值得设置一些调度器来为你pipe理。

我喜欢Aleksandr解决scheme的优雅 – 它解决了您最初提出的所有问题 – 但我可以看到它有一定的局限性。

我以前使用BSD lpd作为排队作业的方法 – “打印机驱动程序”只是一个shell脚本,因此它很容易适应不同的任务(在我的情况下,这意味着pipe理4个调制解调器数据,发送传真,短信和其他的东西)。

你想要的是一个非交互式的命令队列。 好消息! 我为你写了一个。

enqueue_cmd

 #!/usr/bin/perl -w # Enqueue a job use strict; use Fcntl qw(:flock); my $JOB_QUEUE_FILE = '/var/tmp/job_queue'; my $LOCK_TRIES = 5; my $LOCK_SLEEP = 1; my $jq; open $jq, ">> $JOB_QUEUE_FILE" or die "!open $JOB_QUEUE_FILE: $!"; my $locked = 0; LOCK_ATTEMPT: for (my $lock_tries = 0; $lock_tries < $LOCK_TRIES; $lock_tries++) { if (flock $jq, LOCK_EX) { $locked = 1; last LOCK_ATTEMPT; } sleep $LOCK_SLEEP; } $locked or die "could not lock $JOB_QUEUE_FILE"; for (@ARGV) { print $jq "$_\n"; } close $jq; 

dequeue_cmd

 #!/usr/bin/perl -w # Dequeue a jobs and run them use strict; use Fcntl qw(:seek :flock); use FileHandle; my $QUEUE_FILE = '/var/tmp/job_queue'; my $OUTPUT_FILE = '/var/tmp/job_out'; my $LOCK_TRIES = 5; my $LOCK_SLEEP = 1; my $JOB_SLEEP = 1; my $locked; my $jo; open $jo, ">> $OUTPUT_FILE" or die "!open $OUTPUT_FILE: $!"; $jo->autoflush(1); my $jq; open $jq, "+< $QUEUE_FILE" or die "!open $QUEUE_FILE: $!"; my @jobs = ( ); my $job; JOB: while (1) { if (-s $QUEUE_FILE == 0) { sleep $JOB_SLEEP; next JOB; } $locked = 0 LOCK_ATTEMPT: for (my $lock_tries = 0; $lock_tries < $LOCK_TRIES; $lock_tries++) { if (flock $jq, LOCK_EX) { $locked = 1; last LOCK_ATTEMPT; } sleep $LOCK_SLEEP; } $locked or die "could not lock $QUEUE_FILE"; seek $jq, 0, SEEK_SET or die "could not seek to start of file"; push @jobs, <$jq>; truncate $jq, 0 or die "could not truncate $QUEUE_FILE"; seek $jq, 0, SEEK_SET or die "could not seek to start of $QUEUE_FILE"; flock $jq, LOCK_UN; for $job (@jobs) { chomp $job; print $jo "## executing $job\n"; print $jo `$job`; } sleep $JOB_SLEEP; } 

首先,运行nohup ./dequeue_cmd & ,然后像这样添加你的命令:

 ./enqueue_cmd "echo 'hello world'" "sleep 5" "date" ./enqueue_cmd "ls /var/tmp" 

输出显示在/var/tmp/job_out

 tail -F /var/tmp/job_out ## executing echo 'hello world' hello world ## executing sleep 5 ## executing date Fri Dec 10 16:35:43 PST 2010 ## executing ls /var/tmp ff job_out job_queue ss