Work the Shell - 电影知识问答和随机数的乐趣

作者:Dave Taylor

上个月,我们玩得很开心地挖掘了互联网电影数据库,制作了一组脚本,它们共同作用,可以轻松生成网站上排名前 250 部电影的列表,并附带发行日期。输出格式是

All About Eve | 1950

Hotel Rwanda | 2004

Sin City | 2005

City Lights | 1931

本月,我将研究如何分解这两个字段,并随机生成一些接近实际日期的可能的发行日期,然后将其作为问题发送到 Twitter 上。例如,它可能会问:“《卢旺达饭店》是在以下哪一年发行的:2000 年、2001 年、2004 年还是 2007 年?”

分割字段

好的,对于阅读本专栏的任何人来说,这都应该非常容易。有很多方法可以获取两条字段的数据记录并将其拆分,但我最喜欢的工具是 cut。所以,我们可以这样做

moviename="$(echo $entry | cut -d\| -f1)"
releasedate=$(echo $entry | cut -d\| -f2)"

这很简单,对吧?当然,如果您想做得更漂亮,您还需要去除任何前导或尾随空格,这可以使用 sed 命令来完成

sed 's/^ //g;s/ $//g'

但是,如何从文本文件中随机获取一行呢?

如果您还记得之前的专栏,Bash shell 内置数学功能的秘密功能之一(可以使用 $(( )) 符号访问)是无需任何其他麻烦即可获得随机整数的能力,就像这样

echo $(( $RANDOM ))

在您自己的命令 shell 中尝试几次,您将获得一系列随机整数值,例如 29408 和 17501。为了将其限制在文件大小之内,我们可以使用wc -l来识别实际数据文件中的行数,但是因为我们已经知道我们正在从 IMDb 获取 250 个电影标题,所以很容易直接使用该值。这是第一个尝试

pickline="$(( $RANDOM % 250 )) "

但这不太对,因为我们将得到 0-254 的值。您可以通过输入以下命令来验证这一点echo $(( 5 % 5 ))例如。所以,我们需要将所有数字向上移动一位

pickline="$(expr $(( $RANDOM % 250 )) + 1 )"

这会生成一个随机数。要从行文件中提取该值,有很多解决方案,但我将坚持使用 sed。在这种情况下,提取第 33 行的解决方案示例如下

sed -n 33p

但是,如果您将值更改为变量名,则会出现问题

sed -n $picklinep

您不能在变量名和 p 之间放置空格,但如果您不这样做,则会得到一个错误的变量名,因为它应该是 pickline,而不是 picklinep。解决方案是您可以在脚本中使用的秘密符号约定,当存在任何此类歧义时,可以使用花括号。所以,该行最终如下所示

sed -n ${pickline}p

这确实有效,并且在这种应用程序中,sed 也非常快。

至此,我们有了一个有趣信息的数据文件,我们可以从文件中提取随机行,并且可以将结果数据拆分为电影标题和发行年份。那么,提出合理的替代发行年份怎么样?

计算随机年份

我生成随机年份的第一个想法是加减 1-3 年,然后将这些用作替代值。如果我们正在看,例如,僵尸肖恩,于 2004 年发行,我们可能会得到 2001 年和 2007 年作为选项。匹配一部更新的电影,例如 2007 年的 刑房(尽管我不明白为什么它会在 IMDb 前 250 部电影列表中),我们遇到了问题。建议 2009 年作为可能的发行日期将是愚蠢的。

更重要的是,人们很快就会意识到测验中始终正确的是中间值 - 这不好。就像 SAT 和 GMAT 一样,重要的是避免答案中出现任何可能的模式。

因此,我们可以尝试更复杂的方法。每个可能的年份都是实际发行年份加上或减去 1-5 的随机值 - 足够接近,以至于记住正确的年份将具有挑战性。

这是脚本的开头

add="$(( $RANDOM % 2 ))"              
delta="$(expr $(( $RANDOM % 5 )) + 1)"      

在这里,add 将为 0(假)或 1(真)以供稍后进行条件测试,而 delta 是介于 1 到 5 之间的值,正如我们需要的那样。它们可以按如下方式应用

if [ $add -eq 1 ] ; then
  newvalue=$(expr $1 + $delta )
else
  newvalue=$(expr $1 - $delta )
fi

可以通过将其放入一个简单的脚本中轻松测试此脚本,我将其称为 random-years.sh。将其应用于起始年份 2000 的结果是 2002、1998、2005、2001、2003、2004。看起来足够随机,是吗?

现在,让我们考虑一些细微之处。首先,我们需要确保它永远不会超过当前年份,这可以通过使用格式字符串从 date 命令中获取该值来完成date +%Y(通过以下命令了解有关 date 命令理解的许多格式字符串的更多信息man strftime).

其次,这是一个更有趣的想法。如果电影是很久以前上映的,我们应该比最近上映的电影有更大的 delta。换句话说,如果电影是 卡萨布兰卡,它于 1942 年上映,66 年前。钢铁侠,也在前 250 名列表中,于 2008 年上映,0 年前。对于 卡萨布兰卡,我们可能有 1938 年甚至 1951 年的可能值,对于任何不是完全的电影迷来说,这将是一个很好的测验问题。但是,钢铁侠的如此大的范围是没有意义的。没有人会认为它可能在 1999 年上映。

那么在这种情况下我正在考虑的是,delta 可能是电影年龄的百分比,经过标准化处理,以便我们始终具有某种范围。也许 20%?这将为我们提供 卡萨布兰卡 的 13.2 和 钢铁侠 的 0 的 delta。这可能行得通。

啊,但我没空间了。下个月,我们将回到随机相邻年份函数来完成它,然后看看如何将这些问题发布到 Twitter 上,而不是仅仅在 Linux 命令行上。在那之前,“永志不忘,佳人!”

Dave Taylor 是 UNIX 领域的 26 年资深人士,Elm 邮件系统的创建者,也是畅销书 Wicked Cool Shell ScriptsTeach Yourself Unix in 24 Hours 等 16 本技术书籍的作者。他的主要网站是 www.intuitive.com,他还提供技术支持,网址为 AskDaveTaylor.com。如果您愿意,请在 Twitter 上关注他:twitter.com/DaveTaylor

加载 Disqus 评论