bash 脚本能否判断它是否通过 cron 运行?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3214935/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Can a bash script tell if it's being run via cron?
提问by Topher Fangio
Not having much luck Googling this question and I thought about posting it on SF, but it actually seems like a development question. If not, please feel free to migrate.
没有太多运气谷歌搜索这个问题,我想把它发布在 SF 上,但它实际上似乎是一个开发问题。如果没有,请随时迁移。
So, I have a script that runs via cron every morning at about 3 am. I also run the same scripts manually sometimes. The problem is that every time I run my script manually and it fails, it sends me an e-mail; even though I can look at the output and view the error in the console.
所以,我有一个脚本,每天早上大约凌晨 3 点通过 cron 运行。有时我也手动运行相同的脚本。问题是每次我手动运行我的脚本但它失败时,它会向我发送一封电子邮件;即使我可以查看输出并在控制台中查看错误。
Is there a way for the bash script to tell that it's being run through cron (perhaps by using whoami) and only send the e-mail if so? I'd love to stop receiving emails when I'm doing my testing...
有没有办法让 bash 脚本告诉它正在通过 cron 运行(也许通过使用 whoami)并且只有在这样的情况下才发送电子邮件?我很想在我进行测试时停止接收电子邮件...
采纳答案by eruciform
you can try "tty" to see if it's run by a terminal or not. that won't tell you that it's specifically run by cron, but you can tell if its "not a user as a prompt".
您可以尝试使用“tty”来查看它是否由终端运行。这不会告诉您它是由 cron 专门运行的,但是您可以判断它是否“不是用户作为提示”。
you can also get your parent-pid and follow it up the tree to look for cron, though that's a little heavy-handed.
您还可以获取您的父 pid 并在树上跟踪它以查找 cron,尽管这有点笨手笨脚。
回答by d-_-b
Why not have a command line argument that is -t for testing or -c for cron.
为什么不使用 -t 用于测试或 -c 用于 cron 的命令行参数。
Or better yet:
或者更好:
If it's not specified, don't send an email.
如果未指定,请不要发送电子邮件。
回答by Geoff Reedy
Here's two different options for you:
这里有两个不同的选项供您选择:
Take the emailing out of your script/program and let cron handle it. If you set the MAILTO variable in your crontab, cron will send anything printed out to that email address. eg:
[email protected] # run five minutes after midnight, every day 5 0 * * * $HOME/bin/daily.jobSet an environment variable in your crontab that is used to determine if running under cron. eg:
THIS_IS_CRON=1 # run five minutes after midnight, every day 5 0 * * * $HOME/bin/daily.joband in your script something like
if [ -n "$THIS_IS_CRON" ]; then echo "I'm running in cron"; else echo "I'm not running in cron"; fi
从您的脚本/程序中取出电子邮件,让 cron 处理它。如果您在 crontab 中设置了 MAILTO 变量,cron 会将任何打印出来的内容发送到该电子邮件地址。例如:
[email protected] # run five minutes after midnight, every day 5 0 * * * $HOME/bin/daily.job在您的 crontab 中设置一个环境变量,用于确定是否在 cron 下运行。例如:
THIS_IS_CRON=1 # run five minutes after midnight, every day 5 0 * * * $HOME/bin/daily.job在你的脚本中类似
if [ -n "$THIS_IS_CRON" ]; then echo "I'm running in cron"; else echo "I'm not running in cron"; fi
回答by shekwi
I had a similar issue. I solved it with checking if stdout was a TTY. This is a check to see if you script runs in interactive mode:
我有一个类似的问题。我通过检查 stdout 是否为 TTY 来解决它。这是检查您的脚本是否在交互模式下运行的检查:
if [ -t 1 ] ; then
echo "interacive mode";
else
#send mail
fi
I got this from: How to detect if my shell script is running through a pipe?
The -t test return true if file descriptor is open and refers to a terminal. '1' is stdout.
如果文件描述符已打开并指向终端,则 -t 测试返回 true。“1”是标准输出。
回答by Tal
I know the question is old, but I just came across the same problem. This was my solution:
我知道这个问题很老,但我刚刚遇到了同样的问题。这是我的解决方案:
CRON=$(pstree -s $$ | grep -q cron && echo true || echo false)
then test with
然后用
if $CRON
then
echo "Being run by cron"
else
echo "Not being run by cron"
fi
same idea as the one that @eruciform mentioned - follows your PID up the process tree checking for cron.
与@eruciform 提到的想法相同的想法 - 按照您的 PID 向上检查 cron 的进程树。
Note: This solution only works specifically for cron, unlike some of the other solutions, which work anytime the script is being run non-interactively.
注意:此解决方案仅适用于 cron,与其他一些解决方案不同,这些解决方案在脚本以非交互方式运行的任何时候都有效。
回答by edoceo
What works for me is to check $TERM. Under cron it's "dumb" but under a shell it's something else. Use the setcommand in your terminal, then in a cron-script and check it out
对我有用的是检查$TERM. 在 cron 下它是“愚蠢的”,但在 shell 下它是别的东西。set在终端中使用该命令,然后在 cron 脚本中查看它
if [ "dumb" == "$TERM" ]
then
echo "cron"
else
echo "term"
fi
回答by Grisha Levit
I'd like to suggest a new answer to this highly-voted question. This works only on systemd systems with loginctl(e.g. Ubuntu 14.10+, RHEL/CentOS 7+) but is able to give a much more authoritative answer than previously presented solutions.
我想对这个投票率很高的问题提出一个新的答案。这仅适用于具有loginctl(例如 Ubuntu 14.10+、RHEL/CentOS 7+)的systemd 系统,但能够提供比以前提出的解决方案更权威的答案。
service=$(loginctl --property=Service show-session $(</proc/self/sessionid))
if [[ ${service#*=} == 'crond' ]]; then
echo "running in cron"
fi
To summarize: when used with systemd, crond(like sshdand others) creates a new sessionwhen it starts a job for a user. This session has an ID that is unique for the entire uptime of the machine. Each session has some properties, one of which is the name of the service that started it. loginctlcan tell us the value of this property, which will be "crond" if and only ifthe session was actually started by crond.
总结一下:当与 systemd 一起使用时,crond(sshd和其他人一样)在为用户启动作业时会创建一个新会话。此会话具有一个 ID,该 ID 对于机器的整个正常运行时间都是唯一的。每个会话都有一些属性,其中之一是启动它的服务的名称。 loginctl可以告诉我们这个属性的值,当且仅当会话实际上是由 crond 启动时,它才会是“ crond” 。
Advantages over using environment variables:
使用环境变量的优点:
- No need to modify cron entries to add special invocations or environment variables
- No possibility of an intermediate process modifying environment variables to create a false positive or false negative
- 无需修改 cron 条目以添加特殊调用或环境变量
- 中间过程不可能修改环境变量以创建误报或漏报
Advantages over testing for tty:
与测试 tty 相比的优势:
- No false positives in pipelines, startup scripts, etc
- 管道、启动脚本等中没有误报
Advantages over checking the process tree:
与检查进程树相比的优势:
- No false positives from processes that also have
crondin their name - No false negatives if the script is disowned
- 没有来自
crond名称中也包含的进程的误报 - 如果脚本被否认,则不会出现漏报
回答by frank42
I also liked the idea from Tal, but also see the risk of having undefined returns. I ended up with a slightly modified version, which seems to work very smooth in my opinion:
我也喜欢 Tal 的想法,但也看到了不确定回报的风险。我最终得到了一个稍微修改过的版本,在我看来它似乎工作得非常顺利:
CRON="$( pstree -s $$ | grep -c cron )"
CRON="$( pstree -s $$ | grep -c cron )"
So you can check for $CRON being 1 or 0 at any time.
因此,您可以随时检查 $CRON 是 1 还是 0。
回答by FifthAxiom
Many of the commands used in prior posts are not available on every system (pstree, loginctl, tty). This was the only thing that worked for me on a ten years old BusyBox/OpenWrt router that I'm currently using as a blacklist DNS server. It runs a script with an auto-update feature. Running from crontab, it sends an email out.
之前帖子中使用的许多命令并非在每个系统上都可用(pstree、loginctl、tty)。这是我目前用作黑名单 DNS 服务器的十年前 BusyBox/OpenWrt 路由器上唯一对我有用的东西。它运行具有自动更新功能的脚本。从 crontab 运行,它会发送一封电子邮件。
[ -z "$TERM" ] || [ "$TERM" = "dumb" ] && echo 'Crontab' || echo 'Interactive'
In an interactive shell the $TERM-variable returns the value vt102for me. I included the check for "dumb" since @edoceo mentioned it worked for him. I didn't use '==' since it's not completely portable.
在交互式 shell 中,$TERM-variablevt102为我返回值。我包括了“愚蠢”的检查,因为@edoceo 提到它对他有用。我没有使用'==',因为它不是完全可移植的。

