我正在 Raspberry Pi(运行 Raspbian)上运行一个 shell 脚本cron
。由于它是一个备份脚本,它有时会运行很长时间(例如,如果我添加了很多照片),而且我不希望它同时运行,所以我采用了此片段在我的脚本中。另外,我希望在脚本运行时收到可能出现的任何问题的通知,因此我通过克罗尼克。最后,我已启用set -o xtrace
调试目的。
我的脚本现在如下所示:
#!/usr/bin/env sh
set -o errexit -o nounset -o xtrace
SCRIPTNAME="$(basename $0)"
RUNNING="$(ps ax | grep $SCRIPTNAME | grep -v $$ | grep bash | grep -v grep | wc -l)"
if [ "$RUNNING" != "1" ]; then
echo "Skipping $SCRIPTNAME because it is already running..." 1>&2
exit 1;
fi
# rsync stuff
我的crontab
样子是这样的:
[email protected]
0 23 * * * cronic ~/sync-to-backup.sh
这样,当备份脚本失败并显示退出代码时,或当有输出时,或两者皆有时,我都会收到一封电子邮件stderr
。这太棒了!
但是,大约每运行两三次,我就会收到一封电子邮件,表明脚本实际上运行正常。结果发现,在这些情况下,输出xtrace
会变得混乱,如下所示:
TRACE-ERROR OUTPUT:
+ basename /home/pi/sync-to-backup.sh
+ SCRIPTNAME=sync-to-backup.sh
+ ps ax
+ grep sync-to-backup.sh
+ grep -v 3050
+ + wcgrep -l -v
grep
+ grep bash
+ RUNNING=1
+ [ 1 != 1 ]
# rsync output comes next
或者像这样:
TRACE-ERROR OUTPUT:
+ basename /home/pi/sync-to-backup.sh
+ SCRIPTNAME=sync-to-backup.sh
+ ps ax
+ grep sync-to-backup.sh
+ grep -v 12573
+ + grep bashwc
-l
+ grep -v grep
+ RUNNING=1
+ [ 1 != 1 ]
# rsync output comes next
或者像这样:
TRACE-ERROR OUTPUT:
+ basename /home/pi/sync-to-backup.sh
+ SCRIPTNAME=sync-to-backup.sh
+ ps ax
+ grep sync-to-backup.sh
+ grep -v 30881
+ + grep bash
wc -l
+ grep -v grep
+ RUNNING=1
+ [ 1 != 1 ]
# rsync output comes next
在每种情况下,rsync 命令都运行正常,没有问题。只是没有以 开头的跟踪行+
(例如wc -l
,上一个示例中的 )显然被打印为stderr
?因此,Cronic 现在认为存在错误,但实际上没有错误。
我不知道为什么会发生这种情况。作为一名 Java 开发人员,我认为可能存在并发问题,但我不认为 Linux 管道是并行运行的,不是吗?我尝试将所有内容(包括 在内的所有参数grep
)都括grep -v $$
在引号中,如下所示:grep -v "$$"
以防万一&
输出中的某个地方会导致进程在后台开始运行,但这也无济于事。
我意识到我可以通过另一种方式来确定进程是否已经在运行来避免这个问题(也许使用flock
),但这样我可能就必须安装一个我不想安装的依赖项。或者我可以减少grep
s 的数量,但我觉得这只会减少问题发生的频率,而不是解决问题。我也可以完全禁用跟踪,但我喜欢能够在问题发生时调试问题的想法。
所以,我的问题是:这是怎么回事?是什么导致了这种行为?以及:我怎样才能阻止它?