Redian新闻
>
通过编写“猜数字”游戏来学习 Awk | Linux 中国

通过编写“猜数字”游戏来学习 Awk | Linux 中国

科技
 
导读:编程语言往往具有许多共同特征。学习一门新语言的好方法是去写一个熟悉的程序。在本文中,我将会使用 Awk 编写一个“猜数字”程序来展示熟悉的概念。
本文字数:7490,阅读时长大约:9分钟

编程语言往往具有许多共同特征。学习一门新语言的好方法是去写一个熟悉的程序。在本文中,我将会使用 Awk 编写一个“猜数字”程序来展示熟悉的概念。

当你学习一门新的编程语言时,最好把重点放在大多数编程语言都有的共同点上:

◈ 变量 —— 存储信息的地方
◈ 表达式 —— 计算的方法
◈ 语句 —— 在程序中表示状态变化的方法

这些概念是大多是编程语言的基础。

一旦你理解了这些概念,你就可以开始把其他的弄清楚。例如,大多数语言都有由其设计所支持的“处理方式”,这些方式在不同语言之间可能有很大的不同。这些方法包括模块化(将相关功能分组在一起)、声明式与命令式、面向对象、低级与高级语法特性等等。许多程序员比较熟悉的是编程“仪式”,即,在处理问题之前设置场景所需花费的工作。据说 Java 编程语言有一个源于其设计的重要仪式要求,就是所有代码都在一个类中定义。

但从根本上讲,编程语言通常有相似之处。一旦你掌握了一种编程语言,就可以从学习另一种语言的基本知识开始,品味这种新语言的不同之处。

一个好方法是创建一组基本的测试程序。有了这些,就可以从这些相似之处开始学习。

你可以选择创建的一个测试程序是“猜数字”程序。电脑从 1 到 100 之间选择一个数字,让你猜这个数字。程序一直循环,直到你猜对为止。

“猜数字”程序练习了编程语言中的几个概念:

◈ 变量
◈ 输入
◈ 输出
◈ 条件判断
◈ 循环

这是学习一门新的编程语言的一个很好的实践实验。

:本文改编自 Moshe Zadka 在 Julia🔗 opensource.com 中使用这种方法和 Jim Hall在 Bash🔗 opensource.com 中使用这种方法的文章。

在 awk 程序中猜数

让我们编写一个实现“猜数字”游戏的 Awk 程序。

Awk 是动态类型的,这是一种面向数据转换的脚本语言,并且对交互使用有着令人惊讶的良好支持。Awk 出现于 20 世纪 70 年代,最初是 Unix 操作系统的一部分。如果你不了解 Awk,但是喜欢电子表格,这就是一个你可以 去学习 Awk🔗 opensource.com 的信号!

您可以通过编写一个“猜数字”游戏版本来开始对 Awk 的探索。

以下是我的实现(带有行号,以便我们可以查看一些特定功能):

  1.      1    BEGIN {
  2.      2        srand(42)
  3.      3        randomNumber = int(rand() * 100) + 1
  4.      4        print "random number is",randomNumber
  5.      5        printf "guess a number between 1 and 100\n"
  6.      6    }
  7.      7    {
  8.      8        guess = int($0)
  9.      9        if (guess < randomNumber) {
  10.     10            printf "too low, try again:"
  11.     11        } else if (guess > randomNumber) {
  12.     12            printf "too high, try again:"
  13.     13        } else {
  14.     14            printf "that's right\n"
  15.     15            exit
  16.     16        }
  17.     17    }

我们可以立即看到 Awk 控制结构与 C 或 Java 的相似之处,但与 Python 不同。在像 if-then-elsewhile 这样的语句中,thenelse 和 while 部分接受一个语句或一组被 { 和 } 包围的语句。然而,Awk 有一个很大的区别需要从一开始就了解:

根据设计,Awk 是围绕数据管道构建的。

这是什么意思呢?大多数 Awk 程序都是一些代码片段,它们接收一行输入,对数据做一些处理,然后将其写入输出。认识到这种转换管道的需要,Awk 默认情况下提供了所有的转换管道。让我们通过关于上面程序的一个基本问题来探索:“从控制台读取数据”的结构在哪里?

答案是——“内置的”。特别的,第 7-17 行告诉 Awk 如何处理被读取的每一行。在这种情况下,很容易看到第 1-6 行是在读取任何内容之前被执行的。

更具体地说,第 1 行上的 BEGIN 关键字是一种“模式”,在本例中,它指示 Awk 在读取任何数据之前,应该先执行 { ... } 中 BEGIN 后面的内容。另一个类似的关键字 END,在这个程序中没有被使用,它指示 Awk 在读取完所有内容后要做什么。

