我周末要在后台运行三个 SAS 程序。这三个程序将信息输出到同名的文件中,因此我需要在第一个程序完成之后和第二个程序启动之前以及第二个程序完成之后和第三个程序启动之前删除这些输出文件。显然,解决这个问题的最简单方法是改变每个程序,使输出文件名不同,但这无助于我学习如何使用 Unix。这就是我到目前为止所得到的:
# Begin by running the first SAS program in the background.
sas program1.sas & | at 5:00 PM JAN 11
# I'd like to wait until the first program finishes to remove
# the output files and run the second program.
wait ???
rm file1.sas7bdat file2.sas7bdat file3.sas7bdat file4.sas7bdat file5.sas7bdat
sas program2.sas & | at 5:00 PM JAN 12
# And now I repeat.
wait ???
rm file1.sas7bdat file2.sas7bdat file3.sas7bdat file4.sas7bdat file5.sas7bdat
sas program3.sas & | at 5:00 PM JAN 13
我将每个程序设置为连续几天同时运行有两个原因:(1) 我知道前一个程序将在 24 小时内完成,(2) 我假设服务器上的负载同时相似连续几天。理想情况下,我可以以某种方式获取第一个程序的进程 ID 并将其传递给第一个wait
命令,对于第二个程序和wait
命令也是如此。有任何想法吗?
编辑
wait
与这种特定情况相比,我对确定进程 ID 并将其传递给命令的通用解决方案更感兴趣。
答案1
问题是你用 at 来做一些不应该用的事情,真的。您还有两个相互冲突的目标:“在程序 1 之后运行程序 2”和“在 1 月 12 日下午 5 点运行程序 2”。
您的问题的一部分很容易解决:at 允许多个命令。因此,您不仅可以使用它at
来安排sas
脚本,还可以将其放入rm
作业中。
at 5:00 PM JAN 11 <<EOJ
sas program1.sas
rm file1.sas7bdat file2.sas7bdat file3.sas7bdat file4.sas7bdat file5.sas7bdat
EOJ
没有理由&
排队sas
;at
始终“在后台”运行作业。
接下来,你必须弄清楚你想如何解决前面提到的冲突。特别是,如果 1 月 11 日的工作在 24 小时后(1 月 12 日下午 5 点之前)尚未完成。有几种方法可以解决这个问题:
- 这并不是 1 月 12 日的工作。 program1.sas 完成后它应该立即运行。在这种情况下,只需将其作为上面第一项作业的一部分即可,就像
rm
. - 这永远不会发生。如果确实如此,您将手动修复它。在这种情况下,只需像上面那样安排即可。
- 需要等待。在这种情况下,您可以将其安排在第一个 at 作业结束时,或者使用锁定文件,或者计算适当的睡眠时间(或者使用
sleepenh
,如果可用,以避免自己进行计算)。
答案2
所以你所要做的和想要做的基本上可以归结为以下几点。
command1 &
wait <on command1>
sleep <until specified time>
command2 &
wait <on command2>
sleep <until specified time>
...
在这种情况下,删除背景 ( &
) 以及wait
和sleep
将导致命令按顺序执行。然而,这将使它们立即执行。
要等到特定时间,您可以sleep
等待适当的时间。sleep
需要几秒作为输入,而 Unix 系统传统上以秒为单位保存和测量时间,因此这可以归结为简单的算术:
- 将等待日期和时间转换为自纪元以来的秒数。
- 将当前时间转换为自纪元以来的秒数。
- 计算差异。
- 睡那么久。
如何做到这一点在这个堆栈溢出答案,但要复制重要部分:
current_epoch=$(date +%s)
target_epoch=$(date -d '01/01/2010 12:00' +%s)
sleep_seconds=$(( $target_epoch - $current_epoch ))
sleep $sleep_seconds
这个特定的例子是 bash 语法,但它应该很容易转换为任何 shell 脚本语言。$(...)
执行命令并替换为该命令的输出,并$(( ... ))
计算算术表达式。
GNUdate -d
还支持仅时间时间戳,因此您可以说它date -d '05:00'
会将其转换为即将到来的 05:00。
将这些放在一起,应该很容易制作出您想要的脚本。
答案3
嗯,没有wait
命令。至少据我所知不是。这是我的替代逻辑:
为每个 SAS 程序创建 3 个脚本文件。仅当前面的 sas 程序执行完毕后,这些脚本才会执行。这可以通过捕获pid
以前的 sas 程序并ps
在删除输出文件之前使用命令验证它不再运行来完成。
分别安排脚本crontab
在每个周五到周日运行。
因此,如果我命名第一个脚本文件sas_script1.sh
,它将如下所示:
if [ -f /var/run/sas.pid ]; then
/bin/ps $( cat /var/run/sas.pid ) >/dev/null
[ $? ] && exit # $? checks the exit status of the last command
fi
rm -f /path/to/file{1..5}.sas7bdat
/usr/bin/sas /path/to/program1.sas &
echo $! >/var/run/sas.pid # $! gives you the PID of the last program that's sent background
为两个 SAS 程序的其余部分编写相同的脚本,例如只需编辑program1.sas
为program2.sas
创建一个file
并在其中写入以下内容:
00 17 * * 5 /path/to/sas_script1.sh
00 17 * * 6 /path/to/sas_script2.sh
00 17 * * 0 /path/to/sas_script3.sh
现在,将文件上传为 cron 作业:
crontab /path/to/file
您可以通过这种方式了解有关 Un*X 的更多信息 :D