<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Cron on 寻 Mi 处</title>
        <link>https://blog.mibase.top/tags/cron/</link>
        <description>Recent content in Cron on 寻 Mi 处</description>
        <generator>Hugo -- gohugo.io</generator>
        <language>zh</language>
        <lastBuildDate>Sun, 25 Oct 2026 19:57:00 +0800</lastBuildDate><atom:link href="https://blog.mibase.top/tags/cron/index.xml" rel="self" type="application/rss+xml" /><item>
            <title>脚本手动跑得好好的，放进 crontab 就是不动</title>
            <link>https://blog.mibase.top/p/cron-not-running/</link>
            <pubDate>Sun, 25 Oct 2026 19:57:00 +0800</pubDate>
            <guid>https://blog.mibase.top/p/cron-not-running/</guid>
            <description>&lt;img src=&#34;https://blog.mibase.top/p/cron-not-running/cover.jpg&#34; alt=&#34;Featured image of post 脚本手动跑得好好的，放进 crontab 就是不动&#34; /&gt;&lt;p&gt;先说结论的话，这篇其实没什么高深的东西，全是 cron 的基本脾气。但我是真的被它折腾了一个周末，所以还是想写下来，哪天再遇到能少走点弯路。&lt;/p&gt;&#xA;&lt;p&gt;事情的起因是我想给自己那台小服务器做个像样的备份。之前的做法是想起来了就手动 &lt;code&gt;pg_dump&lt;/code&gt; 一下，然后 scp 回家里的电脑，这种&amp;quot;想起来了&amp;quot;的备份，说实话跟没有差不多。上个月有一次手滑把一个库里的表 drop 了，翻了半天发现最近一次备份是四十多天前的，才下决心搞个自动的。&lt;/p&gt;&#xA;&lt;h2 id=&#34;脚本本身&#34;&gt;脚本本身&#xA;&lt;/h2&gt;&lt;p&gt;思路很简单：每天凌晨导出一份数据库，压缩，用 rclone 传到一个对象存储的桶里，本地只留最近七天的。&lt;/p&gt;&#xA;&lt;p&gt;我把它放在 &lt;code&gt;/home/zhou/bin/backup.sh&lt;/code&gt;，大概长这样：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt; 1&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 2&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 3&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 4&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 5&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 6&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 7&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 8&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 9&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;10&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;11&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;12&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#!/bin/bash&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; -e&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;DIR&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;/home/zhou/backup&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;NAME&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;pg-&lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;date +%Y%m%d-%H%M&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;.sql.gz&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;mkdir -p &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$DIR&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;pg_dump -U zhou -h 127.0.0.1 mydb &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; gzip &amp;gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$DIR&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$NAME&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;rclone copy &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$DIR&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$NAME&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt; mybucket:backup/pg/&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;find &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$DIR&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt; -name &lt;span class=&#34;s1&#34;&gt;&amp;#39;pg-*.sql.gz&amp;#39;&lt;/span&gt; -mtime +7 -delete&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;date&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt; done &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$NAME&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;pg 的密码放在 &lt;code&gt;~/.pgpass&lt;/code&gt; 里，rclone 的配置在 &lt;code&gt;~/.config/rclone/rclone.conf&lt;/code&gt;，这两个都是我手动配好的，没毛病。&lt;/p&gt;&#xA;&lt;p&gt;手动跑：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;bash /home/zhou/bin/backup.sh&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;几秒钟之后输出一行 &lt;code&gt;Sat Oct 24 23:41:07 CST 2026 done pg-20261024-2341.sql.gz&lt;/code&gt;，登上对象存储的网页后台一看，文件也确实在那儿。&lt;/p&gt;&#xA;&lt;p&gt;好，脚本没问题。接下来丢给 cron。&lt;/p&gt;&#xA;&lt;h2 id=&#34;然后什么都没发生&#34;&gt;然后什么都没发生&#xA;&lt;/h2&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;crontab -e&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;加了一行：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;30 3 * * * /home/zhou/bin/backup.sh&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;这里先吐槽一下，我最开始忘了给脚本加执行权限，不过这个比较明显，第二天看不到文件之后我很快就想到了，&lt;code&gt;chmod +x&lt;/code&gt; 一下就行。&lt;/p&gt;&#xA;&lt;p&gt;加完权限之后我没有等到第二天凌晨，而是把时间改成了&amp;quot;两分钟之后&amp;quot;来测试，一边盯着一边等。&lt;/p&gt;&#xA;&lt;p&gt;两分钟过去了，桶里没有新文件，本地 backup 目录里也没有。&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;crontab -l&lt;/code&gt; 看了一眼，条目确实在。&lt;code&gt;systemctl status cron&lt;/code&gt; 也是 active (running)。&lt;/p&gt;&#xA;&lt;p&gt;到这里我有点懵，因为按我的理解，要么执行成功要么应该有个报错，而眼前是什么都没有，不成功也不失败，像是掉进了黑洞。&lt;/p&gt;&#xA;&lt;h2 id=&#34;cron-到底有没有跑它&#34;&gt;cron 到底有没有跑它&#xA;&lt;/h2&gt;&lt;p&gt;后来我想明白了，第一步其实不该猜，应该先确认 cron 有没有真的去执行那一行。&lt;/p&gt;&#xA;&lt;p&gt;Debian 12 默认不装 rsyslog 了，所以老教程里说的 &lt;code&gt;/var/log/syslog&lt;/code&gt; 在我这儿根本不存在。cron 的日志要去 journal 里找：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;journalctl -u cron --since &lt;span class=&#34;s2&#34;&gt;&amp;#34;10 minutes ago&amp;#34;&lt;/span&gt; --no-pager&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Oct 25 10:12:01 vps CRON[48213]: (zhou) CMD (/home/zhou/bin/backup.sh)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Oct 25 10:12:01 vps CRON[48212]: (CRON) info (No MTA installed, discarding output)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;这两行信息量其实很大。&lt;/p&gt;&#xA;&lt;p&gt;第一行说明 cron 确实在 10:12 把命令拉起来了，所以调度这块没问题，不是 cron 服务的毛病，也不是时间写错了。&lt;/p&gt;&#xA;&lt;p&gt;第二行是关键：&lt;code&gt;No MTA installed, discarding output&lt;/code&gt;。cron 有个设定，任务如果有任何标准输出或者标准错误，它会尝试用邮件发给任务所属用户。我这台机器没装邮件服务，所以所有的输出，不管是成功的提示还是报错，都被它丢掉了。&lt;/p&gt;&#xA;&lt;p&gt;也就是说脚本其实可能报错了，只是我完全看不到。&lt;/p&gt;&#xA;&lt;p&gt;这个设计我是能理解的，毕竟 cron 诞生的年代，每台机器都有本地邮件系统。但放到今天，一个没装 MTA 的小 VPS 上，这等于默认静音。&lt;/p&gt;&#xA;&lt;h2 id=&#34;先让它说话&#34;&gt;先让它说话&#xA;&lt;/h2&gt;&lt;p&gt;解决办法很土：把输出重定向到一个文件里。&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;30 3 * * * /home/zhou/bin/backup.sh &amp;gt;&amp;gt; /home/zhou/backup/cron.log 2&amp;gt;&amp;amp;1&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;再等一次。这次文件里有东西了：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;/home/zhou/bin/backup.sh: line 9: rclone: command not found&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;终于。&lt;/p&gt;&#xA;&lt;p&gt;顺带发现一个事，因为我脚本里写了 &lt;code&gt;set -e&lt;/code&gt;，rclone 失败之后脚本直接退出了，所以后面的 find 清理也没执行，最后那句 &lt;code&gt;echo done&lt;/code&gt; 当然也没有。pg_dump 倒是成功了，本地目录里其实有那个 &lt;code&gt;.sql.gz&lt;/code&gt;，只是我之前没注意到，因为我是直接去桶里看的。&lt;/p&gt;&#xA;&lt;h2 id=&#34;path-的问题&#34;&gt;PATH 的问题&#xA;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;rclone: command not found&lt;/code&gt;，可我在终端里明明能用。&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;which rclone&lt;/code&gt; 一下：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;/usr/local/bin/rclone&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;它装在 &lt;code&gt;/usr/local/bin&lt;/code&gt;。而 cron 启动任务的时候，环境变量非常干净，PATH 默认只有 &lt;code&gt;/usr/bin:/bin&lt;/code&gt;，没有 &lt;code&gt;/usr/local/bin&lt;/code&gt;，更别说我在 &lt;code&gt;.bashrc&lt;/code&gt; 里加的那些乱七八糟的路径了。cron 也不会去读 &lt;code&gt;.bashrc&lt;/code&gt; 或者 &lt;code&gt;.profile&lt;/code&gt;，因为它根本不是个登录 shell，甚至默认连 bash 都不是，用的是 &lt;code&gt;/bin/sh&lt;/code&gt;。&lt;/p&gt;&#xA;&lt;p&gt;可以自己验证一下 cron 里的环境到底长什么样，加一行：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;* * * * * env &amp;gt; /tmp/cronenv.txt&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;一分钟后看 &lt;code&gt;/tmp/cronenv.txt&lt;/code&gt;：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;4&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;5&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;SHELL=/bin/sh&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;PWD=/home/zhou&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;LOGNAME=zhou&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;HOME=/home/zhou&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;PATH=/usr/bin:/bin&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;就这么几行。测完记得把这条删掉，不然它每分钟写一次，我就忘过一回，两天之后才想起来。&lt;/p&gt;&#xA;&lt;p&gt;解决办法有三种，我都试了：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;脚本里用绝对路径，&lt;code&gt;/usr/local/bin/rclone copy ...&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;脚本开头自己设 &lt;code&gt;export PATH=/usr/local/bin:/usr/bin:/bin&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;在 crontab 文件最上面写一行 &lt;code&gt;PATH=/usr/local/bin:/usr/bin:/bin&lt;/code&gt;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;我最后选了第三种加第一种，crontab 顶上写 PATH，脚本里涉及的关键命令也不偷懒。倒不是不信任 PATH，而是想着过两年我自己都忘了这个脚本是靠 crontab 里那一行才能跑的，换台机器或者换个用户，又会掉进同一个坑。脚本自己带着依赖，心里踏实些。&lt;/p&gt;&#xA;&lt;p&gt;顺手把 &lt;code&gt;SHELL=/bin/bash&lt;/code&gt; 也写进了 crontab 顶部，因为我脚本里偶尔会用到一些 bash 才有的写法，万一以后直接在 crontab 行里写命令，不想再踩 &lt;code&gt;sh&lt;/code&gt; 的坑。&lt;/p&gt;&#xA;&lt;h2 id=&#34;百分号一个更阴险的东西&#34;&gt;百分号，一个更阴险的东西&#xA;&lt;/h2&gt;&lt;p&gt;PATH 改好之后，我以为这事结束了。结果它又给了我一个惊喜。&lt;/p&gt;&#xA;&lt;p&gt;我想让日志文件按日期分开，就把重定向那段改成了：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;30 3 * * * /home/zhou/bin/backup.sh &amp;gt;&amp;gt; /home/zhou/backup/cron-$(date +%Y%m%d).log 2&amp;gt;&amp;amp;1&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;然后这一条又不动了，而且这次连 cron.log 都没有新东西。journal 里是：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;CRON[51002]: (zhou) CMD (/home/zhou/bin/backup.sh &amp;gt;&amp;gt; /home/zhou/backup/cron-$(date +)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;对，命令在 &lt;code&gt;+&lt;/code&gt; 那里被截断了，后面的 &lt;code&gt;%Y%m%d)...&lt;/code&gt; 没了。&lt;/p&gt;&#xA;&lt;p&gt;这是 cron 的一个老规矩：crontab 里，没有被转义的 &lt;code&gt;%&lt;/code&gt; 会被当成换行符，第一个 &lt;code&gt;%&lt;/code&gt; 之前的部分是命令，之后的部分会被当作标准输入喂给这个命令。所以上面这行实际被切成了命令 &lt;code&gt;... $(date +&lt;/code&gt;，当然 shell 会报语法错误（括号没闭合），这个错误本来该通过邮件发出来，但是——前面说过了，我没装 MTA。&lt;/p&gt;&#xA;&lt;p&gt;解决办法是转义：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;30 3 * * * /home/zhou/bin/backup.sh &amp;gt;&amp;gt; /home/zhou/backup/cron-$(date +\%Y\%m\%d).log 2&amp;gt;&amp;amp;1&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;每个 &lt;code&gt;%&lt;/code&gt; 前面加反斜杠。&lt;/p&gt;&#xA;&lt;p&gt;其实我脚本里的 &lt;code&gt;date +%Y%m%d-%H%M&lt;/code&gt; 一直没事，是因为那是在脚本文件里，不是在 crontab 里，cron 不会去解析脚本内容。这个区别我之前是模模糊糊知道的，真撞上了才算记住。&lt;/p&gt;&#xA;&lt;p&gt;更省事的做法是干脆别在 crontab 行里写这种东西，把日志重定向的逻辑放进脚本里，crontab 只留一个干净的路径，这样以后也不会再因为一个百分号被坑。我后来就改成了这样，在脚本开头加了：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;exec&lt;/span&gt; &amp;gt;&amp;gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;/home/zhou/backup/cron-&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;date +%Y%m%d&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;.log&amp;#34;&lt;/span&gt; 2&amp;gt;&lt;span class=&#34;p&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;&lt;code&gt;exec&lt;/code&gt; 不带命令的时候，作用是把当前 shell 之后所有的输出都重定向过去。这样脚本里随便 echo，都会进日志。&lt;/p&gt;&#xA;&lt;h2 id=&#34;还有一件我没踩但是差点踩的事&#34;&gt;还有一件我没踩但是差点踩的事&#xA;&lt;/h2&gt;&lt;p&gt;查资料的过程中看到别人提到，如果不是放在用户的 crontab 里，而是想放在 &lt;code&gt;/etc/cron.d/&lt;/code&gt; 或者 &lt;code&gt;/etc/cron.daily/&lt;/code&gt; 里，还有另外几个规矩，我当时想着要不要换成这种方式，所以顺便试了一下。&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;/etc/cron.daily/&lt;/code&gt; 这种目录是靠 &lt;code&gt;run-parts&lt;/code&gt; 来跑的。Debian 上的 run-parts 对文件名有要求，只接受字母、数字、下划线和连字符，带点号的会被直接跳过。所以我把脚本命名成 &lt;code&gt;backup.sh&lt;/code&gt; 放进 &lt;code&gt;/etc/cron.daily/&lt;/code&gt; 之后，它永远不会被执行，连个提示都没有。改名成 &lt;code&gt;backup&lt;/code&gt; 才行。&lt;/p&gt;&#xA;&lt;p&gt;可以用 &lt;code&gt;run-parts --test /etc/cron.daily&lt;/code&gt; 来看哪些文件会被执行，我的 &lt;code&gt;backup.sh&lt;/code&gt; 确实没出现在列表里。&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;/etc/cron.d/&lt;/code&gt; 又不一样，那里面放的是 crontab 格式的文件，和用户 crontab 的区别是时间后面要多写一个用户名：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;30 3 * * * zhou /home/zhou/bin/backup.sh&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;忘了写用户名的话，cron 会把脚本路径当成用户名，然后报个莫名其妙的错。文件名也是同样不能带点号。另外这类文件要求属主是 root，权限不能让其他人可写，文件结尾要有换行。&lt;/p&gt;&#xA;&lt;p&gt;我最后还是没用这两个地方，就用的用户自己的 crontab。理由很朴素：备份是我自己一个人的事，放在自己用户下，出了问题 &lt;code&gt;crontab -l&lt;/code&gt; 一眼就能看到，不用去 &lt;code&gt;/etc&lt;/code&gt; 里翻。&lt;/p&gt;&#xA;&lt;h2 id=&#34;最终的样子&#34;&gt;最终的样子&#xA;&lt;/h2&gt;&lt;p&gt;crontab：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;4&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;SHELL=/bin/bash&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;PATH=/usr/local/bin:/usr/bin:/bin&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;30 3 * * * /home/zhou/bin/backup.sh&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;脚本：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt; 1&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 2&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 3&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 4&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 5&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 6&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 7&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 8&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 9&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;10&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;11&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;12&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;13&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;14&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;15&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;16&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#!/bin/bash&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; -eu -o pipefail&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;export&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;PATH&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;/usr/local/bin:/usr/bin:/bin&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;DIR&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;/home/zhou/backup&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;exec&lt;/span&gt; &amp;gt;&amp;gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$DIR&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;/cron-&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;date +%Y%m%d&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;.log&amp;#34;&lt;/span&gt; 2&amp;gt;&lt;span class=&#34;p&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;NAME&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;pg-&lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;date +%Y%m%d-%H%M&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;.sql.gz&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;mkdir -p &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$DIR&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;pg_dump -U zhou -h 127.0.0.1 mydb &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; gzip &amp;gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$DIR&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$NAME&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;/usr/local/bin/rclone copy &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$DIR&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$NAME&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt; mybucket:backup/pg/&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;find &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$DIR&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt; -name &lt;span class=&#34;s1&#34;&gt;&amp;#39;pg-*.sql.gz&amp;#39;&lt;/span&gt; -mtime +7 -delete&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;find &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$DIR&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt; -name &lt;span class=&#34;s1&#34;&gt;&amp;#39;cron-*.log&amp;#39;&lt;/span&gt; -mtime +30 -delete&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;date&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt; done &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$NAME&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;这里我还加了 &lt;code&gt;pipefail&lt;/code&gt;，是因为中途发现一个很不好的事：&lt;code&gt;pg_dump ... | gzip &amp;gt; file&lt;/code&gt; 这个管道，如果 pg_dump 失败了，gzip 照样成功退出，整条命令的返回值是最后一个的，也就是 0。结果会得到一个 20 字节的空压缩包，脚本还以为一切正常，并且把这个空文件传到桶里去。没有 &lt;code&gt;pipefail&lt;/code&gt; 的话，你的备份可能一直是空的，而你完全不知道。&lt;/p&gt;&#xA;&lt;p&gt;我是故意把 pg 的密码改错了测了一次才发现这个的。改错之后脚本打出 &lt;code&gt;done&lt;/code&gt;，桶里多了一个 20 字节的文件。当时看着那个文件，背后有点发凉。&lt;/p&gt;&#xA;&lt;h2 id=&#34;最后补一个监控&#34;&gt;最后补一个监控&#xA;&lt;/h2&gt;&lt;p&gt;日志写进文件了，但没人会每天去看日志。我又加了个很粗糙的东西：脚本最后一行成功之后，对 Uptime Kuma 的一个 push 地址 curl 一下。&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;curl -fsS -m &lt;span class=&#34;m&#34;&gt;10&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;https://kuma.example.com/api/push/xxxxxxxx?status=up&amp;amp;msg=ok&amp;#34;&lt;/span&gt; &amp;gt;/dev/null&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;Kuma 那边设成 26 小时没收到心跳就报警。这样不管是 cron 没触发、脚本中途失败、还是机器直接挂了，我都会收到一条通知。比起让脚本失败时去发邮件，反向地&amp;quot;没成功就报警&amp;quot;可靠得多，因为失败的方式太多了，很难每一种都覆盖到，但成功只有一种。&lt;/p&gt;&#xA;&lt;p&gt;昨天夜里它第一次完整自己跑完了。早上起来我手机上没有任何通知，打开桶看了一眼，有个三点三十一分的文件，大小 3.2M。&lt;/p&gt;&#xA;&lt;p&gt;挺好。就是这几个 cron 的坑，都不大，凑在一起够恶心的。&lt;/p&gt;&#xA;</description>
        </item></channel>
</rss>
