等待源Bash脚本完成后再次运行它

3

我有两个bash脚本...

第一个脚本(begin.sh)通过SSH2从外部PHP脚本接收变量(这些变量是动态的,因此在此脚本中不可见):

但它们看起来像这样:

 $1 = myfile.mp3
 $2 = artwork.jpg
 $3 = my title - my artist

这里是第一个脚本(begin.sh):

#!/bin/bash

. ./process.sh

以下是第二个脚本(process.sh):

#!/bin/bash

wget -O /root/incoming/shows/$1 http://remoteserver.com/files/$1;

exec lame --decode /root/incoming/shows/$1 - | /root/incoming/stereo_tool_cmd_64 - - -s /usr/incoming/settings/settings.sts | lame -b 128 - /root/incoming/processing/$1;

wait

mv /root/incoming/processing/$1 /var/www/html/processed/$1;

#Send Email when process is complete

recipients="somebody@somewhere.com"
subject="Podcast Submission"
from="somebodyelse@somewhere.com"
importLink="http://thisserveraddress.com/processed/$1"
artwork="http://anotherserver.com/podcast-art/$2"

message_txt=$(echo -e "A new podcast has been submitted.\n\nTitle : $3\n\nImport : $importLink")

/usr/sbin/sendmail "$recipients" << EOF
subject:$subject
from:$from

$message_txt
EOF

上述脚本中的过程非常耗时(大约需要8分钟才能完成),并且非常处理器密集型(使用约50%的CPU),因此我只想一次运行一个这样的进程。问题是,整个过程可以由多个用户随时远程执行。因此,我需要找到一种按照它们进来的顺序串行运行这些作业的方法。
我认为源代码进程将有效地排队作业,但实际上并不是这样。如果在它已经运行时再次执行脚本,则什么也不会发生。
有什么建议吗?
为了清晰起见,以下是process.sh脚本正在做的进一步解释....
首先,主机从remoteserver.com下载mp3文件
然后它取出下载的mp3文件并使用lame将其解码为wav,然后另一个应用程序对文件进行了大量的音频处理,之后将其重新编码回mp3。
完成后,它将新的mp3文件移动到公共可访问的文件夹中。
完成后,它发送电子邮件通知所有这些已经发生,并概述可以从中下载所有内容的各种链接。

你需要多个独立的begin.sh执行,以便在任何其他process.sh实例正在运行时不运行process.sh吗? - Etan Reisner
@EtanReisner 有点类似,我需要让begin.sh排队执行任务。我原以为通过对进程脚本进行源代码处理,它会等待当前进程完成后再启动新的进程,但实际上并不是这样。就像我之前提到的那样,如果在process.sh已经运行时执行begin.sh,它只会被忽略,新的进程永远不会被运行。 - Grant
像这样获取脚本将导致begin.sh等待其完成。第二次运行begin.sh将不知道第一次运行的情况,而会启动自己的process.sh运行。我无法看出第二行上的exec对您有任何作用,除非您在后台运行了某些内容(使用&)。如果您在begin.sh的顶部添加set -x并运行两次,您从第二次运行中得到什么输出? - Etan Reisner
@EtanReisner 谢谢,我已经从 process.sh 中删除了 execwait。同时,我还在 begin.sh 中添加了 set -x。现在它可以同时运行两个进程,这正是我想要避免的。 - Grant
好的。所以问题又回到了需要不同的begin.sh进程相互知晓的问题上。这是一个标准的问题。解决方案主要涉及某种锁定文件或类似机制。或者将问题反转为作业队列提交过程。 - Etan Reisner
@EtanReisner 哦,好的。您能否指导我一些资源,以帮助我完成这项工作?除了我在这里提出的主要问题之外,我甚至不知道该寻找什么。 - Grant
1个回答

2
锁定原理可以如下: 当您的脚本启动时,它首先在其工作目录中创建一个空的script.lock文件。 当它完成后,它会删除script.lock文件。 编辑:更好的做法是使用mkdir创建一个script.lock目录,正如Dror Cohen在他的评论中建议的那样。
这是一个通用的想法。 实际上,为了使其起作用,只有在不存在当前script.lock时才真正开始运行。如果存在,则会在/queue/文件夹中创建一个包含调用参数的新文件。
因此,最终你会像这样拥有一个begin.sh:
检查script.lock是否存在。 - 如果存在,则在/queue/中写入一个新文件并停止 - 如果不存在,则创建script.lock并继续
在脚本的最后,它会检查/queue/文件夹中是否有任何文件。 - 如果没有,则删除script.lock并停止。 - 如果在/queue/中有一个文件,则取出较旧的文件,删除它并再次使用保存在文件中的参数启动它自己。

文件检查不是原子性的。你应该修复你的答案,改用目录检查,参见这个答案 - Dror Cohen
谢谢,我从未意识到这一点。在时序关键的情况下,这肯定很重要 :) - CCH
@CCH 听起来正是我所需要的。我正试图实现Dror链接帖子中的解决方案,但我不知道如何做最后一件事,即删除锁并停止等等...你能给我展示一个工作示例吗?我有点力不从心。另外,我还不理解队列系统将如何工作。 - Grant
实际上,经过多次阅读您的原始答案后,我完全理解了这个概念,但是不知道如何实现它。任何帮助都将不胜感激,我还在学习中 :) - Grant
我知道你已经在begin.sh中找到了如何完成第一部分。对于最后一部分,最好的方法是在process.sh的结尾处做完全相同的事情,但使用rmdir而不是mkdir。这样,您可以利用锁定目录,将其用作队列文件夹。如果您发布了迄今为止所做的内容,我可以指引您正确的方向。 - CCH

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接