月亮是盈还是亏?

作者:Dave Taylor

在我的上一篇文章中,我谈到了计算月相的复杂性,并决定简单地抓取 Google 使用的同一个网站

该网站提供了当前的月球照明水平,您可以将其分解为新月、眉月、上弦月、凸月和满月等阶段。业余天文学家知道,追踪月相的乐趣在于了解它是“盈”(变得更亮)还是“亏”(变得更暗)。

虽然在任何给定时刻,月球的照明都基于其位置以及您相对于太阳的位置,但月相的完整周期始于并结束于新月(0% 照明),而满月(100% 照明)是旅程的中点。

因此,要确定盈亏,您所需要做的就是知道今天的月球照明水平以及昨天或明天的照明水平。幸运的是,“月亮巨人”网站非常乐意让您确定特定日期的照明水平。

快速访问该网站,使用常规网络浏览器会发现它使用基于日期的 URL 格式,例如:http://www.moongiant.com/phase/11/6/2016。

因此,您可以使用调用 date 程序来构建前一天的日期 URL。如果您安装了 GNU 版本的 date,则很容易后退一天


$ date
Mon Nov  7 11:40:31 MST 2016
$ date -v -1d
Sun Nov  6 11:40:15 MST 2016

事实证明,您还可以指定要后退 24 小时,当然,最终结果是相同的


$ date -v -24H
Sun Nov  6 11:40:24 MST 2016

更重要的是,您可以将格式字符串传递给 date,然后可以使用 eval 函数对其进行求值,这样您就可以在一个简单的步骤中设置昨天的月份、日期和年份


$ eval $( date -v -1d +"mon=%m day=%d year=%Y" )
$ echo month = $mon, day = $day and year $year
month = 11, day = 06 and year 2016

当您需要处理从日期中提取特定元素时,这是一个非常方便的技巧,当它还涉及日期计算时,更是方便 10 倍。

旧版本的 Date 程序更加复杂

但是,如果您的 date 版本不包含 -v 标志,并且没有所有这些花哨的功能怎么办?那么,我的朋友,您将面临一个明确的挑战。日期计算非常容易,除非遇到边缘情况。

也就是说,即使是最基本的 Linux 版本的 date,也很容易提取当前月份、日期和年份,并且显然很容易从日期中减去 1,但如果它是月初呢?或者是年初?

那也可以做到,但这只是稍微多一点工作。值得注意的是,您还需要了解闰年,因为 2016 年 3 月 1 日的前一天可能是 2 月 28 日,也可能是 2 月 29 日,具体取决于 2016 年是否是闰年。

现在,一个偷偷摸摸的简单方法是回避这个问题。如果月份中的日期编号大于 1,则减去 1 以获得昨天的日期。但是,如果它是第一天,则加 1 并反转盈/亏测试的逻辑

幸运的是,我确实有更复杂的 date 程序,所以我将做最令人沮丧的事情之一,并将这个特殊的方面留给读者作为众所周知的练习。

昨天的月球照明水平

了解指定日期时“月亮巨人”URL 的格式,并了解如何使用 evaldate 获取昨天的数字月份、日期和年份值,以下是一些将它们组合在一起的代码


url_ago="http://www.moongiant.com/phase"
eval $( date -v -1d +"mon=%m day=%d year=%Y" )
ydayurl="$url_ago/$mon/$day/$year"

好消息是,生成的网页与今天的照明水平页面的格式相同,因此我在上一篇文章中探讨的相同 curl|grep 序列可以重复用于此任务


yillumlevel="$( curl -s "$ydayurl" | grep "$pattern" | tr ',' '\
' | grep "$pattern" | sed 's/[^0-9]//g')"

实际上,让我们添加一个调试语句,显示今天的月球照明水平和昨天的水平


echo today\'s illumination level = $illumlevel and \
    yesterday was $yillumlevel

在 2016 年 11 月 7 日运行它,这是脚本和“月亮巨人”网站的报告


today's illumination level = 47 and yesterday was 37

现在这是一个简单的测试:今天的水平是大于还是小于昨天的水平?

但是等等,“盈”和“亏”仅适用于眉月和凸月阶段。如果月亮是新月、上弦月或满月,则这两个词在常见的天文学术语中都不适用。

说真的,谁想出这些规则的?真是太复杂了!

以下是所有这些如何组合在一起的


if [ $illumlevel -gt $yillumlevel ] ; then
  # we're waxing if it's getting brighter
  waxwane="waxing"
else
  waxwane="waning"
fi
if [ $illumlevel -lt 5 ] ; then
 phasename="new"
elif [ $illumlevel -lt 45 ] ; then
 phasename="$waxwane crescent"
elif [ $illumlevel -lt 55 ] ; then
 phasename="quarter"
elif [ $illumlevel -lt 95 ] ; then
 phasename="$waxwane gibbous"
else
 phasename="full"
fi
echo "The moon is currently $phasename with \
      $illumlevel% illuminated."

这几乎就是整个脚本。如果我在 2016 年 11 月 7 日运行它,月亮的照明率为 47%,这使其成为上弦月(45%–55%),因此输出为


The moon is currently quarter with 47% illuminated.

几天后,在 11 月 10 日,输出将是您所希望的


The moon is currently waxing gibbous with 78% illuminated.

完成。简单又轻松。

功能蔓延

您可以使用此脚本做很多事情来改进它并使其更强大和灵活。最简单的方法是简单地重写输出行,使其语法不那么笨拙


echo "It's a $phasename moon that's $illumlevel% illuminated."

现在输出将更有意义,因为脚本报告“这是一个照明率为 72% 的亏凸月。”

更大的任务是允许用户指定日期并计算该特定日期的值(包括指定日期前一天)。我将使用相同的基本 date -v 方法来做到这一点,但首先要解析用户的输入并将其分解为月份、日期和年份。为了简单起见,将他们的输入限制为 MM/DD/YYYY 格式,并且该任务涉及的内容出奇地少。

当然,对于巨大的额外加分,图形显示会很不错。但是用 shell 脚本很难做到这一点,对吧?

下一篇文章

太空就到此为止。在下一篇文章中,我计划回到游戏,探索如何编写石头、剪刀、布游戏。您可能需要先研究一下这个游戏,以便做好准备!

Dave Taylor 在 UNIX 和 Linux 系统上编写 shell 脚本已经很长时间了。他是 Learning Unix for Mac OS XWicked Cool Shell Scripts 的作者。您可以在 Twitter 上找到他,账号是 @DaveTaylor,您可以通过他的技术问答网站联系他:Ask Dave Taylor

加载 Disqus 评论