回到第 7-17 行,我们看到它们创建了一个类似代码块 { ... } 的片段,但前面没有关键字。因为在 { 之前没有任何东西可以让 Awk 匹配,所以它将把这一行用于接收每一行输入。每一行的输入都将由用户输入作为猜测。

让我们看看正在执行的代码。首先,是在读取任何输入之前发生的序言部分。

在第 2 行,我们用数字 42 初始化随机数生成器(如果不提供参数,则使用系统时钟)。为什么要用 42?当然要选 42!🔗 en.wikipedia.org 第 3 行计算 1 到 100 之间的随机数,第 4 行输出该随机数以供调试使用。第 5 行邀请用户猜一个数字。注意这一行使用的是 printf,而不是 print。和 C 语言一样,printf 的第一个参数是一个用于格式化输出的模板。

既然用户知道程序需要输入,她就可以在控制台上键入猜测。如前所述,Awk 将这种猜测提供给第 7-17 行的代码。第 18 行将输入记录转换为整数;$0 表示整个输入记录,而 $1 表示输入记录的第一个字段,$2 表示第二个字段,以此类推。是的,Awk 使用预定义的分隔符(默认为空格)将输入行分割为组成字段。第 9-15 行将猜测结果与随机数进行比较,打印适当的响应。如果猜对了,第 15 行就会从输入行处理管道中提前退出。

就这么简单!

考虑到 Awk 程序不同寻常的结构,代码片段会对特定的输入行配置做出反应,并处理数据,让我们看看另一种结构,看看过滤部分是如何工作的:

  1.      1    BEGIN {
  2.      2        srand(42)
  3.      3        randomNumber = int(rand() * 100) + 1
  4.      4        print "random number is",randomNumber
  5.      5        printf "guess a number between 1 and 100\n"
  6.      6    }
  7.      7    int($0) < randomNumber {
  8.      8        printf "too low, try again: "
  9.      9    }
  10.     10    int($0) > randomNumber {
  11.     11        printf "too high, try again: "
  12.     12    }
  13.     13    int($0) == randomNumber {
  14.     14        printf "that's right\n"
  15.     15        exit
  16.     16    }

第 1–6 行代码没有改变。但是现在我们看到第 7-9 行是当输入整数值小于随机数时执行的代码,第 10-12 行是当输入整数值大于随机数时执行的代码,第 13-16 行是两者相等时执行的代码。

这看起来“很酷但很奇怪” —— 例如,为什么我们会重复计算 int($0)?可以肯定的是,用这种方法来解决问题会很奇怪。但这些模式确实是分离条件处理的非常好的方式,因为它们可以使用正则表达式或 Awk 支持的任何其他结构。

为了完整起见,我们可以使用这些模式将普通的计算与只适用于特定环境的计算分离开来。下面是第三个版本:

  1.      1    BEGIN {
  2.      2        srand(42)
  3.      3        randomNumber = int(rand() * 100) + 1
  4.      4        print "random number is",randomNumber
  5.      5        printf "guess a number between 1 and 100\n"
  6.      6    }
  7.      7    {
  8.      8        guess = int($0)
  9.      9    }
  10.     10    guess < randomNumber {
  11.     11        printf "too low, try again: "
  12.     12    }
  13.     13    guess > randomNumber {
  14.     14        printf "too high, try again: "
  15.     15    }
  16.     16    guess == randomNumber {
  17.     17        printf "that's right\n"
  18.     18        exit
  19.     19    }

认识到这一点,无论输入的是什么值,都需要将其转换为整数,因此我们创建了第 7-9 行来完成这一任务。现在第 10-12、13-15 和 16-19 行这三组代码,都是指已经定义好的变量 guess,而不是每次都对输入行进行转换。

让我们回到我们想要学习的东西列表:

◈ 变量 —— 是的,Awk 有这些;我们可以推断出,输入数据以字符串形式输入,但在需要时可以转换为数值
◈ 输入 —— Awk 只是通过它的“数据转换管道”的方式发送输入来读取数据
◈ 输出 —— 我们已经使用了 Awk 的 print 和 printf 函数来将内容写入输出
◈ 条件判断 —— 我们已经学习了 Awk 的 if-then-else 和对应特定输入行配置的输入过滤器
◈ 循环 —— 嗯,想象一下!我们在这里不需要循环,这还是多亏了 Awk 采用的“数据转换管道”方法;循环“就这么发生了”。注意,用户可以通过向 Awk 发送一个文件结束信号(当使用 Linux 终端窗口时可通过快捷键 CTRL-D)来提前退出管道。

不需要循环来处理输入的重要性是非常值得的。Awk 能够长期保持存在的一个原因是 Awk 程序是紧凑的,而它们紧凑的一个原因是不需要从控制台或文件中读取的那些格式代码。

让我们运行下面这个程序:

  1. $ awk -f guess.awk
  2. random number is 25
  3. guess a number between 1 and 100: 50
  4. too high, try again: 30
  5. too high, try again: 10
  6. too low, try again: 25
  7. that's right
  8. $

我们没有涉及的一件事是注释。Awk 注释以 # 开头,以行尾结束。

总结

Awk 非常强大,这种“猜数字”游戏是入门的好方法。但这不应该是你探索 Awk 的终点。你可以看看 Awk 和 Gawk(GNU Awk)的历史🔗 www.gnu.org,Gawk 是 Awk 的扩展版本,如果你在电脑上运行 Linux,可能会有这个。或者,从它的原始开发者那里阅读关于 最初版本🔗 archive.org 的各种信息。

你还可以 下载我们的备忘单🔗 opensource.com 来帮你记录下你所学的一切。

Awk 备忘单🔗 opensource.com


via: https://opensource.com/article/21/1/learn-awk

作者:Chris Hermansen 选题:lujun9972 译者:FYJNEVERFOLLOWS 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出


LCTT 译者 :FYJNEVERFOLLOWS
🌟🌟
翻译: 2.0 篇
|
贡献: 21 天
2022-05-07
2022-05-28
https://linux.cn/lctt/FYJNEVERFOLLOWS
欢迎遵照 CC-BY-SA 协议规定转载,
如需转载,请在文章下留言 “转载:公众号名称”,
我们将为您添加白名单,授权“转载文章时可以修改”。



微信扫码关注该文公众号作者

戳这里提交新闻线索和高质量文章给我们。
相关阅读
如何通过 chroot 恢复 Arch Linux 系统 | Linux 中国西江月 阿拉斯加游Archinstall 新的菜单系统让安装 Arch Linux 更容易了 | Linux 中国Fedora Linux 36 发布 | Linux 中国使用 dnf 进行 Linux 包管理 | Linux 中国你的 Linux 启动时有几只小企鹅? | Linux 中国使用 watch 和 tail 命令监视 Linux 上的活动 | Linux 中国好消息!Docker Desktop 现已支持 Linux | Linux 中国我如何在 Linux 上扫描家庭照片 | Linux 中国在 Linux 上学习 C 语言的五种方式 | Linux 中国【夏日的蓝色海岸】(6)普鲁旺斯的光荣“不要白死”我们还真是不能轻视疫情HydraPaper:一个支持多显示器的 Linux 壁纸管理器 | Linux 中国如何编写 C 程序在 Linux 上创建音乐播放列表 | Linux 中国【英译唐诗】杜甫《春夜喜雨》Linux 内核 5.18 版本正式发布,新增显卡驱动以及硬件支持 | Linux 中国使用 apt 进行 Linux 包管理 | Linux 中国最适合程序员的 10 款 Linux 发行版 | Linux 中国分享 8 篇使用 Linux 命令行的技巧 | Linux 中国微软还有另一个 Linux 发行版,而且是基于 Debian 的 | Linux 中国上一个说“丼”不读jǐng的人,已经被我骂哭了如何在 Fedora Linux 中安装多媒体编码器 | Linux 中国Fudgie?令人惊叹的 Budgie 桌面即将登陆 Fedora Linux | Linux 中国在 Linux 上玩电子游戏的三种方式 | Linux 中国英伟达在提升 Linux 上的 GPU 使用体验上迈出了一大步 | Linux 中国Linux 中国开通播客频道:“开源朗读者”和“硬核观察” | Linux 中国如何在 Linux 桌面中启用 “激活 Linux” 水印通知 | Linux 中国用 Gwenview 在 Linux 上裁剪和调整照片大小 | Linux 中国在 Ubuntu Linux 如何安装 H.264 解码器 | Linux 中国如何在 Linux 和 Windows 电脑之间共享文件 | Linux 中国在虚拟机中运行 Linux 的十大优点 | Linux 中国实测 Linux Mint 升级工具 | Linux 中国在 Linux 上使用 sudo 命令的 5 个理由 | Linux 中国《送孟浩然之广陵》我的英文译本编写你的第一段 JavaScript 代码 | Linux 中国
logo
联系我们隐私协议©2024 redian.news
Redian新闻
Redian.news刊载任何文章,不代表同意其说法或描述,仅为提供更多信息,也不构成任何建议。文章信息的合法性及真实性由其作者负责,与Redian.news及其运营公司无关。欢迎投稿,如发现稿件侵权,或作者不愿在本网发表文章,请版权拥有者通知本网处理。