mirror of
https://github.com/LCTT/TranslateProject.git
synced 2025-03-15 01:50:08 +08:00
commit
11d461dfb6
@ -0,0 +1,72 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (stevenzdg988)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-13082-1.html)
|
||||
[#]: subject: (The importance of consistency in your Python code)
|
||||
[#]: via: (https://opensource.com/article/19/12/zen-python-consistency)
|
||||
[#]: author: (Moshe Zadka https://opensource.com/users/moshez)
|
||||
|
||||
Python 代码一致性的重要性
|
||||
======
|
||||
|
||||
> 本文是 Python 之禅特殊系列的一部分,重点是第十二、十三和十四原则:模糊性和明确性的作用。
|
||||
|
||||

|
||||
|
||||
最小惊喜原则是设计用户界面时的一个 [准则][2]。它是说,当用户执行某项操作时,程序执行的事情应该使用户尽量少地感到意外。这和孩子们喜欢一遍又一遍地读同一本书的原因是一样的:没有什么比能够预测并让预测成真更让人欣慰的了。
|
||||
|
||||
在开发 [ABC 语言][3](Python 的灵感来源)的过程中,一个重要的见解是,编程设计是用户界面,需要使用与 UI 设计者相同的工具来设计。值得庆幸的是,从那以后,越来越多的语言采用了 UI 设计中的<ruby>可承受性<rt>affordance</rt></ruby>和<ruby>人体工程学<rt>ergonomics</rt></ruby>的概念,即使它们的应用并不严格。
|
||||
|
||||
这就引出了 [Python 之禅][4] 中的三个原则。
|
||||
|
||||
### <ruby>面对歧义,要拒绝猜测的诱惑<rt>In the face of ambiguity, refuse the temptation to guess</rt></ruby>
|
||||
|
||||
`1 + "1"` 的结果应该是什么? `"11"` 和 `2` 都是猜测。这种表达方式是*歧义的*:无论如何做都会让一些人感到惊讶。
|
||||
|
||||
一些语言选择猜测。在 JavaScript 中,结果为 `"11"`。在 Perl 中,结果为 `2`。在 C 语言中,结果自然是空字符串。面对歧义,JavaScript、Perl 和 C 都在猜测。
|
||||
|
||||
在 Python 中,这会引发 `TypeError`:这不是能忽略的错误。捕获 `TypeError` 是非典型的:它通常将终止程序或至少终止当前任务(例如,在大多数 Web 框架中,它将终止对当前请求的处理)。
|
||||
|
||||
Python 拒绝猜测 `1 + "1"` 的含义。程序员必须以明确的意图编写代码:`1 + int("1")`,即 `2`;或者 `str(1) + "1"`,即 `"11"`;或 `"1"[1:]`,这将是一个空字符串。通过拒绝猜测,Python 使程序更具可预测性。
|
||||
|
||||
### <ruby>尽量找一种,最好是唯一一种明显的解决方案<rt>There should be one—and preferably only one—obvious way to do it</rt></ruby>
|
||||
|
||||
预测也会出现偏差。给定一个任务,你能预知要实现该任务的代码吗?当然,不可能完美地预测。毕竟,编程是一项具有创造性的任务。
|
||||
|
||||
但是,不必有意提供多种冗余方式来实现同一目标。从某种意义上说,某些解决方案或许 “更好” 或 “更 <ruby>Python 化<rt>Pythonic</rt></ruby>”。
|
||||
|
||||
对 Python 美学欣赏部分是因为,可以就哪种解决方案更好进行健康的辩论。甚至可以持不同观点而继续编程。甚至为使其达成一致,接受不同意的观点也是可以的。但在这一切之下,必须有一种这样的认识,即正确的解决方案终将会出现。我们必须希望,通过商定实现目标的最佳方法,而最终达成真正的一致。
|
||||
|
||||
### <ruby>虽然这种方式一开始可能并不明显(除非你是荷兰人)<rt>Although that way may not be obvious at first (unless you're Dutch)</rt></ruby>
|
||||
|
||||
这是一个重要的警告:首先,实现任务的最佳方法往往*不*明显。观念在不断发展。Python 也在进化。逐块读取文件的最好方法,可能要等到 Python 3.8 时使用 [walrus 运算符][5](`:=`)。
|
||||
|
||||
逐块读取文件这样常见的任务,在 Python 存在近 *30年* 的历史中并没有 “唯一的最佳方法”。
|
||||
|
||||
当我在 1998 年从 Python 1.5.2 开始使用 Python 时,没有一种逐行读取文件的最佳方法。多年来,知道字典中是否有某个键的最佳方法是使用关键字 `.haskey`,直到 `in` 操作符出现才发生改变。
|
||||
|
||||
只是要意识到找到实现目标的一种(也是唯一一种)方法可能需要 30 年的时间来尝试其它方法,Python 才可以不断寻找这些方法。这种历史观认为,为了做一件事用上 30 年是可以接受的,但对于美国这个存在仅 200 多年的国家来说,人们常常会感到不习惯。
|
||||
|
||||
从 Python 之禅的这一部分来看,荷兰人,无论是 Python 的创造者 [Guido van Rossum][6] 还是著名的计算机科学家 [Edsger W. Dijkstra][7],他们的世界观是不同的。要理解这一部分,某种程度的欧洲人对时间的感受是必不可少的。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/19/12/zen-python-consistency
|
||||
|
||||
作者:[Moshe Zadka][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[stevenzdg988](https://github.com/stevenzdg988)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/moshez
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/rh_003499_01_other11x_cc.png?itok=I_kCDYj0 (Two animated computers waving one missing an arm)
|
||||
[2]: https://www.uxpassion.com/blog/the-principle-of-least-surprise/
|
||||
[3]: https://en.wikipedia.org/wiki/ABC_(programming_language)
|
||||
[4]: https://www.python.org/dev/peps/pep-0020/
|
||||
[5]: https://www.python.org/dev/peps/pep-0572/#abstract
|
||||
[6]: https://en.wikipedia.org/wiki/Guido_van_Rossum
|
||||
[7]: http://en.wikipedia.org/wiki/Edsger_W._Dijkstra
|
@ -1,24 +1,26 @@
|
||||
[#]: collector: "lujun9972"
|
||||
[#]: translator: "MjSeven"
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
[#]: reviewer: "wxy"
|
||||
[#]: publisher: "wxy"
|
||||
[#]: url: "https://linux.cn/article-13079-1.html"
|
||||
[#]: subject: "My first day using Ansible"
|
||||
[#]: via: "https://opensource.com/article/20/10/first-day-ansible"
|
||||
[#]: author: "David Both https://opensource.com/users/dboth"
|
||||
|
||||
使用 Ansible 的第一天
|
||||
======
|
||||
一名系统管理员分享了如何使用 Ansible 在网络中配置计算机并把其带入实际工作的信息和建议。
|
||||
![People work on a computer server with devices][1]
|
||||
|
||||
无论是第一次还是第五十次,启动并运行一台新的物理或虚拟计算机都非常耗时,而且需要大量的工作。多年来,我一直使用我创建的一系列脚本和 RPM 来安装所需的软件包,并为我喜欢的工具配置选项。这种方法效果很好,简化了我的工作,而且还减少了在键盘上输入命令的时间。
|
||||
> 一名系统管理员分享了如何使用 Ansible 在网络中配置计算机并把其带入实际工作的信息和建议。
|
||||
|
||||
我一直在寻找更好的工作方式。近几年来,我一直在听到并且读到有关 [Ansible][2] 的信息,它是一个自动配置和管理系统的强大工具。Ansible 允许系统管理员在一个或多个剧本中为每个主机指定一个特定状态,然后执行使主机进入该状态的所有任务。包括安装或删除各种资源,例如 RPM 或 Apt 软件包、配置和其它文件、用户、组等等。
|
||||

|
||||
|
||||
无论是第一次还是第五十次,启动并运行一台新的物理或虚拟计算机都非常耗时,而且需要大量的工作。多年来,我一直使用我创建的一系列脚本和 RPM 来安装所需的软件包,并为我喜欢的工具配置各种选项。这种方法效果很好,简化了我的工作,而且还减少了在键盘上输入命令的时间。
|
||||
|
||||
我一直在寻找更好的工作方式。近几年来,我一直在听到并且读到有关 [Ansible][2] 的信息,它是一个自动配置和管理系统的强大工具。Ansible 允许系统管理员在一个或多个<ruby>剧本<rt>playbook</rt></ruby>中为每个主机指定一个特定状态,然后执行各种必要的任务,使主机进入该状态。这包括安装或删除各种资源,例如 RPM 或 Apt 软件包、配置文件和其它文件、用户、组等等。
|
||||
|
||||
因为一些琐事,我推迟了很长一段时间学习如何使用它。直到最近,我遇到了一个我认为 Ansible 可以轻松解决的问题。
|
||||
|
||||
这篇文章并不会完整地告诉你如何入门 Ansible,相反,它只是对我遇到的问题和我在一些隐秘的地方发现的信息的做一些记录。我在各种在线讨论和问答小组中找到的有关 Ansible 的许多信息都是错误的。错误范围包括明显的老旧信息(没有任何日期或来源的迹象),还有一些是完全错误的信息。
|
||||
这篇文章并不会完整地告诉你如何入门 Ansible,相反,它只是对我遇到的问题和我在一些隐秘的地方发现的信息的做了一些记录。我在各种在线讨论和问答小组中找到的有关 Ansible 的许多信息都是错误的。错误范围包括明显的老旧信息(没有任何日期或来源的迹象),还有一些是完全错误的信息。
|
||||
|
||||
本文所介绍的内容是有用的,尽管可能还有其它方法可以完成相同的事情,但我使用的是 Ansible 2.9.13 和 [Python][3] 3.8.5。
|
||||
|
||||
@ -32,13 +34,13 @@
|
||||
|
||||
### 开始
|
||||
|
||||
我读过许多有关 Ansible 的好文章和书籍,但从来没有遇到过“我必须把这个用到工作中”那种情况。但是,现在就是这种情况。
|
||||
我读过许多有关 Ansible 的好文章和书籍,但从来没有在“我必须现在就把这个做好!”的情况下读过。而现在 —— 好吧,就是现在!
|
||||
|
||||
在重读这些文档时,我发现它们主要是在讨论如何从 GitHub 开始安装并使用 Ansible,这很酷。但是我真的只是想尽快开始,所以我使用 DNF 和 Fedora 仓库中的版本在我的 Fedora 工作站上安装了它,非常简单。
|
||||
|
||||
但是后来我开始寻找文件位置,并尝试确定需要修改哪些配置文件、将我的剧本保存在什么位置,甚至一个剧本怎么写以及它的作用,我脑海中有一大堆(到目前为止)悬而未决的问题。
|
||||
|
||||
因此,在没有进一步描述我的困难的情况下,以下是我发现的东西以及促使我继续前进的东西。
|
||||
因此,不不需要进一步描述我的困难的情况下,以下是我发现的东西以及促使我继续前进的东西。
|
||||
|
||||
### 配置
|
||||
|
||||
@ -46,9 +48,9 @@ Ansible 的配置文件保存在 `/etc/ansible` 中,这很有道理,因为 `
|
||||
|
||||
#### ansible.cfg
|
||||
|
||||
在进行文档和线上找到的一些实践练习之后,我遇到了一些有关弃用某些较旧的 Python 文件的警告信息。因此,我在 `ansible.cfg` 中将 `deprecation_warnings` 设置为 `false`,这样那些愤怒的红色警告消息就不会出现了:
|
||||
在进行了从文档和线上找到的一些实践练习之后,我遇到了一些有关弃用某些较旧的 Python 文件的警告信息。因此,我在 `ansible.cfg` 中将 `deprecation_warnings` 设置为 `false`,这样那些愤怒的红色警告消息就不会出现了:
|
||||
|
||||
```bash
|
||||
```
|
||||
deprecation_warnings = False
|
||||
```
|
||||
|
||||
@ -56,28 +58,28 @@ deprecation_warnings = False
|
||||
|
||||
#### hosts 文件
|
||||
|
||||
与 `/etc/hosts` 文件不同,`hosts` 文件也被称为清单文件,它列出了网络上的主机。此文件允许将主机分组到相关集合中,例如服务器、工作站和任何你所需的名称。这个文件包含帮助和大量示例,所以我在这里就不详细介绍了。但是,有些事情你必须知道。
|
||||
与 `/etc/hosts` 文件不同,`hosts` 文件也被称为<ruby>清单<rt>inventory</rt></ruby>文件,它列出了网络上的主机。此文件允许将主机分组到相关集合中,例如“servers”、“workstations”和任何你所需的名称。这个文件包含帮助和大量示例,所以我在这里就不详细介绍了。但是,有些事情你必须知道。
|
||||
|
||||
主机可以在任何组之外列出,但是组对于识别具有一个或多个共同特征的主机很有帮助。组使用 INI 格式,所以服务器组看起来像这样:
|
||||
主机也可以列在组之外,但是组对于识别具有一个或多个共同特征的主机很有帮助。组使用 INI 格式,所以服务器组看起来像这样:
|
||||
|
||||
```
|
||||
[servers]
|
||||
server1
|
||||
server2
|
||||
...etc.
|
||||
......
|
||||
```
|
||||
|
||||
这个文件中必须有一个主机名,这样 Ansible 才能对它进行操作。尽管有些子命令允许指定主机名,但除非主机名在 `hosts` 文件中,否则命令会失败。一个主机也可以在多个组中。因此,除了 `[servers]` 组之外,`server1` 也可能是 `[webservers]` 组的成员,还可以是 `[ubuntu]` 组的成员,这样以区别于 Fedora 服务器。
|
||||
这个文件中必须有一个主机名,这样 Ansible 才能对它进行操作。即使有些子命令允许指定主机名,但除非主机名在 `hosts` 文件中,否则命令会失败。一个主机也可以放在多个组中。因此,除了 `[servers]` 组之外,`server1` 也可能是 `[webservers]` 组的成员,还可以是 `[ubuntu]` 组的成员,这样以区别于 Fedora 服务器。
|
||||
|
||||
Ansible 很智能。如果 `all` 参数用作主机名,Ansible 会扫描 `hosts` 文件并在它列出的所有主机上执行定义的任务。Ansible 只会尝试在每个主机上工作一次,不管它出现在多少个组中。这也意味着不需要定义 "all" 组,因为 Ansible 可以确定文件中的所有主机名,并创建自己唯一的主机名列表。
|
||||
Ansible 很智能。如果 `all` 参数用作主机名,Ansible 会扫描 `hosts` 文件并在它列出的所有主机上执行定义的任务。Ansible 只会尝试在每个主机上工作一次,不管它出现在多少个组中。这也意味着不需要定义 `all` 组,因为 Ansible 可以确定文件中的所有主机名,并创建自己唯一的主机名列表。
|
||||
|
||||
另一件需要注意的事情是单个主机的多个条目。我在 DNS 文件中使用 `CNAME` 记录来创建别名,这些别名指向某些主机的 [A 记录][5],这样,我可以将一个主机称为 `host1` 或 `h1` 或 `myhost`。如果你在 `hosts` 文件中为同一主机指定多个主机名,则 Ansible 将尝试在所有这些主机名上执行其任务,它无法知道它们指向同一主机。好消息是,这并不会影响整体结果;它只是多花了一点时间,因为 Ansible在辅助主机名上工作,它会确定所有操作均已执行。
|
||||
另一件需要注意的事情是单个主机的多个条目。我在 DNS 文件中使用 `CNAME` 记录来创建别名,这些别名指向某些主机的 [A 记录][5],这样,我可以将一个主机称为 `host1` 或 `h1` 或 `myhost`。如果你在 `hosts` 文件中为同一主机指定多个主机名,则 Ansible 将尝试在所有这些主机名上执行其任务,它无法知道它们指向同一主机。好消息是,这并不会影响整体结果;它只是多花了一点时间,因为 Ansible 会在次要主机名上工作,它会确定所有操作均已执行。
|
||||
|
||||
### Ansible facts
|
||||
### Ansible 实情
|
||||
|
||||
我阅读过 Ansible 的大多数材料都谈到了 [Ansible facts][6],它是与远程系统相关的数据,包括操作系统、IP 地址、文件系统等等。这些信息可以通过其它方式获得,如 `lshw`、`dmidecode` 或 `/proc` 文件系统等。但是 Ansible 会生成一个包含此信息的 JSON 文件。每次 Ansible 运行时,它都会生成这些数据。在这个数据流中,有大量的信息都是键值对形式:`<"变量名": "值">`。所有这些变量都可以在 Ansible 剧本中使用,理解海量信息的最好方法是亲自实践:
|
||||
我阅读过 Ansible 的大多数材料都谈到了 Ansible <ruby>[实情][6]<rt>facts</rt></ruby>,它是与远程系统相关的数据,包括操作系统、IP 地址、文件系统等等。这些信息可以通过其它方式获得,如 `lshw`、`dmidecode` 或 `/proc` 文件系统等。但是 Ansible 会生成一个包含此信息的 JSON 文件。每次 Ansible 运行时,它都会生成这些实情数据。在这个数据流中,有大量的信息,都是以键值对形式出现的:`<"variable-name": "value">`。所有这些变量都可以在 Ansible 剧本中使用,理解大量可用信息的最好方法是实际显示一下:
|
||||
|
||||
```bash
|
||||
```
|
||||
# ansible -m setup <hostname> | less
|
||||
```
|
||||
|
||||
@ -85,23 +87,23 @@ Ansible 很智能。如果 `all` 参数用作主机名,Ansible 会扫描 `host
|
||||
|
||||
### 模块
|
||||
|
||||
`ansible` 命令使用 `-m` 选项来指定 `setup` 模块。Ansible 已经内置了许多模块,所以你不需要使用 -m。也可以安装许多下载的模块,但是内置模块可以完成我目前项目所需的一切。
|
||||
上面的 `ansible` 命令使用 `-m` 选项来指定 `setup` 模块。Ansible 已经内置了许多模块,所以你对这些模块不需要使用 `-m`。也可以安装许多下载的模块,但是内置模块可以完成我目前项目所需的一切。
|
||||
|
||||
### 剧本
|
||||
|
||||
剧本可以放在任何地方。因为我需要以 root 身份运行,所以我将它放在了 `/root/ansible` 下。当我运行 Ansible 时,只要这个目录是当前的工作目录(PWD),它就可以找到我的剧本。Ansible 还有一个选项,用于在运行时指定其它剧本和位置。
|
||||
<ruby>剧本<rt>playbook</rt></ruby>几乎可以放在任何地方。因为我需要以 root 身份运行,所以我将它放在了 `/root/ansible` 下。当我运行 Ansible 时,只要这个目录是当前的工作目录(PWD),它就可以找到我的剧本。Ansible 还有一个选项,用于在运行时指定不同的剧本和位置。
|
||||
|
||||
剧本可以包含注释,但是我看到的文章或书籍很少提及此。作为一个相信记录的系统管理员,我发现使用注释很有帮助。这并不是和任务名称做同样的事情,而是要确定任务组的目的,并确保我以某种方式或顺序记录我做这些事情的原因。当我可能忘记最初的想法时,这可以帮助以后解决调试问题。
|
||||
剧本可以包含注释,但是我看到的文章或书籍很少提及此。但作为一个相信记录一切的系统管理员,我发现使用注释很有帮助。这并不是说在注释中做和任务名称同样的事情,而是要确定任务组的目的,并确保我以某种方式或顺序记录我做这些事情的原因。当我可能忘记最初的想法时,这可以帮助以后解决调试问题。
|
||||
|
||||
剧本只是定义主机所需状态的任务集合。在剧本的开头指定主机名或目录组,并定义 Ansible 将在其上运行剧本的主机。
|
||||
剧本只是定义主机所需状态的任务集合。在剧本的开头指定主机名或清单组,并定义 Ansible 将在其上运行剧本的主机。
|
||||
|
||||
以下是我的一个剧本示例:
|
||||
|
||||
```bash
|
||||
```
|
||||
################################################################################
|
||||
# This Ansible playbook updates Midnight commander configuration files. #
|
||||
################################################################################
|
||||
\- name: Update midnight commander configuration files
|
||||
- name: Update midnight commander configuration files
|
||||
hosts: all
|
||||
|
||||
tasks:
|
||||
@ -149,19 +151,18 @@ Ansible 很智能。如果 `all` 参数用作主机名,Ansible 会扫描 `host
|
||||
mode: 0644
|
||||
owner: root
|
||||
group: root
|
||||
<SNIP>
|
||||
<截断>
|
||||
```
|
||||
|
||||
剧本从它自己的名字和它将要操作的主机开始,在本文中,所有主机都在我的 `hosts` 文件中。`tasks` 部分列出了使主机达到所需状态的特定任务。这个剧本从使用 DNF 更新 Midnight Commander 开始(如果它不是最新的版本的话)。下一个任务确保创建所需的目录(如果它们不存在),其余任务将文件复制到合适的位置,这些 `file` 和 `copy` 任务还可以为目录和文件设置所有权和文件模式。
|
||||
|
||||
剧本细节超出了本文的范围,但是我对这个问题使用了一点蛮力。还有其它方法可以确定哪些用户需要更新文件,而不是对每个用户的每个文件使用一个任务。我的下一个目标是简化这个剧本,使用一些更先进的技术。
|
||||
|
||||
运行剧本很容易,只需要使用 `ansible-playbook` 命令。.yml 扩展名代表 YAML,我看到过它的几种不同含义,但我认为它是“另一种标记语言”,尽管有些人声称 YAML 不是这种语言。
|
||||
运行剧本很容易,只需要使用 `ansible-playbook` 命令。`.yml` 扩展名代表 YAML,我看到过它的几种不同含义,但我认为它是“<ruby>另一种标记语言<rt>Yet Another Markup Language</rt></ruby>”,尽管有些人声称 YAML 不是这种语言。
|
||||
|
||||
这个命令将会运行剧本,它会更新 Midnight Commander 文件:
|
||||
|
||||
|
||||
```bash
|
||||
```
|
||||
# ansible-playbook -f 10 UpdateMC.yml
|
||||
```
|
||||
|
||||
@ -171,12 +172,11 @@ Ansible 很智能。如果 `all` 参数用作主机名,Ansible 会扫描 `host
|
||||
|
||||
剧本运行时会列出每个任务和执行结果。`ok` 代表任务管理的机器状态已经完成,因为在任务中定义的状态已经为真,所以 Ansible 不需要执行任何操作。
|
||||
|
||||
`changed` 表示 Ansible 已经执行了指定的任务。在这种情况下,任务中定义的机器状态不为真,所以执行指定的操作使其为真。在彩色终端上,`TASK` 线会显示彩色。在我的咖啡色终端的主机上,`TASK` 线显示为琥珀色,`changed` 是棕色,`ok` 为绿色,错误是红色。
|
||||
`changed` 表示 Ansible 已经执行了指定的任务。在这种情况下,任务中定义的机器状态不为真,所以执行指定的操作使其为真。在彩色终端上,`TASK` 行会以彩色显示。我的终端配色为“amber-on-black”,`TASK` 行显示为琥珀色,`changed` 是棕色,`ok` 为绿色,错误是红色。
|
||||
|
||||
下面的输出是我最终用于在新主机执行安装后配置的剧本:
|
||||
|
||||
|
||||
```bash
|
||||
```
|
||||
PLAY [Post-installation updates, package installation, and configuration]
|
||||
|
||||
TASK [Gathering Facts]
|
||||
@ -205,16 +205,16 @@ changed: [testvm2] => (item=/root/ansible/PostInstallMain/files/MidnightComma
|
||||
TASK [create ~/.config/mc directory in /etc/skel]
|
||||
changed: [testvm2]
|
||||
|
||||
<SNIP>
|
||||
<截断>
|
||||
```
|
||||
|
||||
### cowsay
|
||||
|
||||
如果你的计算机上安装了 [cowsay][7] 程序,你会发现 `TASK` 的名字出现在奶牛的语音泡泡中:
|
||||
如果你的计算机上安装了 [cowsay][7] 程序,你会发现 `TASK` 的名字出现在奶牛的语音泡泡中:
|
||||
|
||||
```
|
||||
____________________________________
|
||||
< TASK [Ensure we have connectivity] >
|
||||
< TASK [Ensure we have connectivity] >
|
||||
------------------------------------
|
||||
\ ^__^
|
||||
\ (oo)\\_______
|
||||
@ -244,19 +244,19 @@ changed: [testvm2]
|
||||
└── UpdateMC.yml
|
||||
```
|
||||
|
||||
你可以使用任何结构。但是请注意,其它系统管理员可能需要使用你设置的剧本来工作,所以目录应该具有一定程度的逻辑。当我使用 RPM 和 Bash 脚本执行安装任务后,我的文件仓库有点分散,而且绝对没有任何逻辑结构。当我为许多管理任务创建剧本时,我将介绍一个更有逻辑的结构来管理我的目录。
|
||||
你可以使用任何结构。但是请注意,其它系统管理员可能需要使用你设置的剧本来工作,所以目录应该具有一定程度的逻辑。当我使用 RPM 和 Bash 脚本执行安装任务后,我的文件仓库有点分散,绝对没有任何逻辑结构。当我为许多管理任务创建剧本时,我将介绍一个更有逻辑的结构来管理我的目录。
|
||||
|
||||
### 多个剧本运行
|
||||
### 多次运行剧本
|
||||
|
||||
根据需要或期望多次运行剧本是安全的。只有当主机状态与任务中指定的状态不匹配时,才会执行每个任务。这使得很容易从先前的剧本运行中遇到的错误中恢复。因为当剧本遇到错误时,它将停止运行。
|
||||
|
||||
在测试我的第一个剧本时,我犯了很多错误并改正了它们。假设我的修正正确,那么剧本每次运行,都会跳过那些状态已与指定状态匹配的任务,执行不匹配状态的任务。当我的修复程序起作用时,前面失败的任务将成功完成,并且会执行此任务之后的任务--直到遇到另一个错误。
|
||||
在测试我的第一个剧本时,我犯了很多错误并改正了它们。假设我的修正正确,那么剧本每次运行,都会跳过那些状态已与指定状态匹配的任务,执行不匹配状态的任务。当我的修复程序起作用时,之前失败的任务就会成功完成,并且会执行此任务之后的任务 —— 直到遇到另一个错误。
|
||||
|
||||
这使得测试变得容易。我可以添加新任务,并且在运行剧本时,只有新任务会被执行,因为它们是唯一与测试主机期望状态不匹配的任务。
|
||||
|
||||
### 一些想法
|
||||
### 一些思考
|
||||
|
||||
有些任务不适合用 Ansible,因为有更好的方法可以实现特定的计算机状态。我想到的场景是使 VM 返回到初始状态,以便可以多次使用它来执行从已知状态开始的测试。让 VM 进入特定状态,然后对此时的计算机状态进行快照要容易得多。还原到该快照通常比 Ansible 将主机返回到之前状态相比,还原到快照通常会更容易且更快。在研究文章或测试新代码时,我每天都会做几次这样的事情。
|
||||
有些任务不适合用 Ansible,因为有更好的方法可以实现特定的计算机状态。我想到的场景是使 VM 返回到初始状态,以便可以多次使用它来执行从已知状态开始的测试。让 VM 进入特定状态,然后对此时的计算机状态进行快照要容易得多。还原到该快照与 Ansible 将主机返回到之前状态相比,通常还原到快照通常会更容易且更快。在研究文章或测试新代码时,我每天都会做几次这样的事情。
|
||||
|
||||
在完成用于更新 Midnight Commander 的剧本之后,我创建了一个新的剧本,用于在新安装的 Fedora 主机上执行安装任务。我已经取得了不错的进步,剧本比我第一个的更加复杂,但没有那么粗暴。
|
||||
|
||||
@ -268,7 +268,7 @@ changed: [testvm2]
|
||||
|
||||
我找到的最完整、最有用的参考文档是 Ansible 网站上的[用户指南][9]。本文仅供参考,不作为入门文档。
|
||||
|
||||
多年来,Opensource.com 已经发布了许多[有关 Ansible 的文章][10],我发现其中大多数对我的需求很有帮助。Enable Sysadmin 网站上也有很多对我有帮助 [Ansible 文章][11]。你可以通过查看本周(2020 年 10 月 13 日至 14 日)的 [AnsibleFest][12] 了解更多信息。该活动完全是虚拟的,可以免费注册。
|
||||
多年来,我们已经发布了许多[有关 Ansible 的文章][10],我发现其中大多数对我的需求很有帮助。Enable Sysadmin 网站上也有很多对我有帮助 [Ansible 文章][11]。你可以通过查看本周(2020 年 10 月 13 日至 14 日)的 [AnsibleFest][12] 了解更多信息。该活动完全是线上的,可以免费注册。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
@ -277,7 +277,7 @@ via: https://opensource.com/article/20/10/first-day-ansible
|
||||
作者:[David Both][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[MjSeven](https://github.com/MjSeven)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
@ -1,28 +1,30 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-13080-1.html)
|
||||
[#]: subject: (Use Joplin to find your notes faster)
|
||||
[#]: via: (https://opensource.com/article/21/1/notes-joplin)
|
||||
[#]: author: (Kevin Sonney https://opensource.com/users/ksonney)
|
||||
|
||||
使用 Joplin 更快地找到你的笔记
|
||||
======
|
||||
在多个手写和数字平台上整理笔记是一个严峻的挑战。这里有一个小技巧,可以更好地组织你的笔记,并快速找到你需要的东西。
|
||||
![Working from home at a laptop][1]
|
||||
|
||||
> 在多个手写和数字平台上整理笔记是一个严峻的挑战。这里有一个小技巧,可以更好地组织你的笔记,并快速找到你需要的东西。
|
||||
|
||||

|
||||
|
||||
在前几年,这个年度系列涵盖了单个的应用。今年,我们除了关注 2021 年的策略外,还将关注一体化解决方案。欢迎来到 2021 年 21 天生产力的第十五天。
|
||||
|
||||
保持生产力也意味着(在某种程度上)要有足够的组织能力,以便找到笔记并在需要时参考它们。这不仅是对我自己的挑战,也是我交谈的很多人的挑战。
|
||||
保持生产力也意味着(在某种程度上)要有足够的组织能力,以便找到笔记并在需要时参考它们。这不仅是对我自己的挑战,也是与我交谈的很多人的挑战。
|
||||
|
||||
多年来,我在应用中单独或使用数字笔记、纸质笔记、便签、数字便签、word 文档、纯文本文件以及一堆我忘记的其他格式的组合。这不仅让寻找笔记变得困难,而且知道把它们放在哪里是一个更大的挑战。
|
||||
多年来,我在应用中单独或使用数字笔记、纸质笔记、便签、数字便签、Word 文档、纯文本文件以及一堆我忘记的其他格式的组合。这不仅让寻找笔记变得困难,而且知道把它们放在哪里是一个更大的挑战。
|
||||
|
||||
![Stacks of paper notes on a desk][2]
|
||||
|
||||
一堆笔记 (Jessica Cherry, [CC BY-SA 4.0][3])
|
||||
*一堆笔记 (Jessica Cherry, [CC BY-SA 4.0][3])*
|
||||
|
||||
还有就是做笔记最重要的一点:如果你以后找不到它,笔记就没有任何价值。知道含有你所需信息的笔记存在于你保存笔记的_某处_,根本没有任何帮助。
|
||||
还有就是做笔记最重要的一点:如果你以后找不到它,笔记就没有任何价值。知道含有你所需信息的笔记存在于你保存笔记的*某处*,根本没有任何帮助。
|
||||
|
||||
我是如何为自己解决这个问题的呢?正如他们所说,这是一个过程,我希望这也是一个对其他人有效的过程。
|
||||
|
||||
@ -30,13 +32,13 @@
|
||||
|
||||
![Man holding a binder full of notes][4]
|
||||
|
||||
三年多的笔记 (Kevin Sonney, [CC BY-SA 4.0][3])
|
||||
*三年多的笔记 (Kevin Sonney, [CC BY-SA 4.0][3])*
|
||||
|
||||
为了保存我的数字笔记,我需要将它们全部集中到一个地方。这个工具需要能够从多种设备上访问,具有有用的搜索功能,并且能够导出或共享我的笔记。在尝试了很多很多不同的选项之后,我选择了 [Joplin][5]。Joplin 可以让我用 markdown 写笔记,有一个相当不错的搜索功能,有适用于所有操作系统(包括手机)的应用,并支持几种不同的设备同步方式。另外,它还有文件夹_和_标签,因此我可以按照对我有意义的方式将笔记分组。
|
||||
为了保存我的数字笔记,我需要将它们全部集中到一个地方。这个工具需要能够从多种设备上访问,具有有用的搜索功能,并且能够导出或共享我的笔记。在尝试了很多很多不同的选项之后,我选择了 [Joplin][5]。Joplin 可以让我用 Markdown 写笔记,有一个相当不错的搜索功能,有适用于所有操作系统(包括手机)的应用,并支持几种不同的设备同步方式。另外,它还有文件夹*和*标签,因此我可以按照对我有意义的方式将笔记分组。
|
||||
|
||||
![Organized Joplin notes management page][6]
|
||||
|
||||
我的 Joplin
|
||||
*我的 Joplin*
|
||||
|
||||
我花了一些时间才把所有的东西都放在我想要的地方,但最后,这真的是值得的。现在,我可以找到我所做的笔记,而不是让它们散落在我的办公室、不同的机器和各种服务中。
|
||||
|
||||
@ -47,7 +49,7 @@ via: https://opensource.com/article/21/1/notes-joplin
|
||||
作者:[Kevin Sonney][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
@ -1,5 +1,5 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: translator: (stevenzdg988)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
@ -245,7 +245,7 @@ via: https://opensource.com/article/19/2/testing-bash-bats
|
||||
|
||||
作者:[Darin London][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
译者:[stevenzdg988](https://github.com/stevenzdg988)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
@ -1,68 +0,0 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (7 Bash tutorials to enhance your command line skills in 2021)
|
||||
[#]: via: (https://opensource.com/article/21/1/bash)
|
||||
[#]: author: (Jim Hall https://opensource.com/users/jim-hall)
|
||||
|
||||
7 Bash tutorials to enhance your command line skills in 2021
|
||||
======
|
||||
Bash is the default command line shell on most Linux systems. So why not
|
||||
learn how to get the most out of it?
|
||||
![Terminal command prompt on orange background][1]
|
||||
|
||||
Bash is the default command line shell on most Linux systems. So why not learn how to get the most out of it? This year, Opensource.com featured many great articles to help you leverage the power of the Bash shell. These are some of the most-read articles about Bash:
|
||||
|
||||
## [Read and write data from anywhere with redirection in the Linux terminal][2]
|
||||
|
||||
Redirection of input and output is a natural function of any programming or scripting language. Technically, it happens inherently whenever you interact with a computer. Input gets read from stdin (standard input, usually your keyboard or mouse), output goes to stdout (standard output, a text or data stream), and errors get sent to stderr. Understanding that these data streams exist enables you to control where information goes when you're using a shell such as Bash. Seth Kenlon shared these great tips to get data from one place to another without a lot of mouse moving and key pressing. You may not use redirection often, but learning to use it can save you a lot of time needlessly opening files and copying and pasting data.
|
||||
|
||||
## [Get started with Bash scripting for sysadmins][3]
|
||||
|
||||
Bash is free and open source software, so anyone can install it, whether they run Linux, BSD, OpenIndiana, Windows, or macOS. Seth Kenlon helps you learn the commands and features that make Bash one of the most powerful shells available.
|
||||
|
||||
## [Try this Bash script for large filesystems][4]
|
||||
|
||||
Have you ever wanted to list all the files in a directory, but just the files, nothing else? How about only the directories? If you have, then Nick Clifton's article might be just what you're looking for. Nick shares a nifty Bash script that can list directories, files, links, or executables. The script works by using the **find** command to do the searching, and then it runs **ls** to show details. It's a clever solution for anyone managing a large Linux system.
|
||||
|
||||
## [Screenshot your Linux system configuration with Bash tools][5]
|
||||
|
||||
There are many reasons you might want to share your Linux configuration with other people. You might be looking for help troubleshooting a problem on your system, or maybe you're so proud of the environment you've created that you want to showcase it to fellow open source enthusiasts. Don Watkins shows us screenFetch and Neofetch to capture and share your system configuration.
|
||||
|
||||
## [6 Handy Bash scripts for Git][6]
|
||||
|
||||
Git has become a ubiquitous code management system. Knowing how to manage a Git repository can streamline your development experience. Bob Peterson shares six Bash scripts that will make your life easier when you're working with Git repositories. **gitlog** prints an abbreviated list of current patches against the master version. Variations of the script can show the patch SHA1 IDs or search for a string within a collection of patches.
|
||||
|
||||
## [5 ways to improve your Bash scripts][7]
|
||||
|
||||
A system admin often writes Bash scripts, some short and some quite lengthy, to accomplish various tasks. Alan Formy-Duval explains how you can make your Bash scripts simpler, more robust, and easier to read and debug. We might assume that we need to employ languages, such as Python, C, or Java, for higher functionality, but that's not necessarily true. The Bash scripting language is very powerful. There is a lot to learn to maximize its usefulness.
|
||||
|
||||
## [My favorite Bash hacks][8]
|
||||
|
||||
Katie McLaughlin helps you improve your productivity with aliases and other shortcuts for the things you forget too often. When you work with computers all day, it's fantastic to find repeatable commands and tag them for easy use later on. Katie's summary of useful Bash features and helper commands to save you time.
|
||||
|
||||
These Bash tips take an already powerful shell to a whole new level of usefulness. Feel free to share your own tips, too.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/21/1/bash
|
||||
|
||||
作者:[Jim Hall][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/jim-hall
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/terminal_command_linux_desktop_code.jpg?itok=p5sQ6ODE (Terminal command prompt on orange background)
|
||||
[2]: https://opensource.com/article/20/6/redirection-bash
|
||||
[3]: https://opensource.com/article/20/4/bash-sysadmins-ebook
|
||||
[4]: https://opensource.com/article/20/2/script-large-files
|
||||
[5]: https://opensource.com/article/20/1/screenfetch-neofetch
|
||||
[6]: https://opensource.com/article/20/1/bash-scripts-git
|
||||
[7]: https://opensource.com/article/20/1/improve-bash-scripts
|
||||
[8]: https://opensource.com/article/20/1/bash-scripts-aliases
|
@ -1,300 +0,0 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (amwps290)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Learn JavaScript by writing a guessing game)
|
||||
[#]: via: (https://opensource.com/article/21/1/learn-javascript)
|
||||
[#]: author: (Mandy Kendall https://opensource.com/users/mkendall)
|
||||
|
||||
Learn JavaScript by writing a guessing game
|
||||
======
|
||||
Take the first steps toward creating interactive, dynamic web content by
|
||||
practicing some basic JavaScript concepts with a simple game.
|
||||
![Javascript code close-up with neon graphic overlay][1]
|
||||
|
||||
It's pretty safe to say that most of the modern web would not exist without [JavaScript][2]. It's one of the three standard web technologies (along with HTML and CSS) and allows anyone to create much of the interactive, dynamic content we have come to expect in our experiences with the World Wide Web. From frameworks like [React][3] to data visualization libraries like [D3][4], it's hard to imagine the web without it.
|
||||
|
||||
There's a lot to learn, and a great way to begin learning this popular language is by writing a simple application to become familiar with some concepts. Recently, some Opensource.com correspondents have written about how to learn their favorite language by writing a simple guessing game, so that's a great place to start!
|
||||
|
||||
### Getting started
|
||||
|
||||
JavaScript comes in many flavors, but I'll start with the basic version, commonly called "Vanilla JavaScript." JavaScript is primarily a client-side scripting language, so it can run in any standard browser without installing anything. All you need is a code editor ([Brackets][5] is a great one to try) and the web browser of your choice.
|
||||
|
||||
### HTML user interface
|
||||
|
||||
JavaScript runs in a web browser and interacts with the other standard web technologies, HTML and CSS. To create this game, you'll first use HTML (Hypertext Markup Language) to create a simple interface for your players to use. In case you aren't familiar, HTML is a markup language used to provide structure to content on the web.
|
||||
|
||||
To start, create an HTML file for your code. The file should have the `.html` extension to let the browser know that it is an HTML document. You can call your file `guessingGame.html`.
|
||||
|
||||
Use a few basic HTML tags in this file to display the game's title, instructions for how to play, interactive elements for the player to use to enter and submit their guesses, and a placeholder for providing feedback to the player:
|
||||
|
||||
|
||||
```
|
||||
<!DOCTYPE>
|
||||
<[html][6]>
|
||||
<[head][7]>
|
||||
<[meta][8] charset="UTF-8" />
|
||||
<[title][9]> JavaScript Guessing Game </[title][9]>
|
||||
</[head][7]>
|
||||
<[body][10]>
|
||||
<[h1][11]>Guess the Number!</[h1][11]>
|
||||
<[p][12]>I am thinking of a number between 1 and 100. Can you guess what it is?</[p][12]>
|
||||
|
||||
<[label][13] for="guess">My Guess</[label][13]>
|
||||
<[input][14] type="number" id="guess">
|
||||
<[input][14] type="submit" id="submitGuess" value="Check My Guess">
|
||||
|
||||
<[p][12] id="feedback"></[p][12]>
|
||||
</[body][10]>
|
||||
</[html][6]>
|
||||
```
|
||||
|
||||
The `<h1>` and `<p>` elements let the browser know what type of text to display on the page. The set of `<h1>` tags signifies that the text between those two tags (`Guess the Number!`) is a heading. The set of `<p>` tags that follow signify that the short block of text with the instructions is a paragraph. The empty set of `<p>` tags at the end of this code block serve as a placeholder for the feedback the game will give the player based on their guess.
|
||||
|
||||
### The <script> tag
|
||||
|
||||
There are many ways to include JavaScript in a web page, but for a short script like this one, you can use a set of `<script>` tags and write the JavaScript directly in the HTML file. Those `<script>` tags should go right before the closing `</body>` tag near the end of the HTML file.
|
||||
|
||||
Now, you can start to write your JavaScript between these two script tags. The final file looks like this:
|
||||
|
||||
|
||||
```
|
||||
<!DOCTYPE>
|
||||
<[html][6]>
|
||||
|
||||
<[head][7]>
|
||||
<[meta][8] charset="UTF-8" />
|
||||
<[title][9]> JavaScript Guessing Game </[title][9]>
|
||||
</[head][7]>
|
||||
|
||||
<[body][10]>
|
||||
<[h1][11]>Guess the Number!</[h1][11]>
|
||||
<[p][12]>I am thinking of a number between 1 and 100. Can you guess what it is?</[p][12]>
|
||||
|
||||
<[form][15]>
|
||||
<[label][13] for="guess">My Guess</[label][13]>
|
||||
<[input][14] type="number" id="guess">
|
||||
<[input][14] type="submit" id="submitGuess" value="Check My Guess">
|
||||
</[form][15]>
|
||||
|
||||
<[p][12] id="feedback"></[p][12]>
|
||||
|
||||
<[script][16]>
|
||||
const randomNumber = Math.floor(Math.random() * 100) + 1
|
||||
console.log('Random Number', randomNumber)
|
||||
|
||||
function checkGuess() {
|
||||
let myGuess = guess.value
|
||||
if (myGuess === randomNumber) {
|
||||
feedback.textContent = "You got it right!"
|
||||
} else if (myGuess > randomNumber) {
|
||||
feedback.textContent = "Your guess was " + myGuess + ". That's too high. Try Again!"
|
||||
} else if (myGuess < randomNumber) {
|
||||
feedback.textContent = "Your guess was " + myGuess + ". That's too low. Try Again!"
|
||||
}
|
||||
}
|
||||
submitGuess.addEventListener('click', checkGuess)
|
||||
</[script][16]>
|
||||
|
||||
</[body][10]>
|
||||
|
||||
</[html][6]>
|
||||
```
|
||||
|
||||
To run this in the browser, either double-click on the file or go to the menu in your favorite web browser and choose **File > Open File**. (If you are using Brackets, you can also use the lightning-bolt symbol in the corner to open the file in the browser).
|
||||
|
||||
### Pseudo-random number generation
|
||||
|
||||
The first step in the guessing game is to generate a number for the player to guess. JavaScript includes several built-in global objects that help you write code. To generate your random number, use the Math object.
|
||||
|
||||
[Math][17] has properties and functions for working with mathematical concepts in JavaScript. You will use two Math functions to generate the random number for your player to guess.
|
||||
|
||||
Start with [Math.random()][18], which generates a pseudo-random number between 0 and 1. (Math.random is inclusive of 0 but exclusive of 1. This means that the function could generate a zero, but it will never generate a 1.)
|
||||
|
||||
For this game, set the random number between 1 and 100 to narrow down the player's options. Take the decimal you just generated and multiply it by 100 to produce a decimal between 0 and…not quite 100. But you'll take care of that in a few more steps.
|
||||
|
||||
Right now, your number is still a decimal, and you want it to be a whole number. For that, you can use another function that is part of the Math object, [Math.floor()][19]. Math.floor()'s purpose is to return the largest integer that is less than or equal to the number you give it as an argument—which means it rounds down to the nearest whole number:
|
||||
|
||||
|
||||
```
|
||||
`Math.floor(Math.random() * 100)`
|
||||
```
|
||||
|
||||
That leaves you with a whole number between 0 and 99, which isn't quite the range you want. You can fix that with your last step, which is to add 1 to the result. Voila! Now you have a (somewhat) randomly generated number between 1 and 100:
|
||||
|
||||
|
||||
```
|
||||
`Math.floor(Math.random() * 100) + 1`
|
||||
```
|
||||
|
||||
### Variables
|
||||
|
||||
Now you need to store the randomly generated number so that you can compare it to your player's guesses. To do that, you can assign it to a **variable**.
|
||||
|
||||
JavaScript has different types of variables you can choose, depending on how you want to use the variable. For this game, use const and let.
|
||||
|
||||
* **let** is used for variables if their value can change throughout the code.
|
||||
* **const** is used for variables if their value should not be changed.
|
||||
|
||||
|
||||
|
||||
There's a little more to const and let, but this is all you need to know for now.
|
||||
|
||||
The random number is generated only once in the game, so you will use a const variable to hold the value. You want to give the variable a name that makes it clear what value is being stored, so name it `randomNumber`:
|
||||
|
||||
|
||||
```
|
||||
`const randomNumber`
|
||||
```
|
||||
|
||||
_A note on naming: Variables and function names in JavaScript are written in camel case. If there is just one word, it is written in all lower case. If there is more than one word, the first word is all lower case, and any additional words start with a capital letter with no spaces between the words._
|
||||
|
||||
### Logging to the console
|
||||
|
||||
Normally, you don't want to show anyone the random number, but developers may want to know the number that was generated to use it to help debug the code. With JavaScript, you can use another built-in function, [console.log()][20], to output the number to the console in your browser.
|
||||
|
||||
Most browsers include Developer Tools that you can open by pressing the **F12** key on your keyboard. From there, you should see a tab labeled **Console**. Any information logged to the console will appear here. Since the code you have written so far will run as soon as the browser loads, if you look at the console, you should see the random number that you just generated! Hooray!
|
||||
|
||||
![Javascript game with console][21]
|
||||
|
||||
### Functions
|
||||
|
||||
Next, you need a way to get the player's guess from the number input field, compare it to the random number you just generated, and give the player feedback to let them know if they guessed correctly. To do that, write a function. A **function** is code that is grouped to perform a task. Functions are reusable, which means if you need to run the same code multiple times, you can call the function instead of rewriting all of the steps needed to perform the task.
|
||||
|
||||
Depending on the JavaScript version you are using, there are many different ways to write, or declare, a function. Since this is an introduction to the language, declare your function using the basic function syntax.
|
||||
|
||||
Start with the keyword `function` and then give the function a name. It's good practice to use a name that is an action that describes what the function does. In this case, you are checking the player's guess, so an appropriate name for this function would be `checkGuess`. After the function name, write a set of parentheses and then a set of curly braces. You will write the body of the function between these curly braces:
|
||||
|
||||
|
||||
```
|
||||
`function checkGuess() {}`
|
||||
```
|
||||
|
||||
### Access the DOM
|
||||
|
||||
One of the purposes of JavaScript is to interact with HTML on a webpage. It does this through the Document Object Model (DOM), which is an object JavaScript uses to access and change the information on a web page. Right now, you need to get the player's guess from the number input field you set up in the HTML. You can do that using the `id` attribute you assigned to the HTML elements, which in this case is `guess`:
|
||||
|
||||
|
||||
```
|
||||
`<input type="number" id="guess">`
|
||||
```
|
||||
|
||||
JavaScript can get the number the player enters into the number input field by accessing its value. You can do this by referring to the element's id and adding `.value` to the end. This time, use a `let` variable to hold the value of the user's guess:
|
||||
|
||||
|
||||
```
|
||||
`let myGuess = guess.value`
|
||||
```
|
||||
|
||||
Whatever number the player enters into the number input field will be assigned to the `myGuess` variable in the `checkGuess` function.
|
||||
|
||||
### Conditional statements
|
||||
|
||||
The next step is to compare the player's guess with the random number the game generates. You also want to give the player feedback to let them know if their guess was too high, too low, or correct.
|
||||
|
||||
You can decide what feedback the player will receive by using a series of conditional statements. A **conditional statement** checks to see if a condition is met before running a code block. If the condition is not met, the code stops, moves on to check the next condition, or continues with the rest of the code without running the code in the conditional block:
|
||||
|
||||
|
||||
```
|
||||
if (myGuess === randomNumber){
|
||||
feedback.textContent = "You got it right!"
|
||||
}
|
||||
else if(myGuess > randomNumber) {
|
||||
feedback.textContent = "Your guess was " + myGuess + ". That's too high. Try Again!"
|
||||
}
|
||||
else if(myGuess < randomNumber) {
|
||||
feedback.textContent = "Your guess was " + myGuess + ". That's too low. Try Again!"
|
||||
}
|
||||
```
|
||||
|
||||
The first conditional block compares the player's guess to the random number the game generates using a comparison operator `===`. The comparison operator checks the value on the right, compares it to the value on the left, and returns the boolean `true` if they match and `false` if they don't.
|
||||
|
||||
If the number matches (yay!), make sure the player knows. To do this, manipulate the DOM by adding text to the `<p>` tag that has the id attribute "feedback." This works just like `guess.value` above, except instead of getting information from the DOM, it changes the information in it. `<p>` elements don't have a value like `<input>` elements—they have text instead, so use `.textContent` to access the element and set the text you want to display:
|
||||
|
||||
|
||||
```
|
||||
`feedback.textContent = "You got it right!"`
|
||||
```
|
||||
|
||||
Of course, there is a good chance that the player didn't guess right on the first try, so if `myGuess` and `randomNumber` don't match, give the player a clue to help them narrow down their guesses. If the first conditional fails, the code will skip the code block in that `if` statement and check to see if the next condition is true. That brings you to your `else if` blocks:
|
||||
|
||||
|
||||
```
|
||||
else if(myGuess > randomNumber) {
|
||||
feedback.textContent = "Your guess was " + myGuess + ". That's too high. Try Again!"
|
||||
}
|
||||
```
|
||||
|
||||
If you were to read this as a sentence, it might be something like this: "If the player's guess is equal to the random number, let them know they got it right. Otherwise (else), check if the player's guess is greater than `randomNumber`, and if it is, display the player's guess and tell them it was too high."
|
||||
|
||||
The last possibility is that the player's guess was lower than the random number. To check that, add one more `else if` block:
|
||||
|
||||
|
||||
```
|
||||
else if(myGuess < randomNumber) {
|
||||
feedback.textContent = "Your guess was " + myGuess + ". That's too low. Try Again!"
|
||||
}
|
||||
```
|
||||
|
||||
### User events and event listeners
|
||||
|
||||
If you look at your script, you'll see that some of the code runs automatically when the page loads, but some of it does not. You want to generate the random number before the game is played, but you don't want to check the player's guess until they have entered it into the number input field and are ready to check it.
|
||||
|
||||
The code to generate the random number and log it to the console is outside of a function, so it will run automatically when the browser loads your script. However, for the code inside your function to run, you have to call it.
|
||||
|
||||
There are several ways to call a function. Here, you want the function to run when the player clicks on the "Check My Guess" button. Clicking a button creates a user event, which the JavaScript code can then "listen" for so that it knows when it needs to run a function.
|
||||
|
||||
The last line of code adds an event listener to the button to "listen" for when the button is clicked. When it "hears" that event, it will run the function assigned to the event listener:
|
||||
|
||||
|
||||
```
|
||||
`submitGuess.addEventListener('click', checkGuess)`
|
||||
```
|
||||
|
||||
Just like the other instances where you access DOM elements, you can use the button's id to tell JavaScript which element to interact with. Then you can use the built-in `addEventListener` function to tell JavaScript what event to listen for.
|
||||
|
||||
You have already seen a function that takes parameters, but take a moment to look at how this works. Parameters are information that a function needs to perform its task. Not all functions need parameters, but the `addEventListener` function needs two. The first parameter it takes is the name of the user event for which it will listen. The user can interact with the DOM in many ways, like typing, moving the mouse, tabbing with the keyboard, or copying and pasting text. In this case, the user event you are listening for is a button click, so the first parameter will be `click`.
|
||||
|
||||
The second piece of information `addEventListener` needs is the name of the function to run when the user clicks the button. In this case, it's the `checkGuess` function.
|
||||
|
||||
Now, when the player presses the "Check My Guess" button, the `checkGuess` function will get the value they entered in the number input field, compare it to the random number, and display feedback in the browser to let the player know how they did. Awesome! Your game is ready to play.
|
||||
|
||||
### Learn JavaScript for fun and profit
|
||||
|
||||
This bit of Vanilla JavaScript is just a small taste of what this vast ecosystem has to offer. It's a language well worth investing time into learning, and I encourage you to continue to dig in and learn more.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/21/1/learn-javascript
|
||||
|
||||
作者:[Mandy Kendall][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/mkendall
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/code_javascript.jpg?itok=60evKmGl (Javascript code close-up with neon graphic overlay)
|
||||
[2]: https://opensource.com/tags/javascript
|
||||
[3]: https://opensource.com/article/20/11/reactjs-tutorial
|
||||
[4]: https://opensource.com/article/18/9/open-source-javascript-chart-libraries
|
||||
[5]: https://opensource.com/article/20/12/brackets
|
||||
[6]: http://december.com/html/4/element/html.html
|
||||
[7]: http://december.com/html/4/element/head.html
|
||||
[8]: http://december.com/html/4/element/meta.html
|
||||
[9]: http://december.com/html/4/element/title.html
|
||||
[10]: http://december.com/html/4/element/body.html
|
||||
[11]: http://december.com/html/4/element/h1.html
|
||||
[12]: http://december.com/html/4/element/p.html
|
||||
[13]: http://december.com/html/4/element/label.html
|
||||
[14]: http://december.com/html/4/element/input.html
|
||||
[15]: http://december.com/html/4/element/form.html
|
||||
[16]: http://december.com/html/4/element/script.html
|
||||
[17]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math
|
||||
[18]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random
|
||||
[19]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/floor
|
||||
[20]: https://developer.mozilla.org/en-US/docs/Web/API/Console/log
|
||||
[21]: https://opensource.com/sites/default/files/javascript-game-with-console.png (Javascript game with console)
|
@ -1,63 +0,0 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (3 wishes for open source productivity in 2021)
|
||||
[#]: via: (https://opensource.com/article/21/1/productivity-wishlist)
|
||||
[#]: author: (Kevin Sonney https://opensource.com/users/ksonney)
|
||||
|
||||
3 wishes for open source productivity in 2021
|
||||
======
|
||||
There are plenty of ways the open source world can expand for 2021. Here
|
||||
are the three areas I'm particularly interested in.
|
||||
![Looking at a map for career journey][1]
|
||||
|
||||
In prior years, this annual series covered individual apps. This year, we are looking at all-in-one solutions in addition to strategies to help in 2021. Welcome to the final day of 21 Days of Productivity in 2021.
|
||||
|
||||
Here we are, at the end of another series. So let's talk about the things I want to see more of in 2021.
|
||||
|
||||
### Disconnecting
|
||||
|
||||
![Large Lego set built by the author][2]
|
||||
|
||||
I built this over the holidays (Kevin Sonney, [CC BY-SA 4.0][3])
|
||||
|
||||
For many, many, _many_ people, 2020 was a very difficult year. The pandemic, the various political events, the 24-hour news cycle, and so on took a toll on our mental well-being. And while I did talk about [making time for self-care][4], I only touched on disconnecting—that is, turning off alerts, phones, tablets, etc., and just ignoring the world for a bit. One of the managers in my company actually told us to turn off all our work-related stuff if we had a holiday or a day off (unless we were on call). One of my favorite "disconnect" activities is just listening to music and building big, complex Lego sets.
|
||||
|
||||
### Accessibility
|
||||
|
||||
While many of the techniques I talked about are something anyone can do, the software aspects all have some difficulty with accessibility. Linux and the open source world have come a long way when it comes to assistive technologies since the early days of the movement. However, there are still far too many applications and systems that do not consider that the user may not have the same abilities as the person who designed them. I am keeping an eye on developments in this area because everyone should be able to access things.
|
||||
|
||||
### More all-in-one options
|
||||
|
||||
![JPilot all in one organizer software interface][5]
|
||||
|
||||
JPilot (Kevin Sonney, [CC BY-SA 4.0][3])
|
||||
|
||||
There are nowhere near as many all-in-one Personal Information Manager solutions in the FOSS world as there are in the commercial software world. The overall trend has been to use individual apps that must be configured to talk to each other or through an intermediary service (like a CalDAV server). The mobile market largely drives this trend, but I still yearn for the days when something like [JPilot][6] could do almost everything I needed without extra plugins or services.
|
||||
|
||||
Thank you all very much for reading the series year. Please comment with what you think I missed or need to look at for next year.
|
||||
|
||||
And as I say on [Productivity Alchemy][7], do your best to Stay Productive!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/21/1/productivity-wishlist
|
||||
|
||||
作者:[Kevin Sonney][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/ksonney
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/career_journey_road_gps_path_map_520.png?itok=PpL6jJgY (Looking at a map for career journey)
|
||||
[2]: https://opensource.com/sites/default/files/day21-image1.png
|
||||
[3]: https://creativecommons.org/licenses/by-sa/4.0/
|
||||
[4]: https://opensource.com/article/21/1/self-care
|
||||
[5]: https://opensource.com/sites/default/files/day21-image2.png
|
||||
[6]: http://www.jpilot.org/
|
||||
[7]: https://productivityalchemy.com
|
@ -1,5 +1,5 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
|
@ -0,0 +1,315 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Defining boundaries and interfaces in software development)
|
||||
[#]: via: (https://opensource.com/article/21/2/boundaries-interfaces)
|
||||
[#]: author: (Alex Bunardzic https://opensource.com/users/alex-bunardzic)
|
||||
|
||||
Defining boundaries and interfaces in software development
|
||||
======
|
||||
Zombies are bad at understanding boundaries, so set limits and
|
||||
expectations for what your app can do.
|
||||
![Looking at a map for career journey][1]
|
||||
|
||||
Zombies are bad at understanding boundaries. They trample over fences, tear down walls, and generally get into places they don't belong. In the previous articles in this series, I explained why tackling coding problems all at once, as if they were hordes of zombies, is a mistake.
|
||||
|
||||
**ZOMBIES** is an acronym that stands for:
|
||||
|
||||
**Z** – Zero
|
||||
**O** – One
|
||||
**M** – Many (or more complex)
|
||||
**B** – Boundary behaviors
|
||||
**I** – Interface definition
|
||||
**E** – Exercise exceptional behavior
|
||||
**S** – Simple scenarios, simple solutions
|
||||
|
||||
In the first two articles in this series, I demonstrated the first three **ZOMBIES** principles of **Zero**, **One**, and **Many**. The first article [implemented **Z**ero][2], which provides the simplest possible path through your code. The second article [performed tests][3] with **O**ne and **M**any samples. In this third article, I'll take a look at **B**oundaries and **I**nterfaces.
|
||||
|
||||
### Back to One
|
||||
|
||||
Before you can tackle **B**oundaries, you need to circle back (iterate).
|
||||
|
||||
Begin by asking yourself: What are the boundaries in e-commerce? Do I need or want to limit the size of a shopping basket? (I don't think that would make any sense, actually).
|
||||
|
||||
The only reasonable boundary at this point would be to make sure the shopping basket never contains a negative number of items. Write an executable expectation that expresses this limitation:
|
||||
|
||||
|
||||
```
|
||||
[Fact]
|
||||
public void Add1ItemRemoveItemRemoveAgainHas0Items() {
|
||||
var expectedNoOfItems = 0;
|
||||
var actualNoOfItems = -1;
|
||||
Assert.Equal(expectedNoOfItems, actualNoOfItems);
|
||||
}
|
||||
```
|
||||
|
||||
This says that if you add one item to the basket, remove that item, and remove it again, the `shoppingAPI` instance should say that you have zero items in the basket.
|
||||
|
||||
Of course, this executable expectation (microtest) fails, as expected. What is the bare minimum modification you need to make to get this microtest to pass?
|
||||
|
||||
|
||||
```
|
||||
[Fact]
|
||||
public void Add1ItemRemoveItemRemoveAgainHas0Items() {
|
||||
var expectedNoOfItems = 0;
|
||||
Hashtable item = [new][4] Hashtable();
|
||||
shoppingAPI.AddItem(item);
|
||||
shoppingAPI.RemoveItem(item);
|
||||
var actualNoOfItems = shoppingAPI.RemoveItem(item);
|
||||
Assert.Equal(expectedNoOfItems, actualNoOfItems);
|
||||
}
|
||||
```
|
||||
|
||||
This encodes an expectation that depends on the `RemoveItem(item)` capability. And because that capability is not in your `shippingAPI`, you need to add it.
|
||||
|
||||
Flip over to the `app` folder, open `IShippingAPI.cs` and add the new declaration:
|
||||
|
||||
|
||||
```
|
||||
`int RemoveItem(Hashtable item);`
|
||||
```
|
||||
|
||||
Go to the implementation class (`ShippingAPI.cs`), and implement the declared capability:
|
||||
|
||||
|
||||
```
|
||||
public int RemoveItem(Hashtable item) {
|
||||
basket.RemoveAt(basket.IndexOf(item));
|
||||
return basket.Count;
|
||||
}
|
||||
```
|
||||
|
||||
Run the system, and you get an error:
|
||||
|
||||
![Error][5]
|
||||
|
||||
(Alex Bunardzic, [CC BY-SA 4.0][6])
|
||||
|
||||
The system is trying to remove an item that does not exist in the basket, and it crashes. Add a little bit of defensive programming:
|
||||
|
||||
|
||||
```
|
||||
public int RemoveItem(Hashtable item) {
|
||||
if(basket.IndexOf(item) >= 0) {
|
||||
basket.RemoveAt(basket.IndexOf(item));
|
||||
}
|
||||
return basket.Count;
|
||||
}
|
||||
```
|
||||
|
||||
Before you try to remove the item from the basket, check if it is in the basket. (You could've tried by catching the exception, but I feel the above logic is easier to read and follow.)
|
||||
|
||||
### More specific expectations
|
||||
|
||||
Before we move to more specific expectations, let's pause for a second and examine what is meant by interfaces. In software engineering, an interface denotes a specification, or a description of some capability. In a way, interface in software is similar to a recipe in cooking. It lists the ingredients that make the cake but it is not actually edible. We follow the specified description in the recipe in order to bake the cake.
|
||||
|
||||
Similarly here, we define our service by first specifying what is this service capable of. That specification is what we call interface. But interface itself cannot provide any services to us. It is a mere blueprint which we then use and follow in order to implement specified capabilities.
|
||||
|
||||
So far, you have implemented the interface (partially; more capabilities will be added later) and the processing boundaries (you cannot have a negative number of items in the shopping basket). You instructed the `shoppingAPI` how to add items to the shopping basket and confirmed that the addition works by running the `Add2ItemsBasketHas2Items` test.
|
||||
|
||||
However, just adding items to the basket does not an e-commerce app make. You need to be able to calculate the total of the items added to the basket—time to add another expectation.
|
||||
|
||||
As is the norm by now (hopefully), start with the most straightforward expectation. When you add one item to the basket and the item price is $10, you expect the shopping API to correctly calculate the total as $10.
|
||||
|
||||
Your fifth test (the fake version):
|
||||
|
||||
|
||||
```
|
||||
[Fact]
|
||||
public void Add1ItemPrice10GrandTotal10() {
|
||||
var expectedTotal = 10.00;
|
||||
var actualTotal = 0.00;
|
||||
Assert.Equal(expectedTotal, actualTotal);
|
||||
}
|
||||
```
|
||||
|
||||
Make the `Add1ItemPrice10GrandTotal10` test fail by using the good old trick: hard-coding an incorrect actual value. Of course, your previous three tests succeed, but the new fourth test fails:
|
||||
|
||||
|
||||
```
|
||||
A total of 1 test files matched the specified pattern.
|
||||
[xUnit.net 00:00:00.57] tests.UnitTest1.Add1ItemPrice10GrandTotal10 [FAIL]
|
||||
X tests.UnitTest1.Add1ItemPrice10GrandTotal10 [4ms]
|
||||
Error Message:
|
||||
Assert.Equal() Failure
|
||||
Expected: 10
|
||||
Actual: 0
|
||||
|
||||
Test Run Failed.
|
||||
Total tests: 4
|
||||
Passed: 3
|
||||
Failed: 1
|
||||
Total time: 1.0320 Seconds
|
||||
```
|
||||
|
||||
Replace the hard-coded value with real processing. First, see if you have any such capability in your interface that would enable it to calculate order totals. Nope, no such thing. So far, you have declared only three capabilities in your interface:
|
||||
|
||||
1. `int NoOfItems();`
|
||||
2. `int AddItem(Hashtable item);`
|
||||
3. `int RemoveItem(Hashtable item);`
|
||||
|
||||
|
||||
|
||||
None of those indicates any ability to calculate totals. You need to declare a new capability:
|
||||
|
||||
|
||||
```
|
||||
`double CalculateGrandTotal();`
|
||||
```
|
||||
|
||||
This new capability should enable your `shoppingAPI` to calculate the total amount by traversing the collection of items it finds in the shopping basket and adding up the item prices.
|
||||
|
||||
Flip over to your tests and change the fifth test:
|
||||
|
||||
|
||||
```
|
||||
[Fact]
|
||||
public void Add1ItemPrice10GrandTotal10() {
|
||||
var expectedGrandTotal = 10.00;
|
||||
Hashtable item = [new][4] Hashtable();
|
||||
item.Add("00000001", 10.00);
|
||||
shoppingAPI.AddItem(item);
|
||||
var actualGrandTotal = shoppingAPI.CalculateGrandTotal();
|
||||
Assert.Equal(expectedGrandTotal, actualGrandTotal);
|
||||
}
|
||||
```
|
||||
|
||||
This test declares your expectation that if you add an item priced at $10 and then call the `CalculateGrandTotal()` method on the shopping API, it will return a grand total of $10. Which is a perfectly reasonable expectation since that's how the API should calculate.
|
||||
|
||||
How do you implement this capability? As always, fake it first. Flip over to the `ShippingAPI` class and implement the `CalculateGrandTotal()` method, as declared in the interface:
|
||||
|
||||
|
||||
```
|
||||
public double CalculateGrandTotal() {
|
||||
return 0.00;
|
||||
}
|
||||
```
|
||||
|
||||
You're hard-coding the return value as 0.00, just to see if the test (your first customer) will be able to run it and whether it will fail. Indeed, it does run fine and fails, so now you must implement processing logic to calculate the grand total of the items in the shopping basket properly:
|
||||
|
||||
|
||||
```
|
||||
public double CalculateGrandTotal() {
|
||||
double grandTotal = 0.00;
|
||||
foreach(var product in basket) {
|
||||
Hashtable item = product as Hashtable;
|
||||
foreach(var value in item.Values) {
|
||||
grandTotal += Double.Parse(value.ToString());
|
||||
}
|
||||
}
|
||||
return grandTotal;
|
||||
}
|
||||
```
|
||||
|
||||
Run the system. All five tests succeed!
|
||||
|
||||
### From One to Many
|
||||
|
||||
Time for another iteration. Now that you have built the system by iterating to handle the **Z**ero, **O**ne (both very simple and a bit more elaborate scenarios), and **B**oundary scenarios (no negative number of items in the basket), you must handle a bit more elaborate scenario for **M**any.
|
||||
|
||||
A quick note: as we keep iterating and returning back to the concerns related to **O**ne, **M**any, and **B**oundaries (we are refining our implementation), some readers may expect that we should also rework the **I**nterface. As we will see later on, our interface is already fully fleshed out, and we see no need to add more capabilities at this point. Keep in mind that interfaces should be kept lean and simple; there is not much advantage in proliferating interfaces, as that only adds more noise to the signal. Here, we are following the principle of Occam's Razor, which states that entities should not multiply without a very good reason. For now, we are pretty much done with describing the expected capabilities of our API. We're now rolling up our sleeves and refining the implementation.
|
||||
|
||||
The previous iteration enabled the system to handle more than one item placed in the basket. Now, enable the system to calculate the grand total for more than one item in the basket. First things first; write the executable expectation:
|
||||
|
||||
|
||||
```
|
||||
[Fact]
|
||||
public void Add2ItemsGrandTotal30() {
|
||||
var expectedGrandTotal = 30.00;
|
||||
var actualGrandTotal = 0.00;
|
||||
Assert.Equal(expectedGrandTotal, actualGrandTotal);
|
||||
}
|
||||
```
|
||||
|
||||
You "cheat" by hard-coding all values first and then do your best to make sure the expectation fails.
|
||||
|
||||
And it does, so now is the time to make it pass. Modify your expectation by adding two items to the basket and then running the `CalculateGrandTotal()` method:
|
||||
|
||||
|
||||
```
|
||||
[Fact]
|
||||
public void Add2ItemsGrandTotal30() {
|
||||
var expectedGrandTotal = 30.00;
|
||||
Hashtable item = [new][4] Hashtable();
|
||||
item.Add("00000001", 10.00);
|
||||
shoppingAPI.AddItem(item);
|
||||
Hashtable item2 = [new][4] Hashtable();
|
||||
item2.Add("00000002", 20.00);
|
||||
shoppingAPI.AddItem(item2);
|
||||
var actualGrandTotal = shoppingAPI.CalculateGrandTotal();
|
||||
Assert.Equal(expectedGrandTotal, actualGrandTotal);
|
||||
}
|
||||
```
|
||||
|
||||
And it passes. You now have six microtests pass successfuly; the system is back to steady-state!
|
||||
|
||||
### Setting expectations
|
||||
|
||||
As a conscientious engineer, you want to make sure that the expected acrobatics when users add items to the basket and then remove some items from the basket always calculate the correct grand total. Here comes the new expectation:
|
||||
|
||||
|
||||
```
|
||||
[Fact]
|
||||
public void Add2ItemsRemoveFirstItemGrandTotal200() {
|
||||
var expectedGrandTotal = 200.00;
|
||||
var actualGrandTotal = 0.00;
|
||||
Assert.Equal(expectedGrandTotal, actualGrandTotal);
|
||||
}
|
||||
```
|
||||
|
||||
This says that when someone adds two items to the basket and then removes the first item, the expected grand total is $200.00. The hard-coded behavior fails, and now you can elaborate with more specific confirmation examples and running the code:
|
||||
|
||||
|
||||
```
|
||||
[Fact]
|
||||
public void Add2ItemsRemoveFirstItemGrandTotal200() {
|
||||
var expectedGrandTotal = 200.00;
|
||||
Hashtable item = [new][4] Hashtable();
|
||||
item.Add("00000001", 100.00);
|
||||
shoppingAPI.AddItem(item);
|
||||
Hashtable item2 = [new][4] Hashtable();
|
||||
item2.Add("00000002", 200.00);
|
||||
shoppingAPI.AddItem(item2);
|
||||
shoppingAPI.RemoveItem(item);
|
||||
var actualGrandTotal = shoppingAPI.CalculateGrandTotal();
|
||||
Assert.Equal(expectedGrandTotal, actualGrandTotal);
|
||||
}
|
||||
```
|
||||
|
||||
Your confirmation example, coded as the expectation, adds the first item (ID "00000001" with item price $100.00) and then adds the second item (ID "00000002" with item price $200.00). You then remove the first item from the basket, calculate the grand total, and assert if it is equal to the expected value.
|
||||
|
||||
When this executable expectation runs, the system meets the expectation by correctly calculating the grand total. You now have seven tests passing! The system is working; nothing is broken!
|
||||
|
||||
|
||||
```
|
||||
Test Run Successful.
|
||||
Total tests: 7
|
||||
Passed: 7
|
||||
Total time: 0.9544 Seconds
|
||||
```
|
||||
|
||||
### More to come
|
||||
|
||||
You're up to **ZOMBI** now, so in the next article, I'll cover **E**. Until then, try your hand at some tests of your own!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/21/2/boundaries-interfaces
|
||||
|
||||
作者:[Alex Bunardzic][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/alex-bunardzic
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/career_journey_road_gps_path_map_520.png?itok=PpL6jJgY (Looking at a map for career journey)
|
||||
[2]: https://opensource.com/article/21/1/zombies-zero
|
||||
[3]: https://opensource.com/article/21/1/zombies-2-one-many
|
||||
[4]: http://www.google.com/search?q=new+msdn.microsoft.com
|
||||
[5]: https://opensource.com/sites/default/files/uploads/error_0.png (Error)
|
||||
[6]: https://creativecommons.org/licenses/by-sa/4.0/
|
@ -0,0 +1,190 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Improve your productivity with this Linux automation tool)
|
||||
[#]: via: (https://opensource.com/article/21/2/linux-autokey)
|
||||
[#]: author: (Matt Bargenquast https://opensource.com/users/mbargenquast)
|
||||
|
||||
Improve your productivity with this Linux automation tool
|
||||
======
|
||||
Configure your keyboard to correct common typos, enter frequently used
|
||||
phrases, and more with AutoKey.
|
||||
![Linux keys on the keyboard for a desktop computer][1]
|
||||
|
||||
[AutoKey][2] is an open source Linux desktop automation tool that, once it's part of your workflow, you'll wonder how you ever managed without. It can be a transformative tool to improve your productivity or simply a way to reduce the physical stress associated with typing.
|
||||
|
||||
This article will look at how to install and start using AutoKey, cover some simple recipes you can immediately use in your workflow, and explore some of the advanced features that AutoKey power users may find attractive.
|
||||
|
||||
### Install and set up AutoKey
|
||||
|
||||
AutoKey is available as a software package on many Linux distributions. The project's [installation guide][3] contains directions for many platforms, including building from source. This article uses Fedora as the operating platform.
|
||||
|
||||
AutoKey comes in two variants: autokey-gtk, designed for [GTK][4]-based environments such as GNOME, and autokey-qt, which is [QT][5]-based.
|
||||
|
||||
You can install either variant from the command line:
|
||||
|
||||
|
||||
```
|
||||
`sudo dnf install autokey-gtk`
|
||||
```
|
||||
|
||||
Once it's installed, run it by using `autokey-gtk` (or `autokey-qt`).
|
||||
|
||||
### Explore the interface
|
||||
|
||||
Before you set AutoKey to run in the background and automatically perform actions, you will first want to configure it. Bring up the configuration user interface (UI):
|
||||
|
||||
|
||||
```
|
||||
`autokey-gtk -c`
|
||||
```
|
||||
|
||||
AutoKey comes preconfigured with some examples. You may wish to leave them while you're getting familiar with the UI, but you can delete them if you wish.
|
||||
|
||||
![AutoKey UI][6]
|
||||
|
||||
(Matt Bargenquast, [CC BY-SA 4.0][7])
|
||||
|
||||
The left pane contains a folder-based hierarchy of phrases and scripts. _Phrases_ are text that you want AutoKey to enter on your behalf. _Scripts_ are dynamic, programmatic equivalents that can be written using Python and achieve basically the same result of making the keyboard send keystrokes to an active window.
|
||||
|
||||
The right pane is where the phrases and scripts are built and configured.
|
||||
|
||||
Once you're happy with your configuration, you'll probably want to run AutoKey automatically when you log in so that you don't have to start it up every time. You can configure this in the **Preferences** menu (**Edit -> Preferences**) by selecting **Automatically start AutoKey at login**.
|
||||
|
||||
![Automatically start AutoKey at login][8]
|
||||
|
||||
(Matt Bargenquast, [CC BY-SA 4.0][7])
|
||||
|
||||
### Correct common typos with AutoKey
|
||||
|
||||
Fixing common typos is an easy problem for AutoKey to fix. For example, I consistently type "gerp" instead of "grep." Here's how to configure AutoKey to fix these types of problems for you.
|
||||
|
||||
Create a new subfolder where you can group all your "typo correction" configurations. Select **My Phrases** in the left pane, then **File -> New -> Subfolder**. Name the subfolder **Typos**.
|
||||
|
||||
Create a new phrase in **File -> New -> Phrase**, and call it "grep."
|
||||
|
||||
Configure AutoKey to insert the correct word by highlighting the phrase "grep" then entering "grep" in the **Enter phrase contents** section (replacing the default "Enter phrase contents" text).
|
||||
|
||||
Next, set up how AutoKey triggers this phrase by defining an Abbreviation. Click the **Set** button next to **Abbreviations** at the bottom of the UI.
|
||||
|
||||
In the dialog box that pops up, click the **Add** button and add "gerp" as a new abbreviation. Leave **Remove typed abbreviation** checked; this is what instructs AutoKey to replace any typed occurrence of the word "gerp" with "grep." Leave **Trigger when typed as part of a word** unchecked so that if you type a word containing "gerp" (such as "fingerprint"), it _won't_ attempt to turn that into "fingreprint." It will work only when "gerp" is typed as an isolated word.
|
||||
|
||||
![Set abbreviation in AutoKey][9]
|
||||
|
||||
(Matt Bargenquast, [CC BY-SA 4.0][7])
|
||||
|
||||
### Restrict corrections to specific applications
|
||||
|
||||
You may want a correction to apply only when you make the typo in certain applications (such as a terminal window). You can configure this by setting a Window Filter. Click the **Set** button to define one.
|
||||
|
||||
The easiest way to set a Window Filter is to let AutoKey detect the window type for you:
|
||||
|
||||
1. Start a new terminal window.
|
||||
2. Back in AutoKey, click the **Detect Window Properties** button.
|
||||
3. Click on the terminal window.
|
||||
|
||||
|
||||
|
||||
This will auto-populate the Window Filter, likely with a Window class value of `gnome-terminal-server.Gnome-terminal`. This is sufficient, so click **OK**.
|
||||
|
||||
![AutoKey Window Filter][10]
|
||||
|
||||
(Matt Bargenquast, [CC BY-SA 4.0][7])
|
||||
|
||||
### Save and test
|
||||
|
||||
Once you're satisfied with your new configuration, make sure to save it. Click **File** and choose **Save** to make the change active.
|
||||
|
||||
Now for the grand test! In your terminal window, type "gerp" followed by a space, and it should automatically correct to "grep." To validate the Window Filter is working, try typing the word "gerp" in a browser URL bar or some other application. It should not change.
|
||||
|
||||
You may be thinking that this problem could have been solved just as easily with a [shell alias][11], and I'd totally agree! Unlike aliases, which are command-line oriented, AutoKey can correct mistakes regardless of what application you're using.
|
||||
|
||||
For example, another common typo I make is "openshfit" instead of "openshift," which I type into browsers, integrated development environments, and terminals. Aliases can't quite help with this problem, whereas AutoKey can correct it in any occasion.
|
||||
|
||||
### Type frequently used phrases with AutoKey
|
||||
|
||||
There are numerous other ways you can invoke AutoKey's phrases to help you. For example, as a site reliability engineer (SRE) working on OpenShift, I frequently type Kubernetes namespace names on the command line:
|
||||
|
||||
|
||||
```
|
||||
`oc get pods -n openshift-managed-upgrade-operator`
|
||||
```
|
||||
|
||||
These namespaces are static, so they are ideal phrases that AutoKey can insert for me when typing ad-hoc commands.
|
||||
|
||||
For this, I created a phrase subfolder named **Namespaces** and added a phrase entry for each namespace I type frequently.
|
||||
|
||||
### Assign hotkeys
|
||||
|
||||
Next, and most crucially, I assign the subfolder a **hotkey**. Whenever I press that hotkey, it opens a menu where I can select (either with **Arrow key**+**Enter** or using a number) the phrase I want to insert. This cuts down on the number of keystrokes I need to enter those commands to just a few keystrokes.
|
||||
|
||||
AutoKey's pre-configured examples in the **My Phrases** folder are configured with a **Ctrl**+**F7** hotkey. If you kept the examples in AutoKey's default configuration, try it out. You should see a menu of all the phrases available there. Select the item you want with the number or arrow keys.
|
||||
|
||||
### Advanced AutoKeying
|
||||
|
||||
AutoKey's [scripting engine][12] allows users to run Python scripts that can be invoked through the same abbreviation and hotkey system. These scripts can do things like switching windows, sending keystrokes, or performing mouse clicks through supporting API functions.
|
||||
|
||||
AutoKey users have embraced this feature by publishing custom scripts for others to adopt. For example, the [NumpadIME script][13] transforms a numeric keyboard into an old cellphone-style text entry method, and [Emojis-AutoKey][14] makes it easy to insert emojis by converting phrases such as `:smile:` into their emoji equivalent.
|
||||
|
||||
Here's a small script I set up that enters Tmux's copy mode to copy the first word from the preceding line into the paste buffer:
|
||||
|
||||
|
||||
```
|
||||
from time import sleep
|
||||
|
||||
# Send the tmux command prefix (changed from b to s)
|
||||
keyboard.send_keys("<ctrl>+s")
|
||||
# Enter copy mode
|
||||
keyboard.send_key("[")
|
||||
sleep(0.01)
|
||||
# Move cursor up one line
|
||||
keyboard.send_keys("k")
|
||||
sleep(0.01)
|
||||
# Move cursor to start of line
|
||||
keyboard.send_keys("0")
|
||||
sleep(0.01)
|
||||
# Start mark
|
||||
keyboard.send_keys(" ")
|
||||
sleep(0.01)
|
||||
# Move cursor to end of word
|
||||
keyboard.send_keys("e")
|
||||
sleep(0.01)
|
||||
# Add to copy buffer
|
||||
keyboard.send_keys("<ctrl>+m")
|
||||
```
|
||||
|
||||
The sleeps are there because occasionally Tmux can't keep up with how fast AutoKey sends the keystrokes, and they have a negligible effect on the overall execution time.
|
||||
|
||||
### Automate with AutoKey
|
||||
|
||||
I hope you've enjoyed this excursion into keyboard automation with AutoKey and it gives you some bright ideas about how it can improve your workflow. If you're using AutoKey in a helpful or novel way, be sure to share it in the comments below.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/21/2/linux-autokey
|
||||
|
||||
作者:[Matt Bargenquast][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/mbargenquast
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/linux_keyboard_desktop.png?itok=I2nGw78_ (Linux keys on the keyboard for a desktop computer)
|
||||
[2]: https://github.com/autokey/autokey
|
||||
[3]: https://github.com/autokey/autokey/wiki/Installing
|
||||
[4]: https://www.gtk.org/
|
||||
[5]: https://www.qt.io/
|
||||
[6]: https://opensource.com/sites/default/files/uploads/autokey-defaults.png (AutoKey UI)
|
||||
[7]: https://creativecommons.org/licenses/by-sa/4.0/
|
||||
[8]: https://opensource.com/sites/default/files/uploads/startautokey.png (Automatically start AutoKey at login)
|
||||
[9]: https://opensource.com/sites/default/files/uploads/autokey-set_abbreviation.png (Set abbreviation in AutoKey)
|
||||
[10]: https://opensource.com/sites/default/files/uploads/autokey-window_filter.png (AutoKey Window Filter)
|
||||
[11]: https://opensource.com/article/19/7/bash-aliases
|
||||
[12]: https://autokey.github.io/index.html
|
||||
[13]: https://github.com/luziferius/autokey_scripts
|
||||
[14]: https://github.com/AlienKevin/Emojis-AutoKey
|
@ -0,0 +1,253 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (5 Tweaks to Customize the Look of Your Linux Terminal)
|
||||
[#]: via: (https://itsfoss.com/customize-linux-terminal/)
|
||||
[#]: author: (Ankush Das https://itsfoss.com/author/ankush/)
|
||||
|
||||
5 Tweaks to Customize the Look of Your Linux Terminal
|
||||
======
|
||||
|
||||
The terminal emulator or simply the terminal is an integral part of any Linux distribution.
|
||||
|
||||
When you change the theme of your distribution, often the terminal also gets a makeover automatically. But that doesn’t mean you cannot customize the terminal further.
|
||||
|
||||
In fact, many It’s FOSS readers have asked us how come the terminal in our screenshots or videos look so cool, what fonts do we use, etc.
|
||||
|
||||
To answer this frequent question, I’ll show you some simple and some complex tweaks to change the appearance of the terminal. You can compare the visual difference in the image below:
|
||||
|
||||
![][1]
|
||||
|
||||
### Customizing Linux Terminal
|
||||
|
||||
_This tutorial utilizes a GNOME terminal on Pop!_OS to customize and tweak the look of the terminal. But, most of the advice should be applicable to other terminals as well._
|
||||
|
||||
For most of the elements like color, transparency, and fonts, you can utilize the GUI to tweak it without requiring to enter any special commands.
|
||||
|
||||
Open your terminal. In the top right corner, look for the hamburger menu. In here, click on “**Preferences**” as shown in the screenshot below:
|
||||
|
||||
![][2]
|
||||
|
||||
This is where you’ll find all the settings to change the appearance of the terminal.
|
||||
|
||||
#### Tip 0: Use separate terminal profiles for your customization
|
||||
|
||||
I would advise you to create a new profile for your customization. Why? Because this way, your changes won’t impact the main terminal profile. Suppose you make some weird change and cannot recall the default value? Profiles help separate the customization.
|
||||
|
||||
As you can see, Abhishek has separate profiles for taking screenshots and making videos.
|
||||
|
||||
![Terminal Profiles][3]
|
||||
|
||||
You can easily change the terminal profiles and open a new terminal window with the new profile.
|
||||
|
||||
![Change Terminal Profile][4]
|
||||
|
||||
That was the suggestion I wanted to put forward. Now, let’s see those tweaks.
|
||||
|
||||
#### Tip 1: Use a dark/light terminal theme
|
||||
|
||||
You may change the system theme and the terminal theme gets changed. Apart from that, you may switch between the dark theme or light theme, if you do not want to change the system theme.
|
||||
|
||||
Once you head in to the preferences, you will notice the general options to change the theme and other settings.
|
||||
|
||||
![][5]
|
||||
|
||||
#### Tip 2: Change the font and size
|
||||
|
||||
Select the profile that you want to customize. Now you’ll get the option to customize the text appearance, font size, font style, spacing, cursor shape, and toggle the terminal bell sound as well.
|
||||
|
||||
For the fonts, you can only change to what’s available on your system. If you want something different, download and install the font on your Linux system first.
|
||||
|
||||
One more thing! Use monospaced fonts otherwise fonts might overlap and the text may not be clearly readable. If you want suggestions, go with [Share Tech Mono][6] (open source) or [Larabiefont][7] (not open source).
|
||||
|
||||
Under the Text tab, select Custom font and then change the font and its size (if required).
|
||||
|
||||
![][8]
|
||||
|
||||
#### Tip 3: Change the color pallet and transparency
|
||||
|
||||
Apart from the text and spacing, you can access the “Colors” tab and change the color of the text and background of your terminal. You can also adjust the transparency to make it look even cool.
|
||||
|
||||
As you can notice, you can change the color palette from a set of pre-configured options or tweak it yourself.
|
||||
|
||||
![][9]
|
||||
|
||||
If you want to enable transparency just like I did, you click on “**Use transparent background**” option.
|
||||
|
||||
You can also choose to use colors from your system theme, if you want a similar color setting with your theme.
|
||||
|
||||
![][10]
|
||||
|
||||
#### Tip 4: Tweaking the bash prompt variables
|
||||
|
||||
Usually, you will see your username along with the hostname (your distribution) as the bash prompt when launching the terminal without any changes.
|
||||
|
||||
For instance, it would be “ankushdas**@**pop-os**:~$**” in my case. However, I [permanently changed the hostname][11] to “**itsfoss**“, so now it looks like:
|
||||
|
||||
![][12]
|
||||
|
||||
To change the hostname, you can type in:
|
||||
|
||||
```
|
||||
hostname CUSTOM_NAME
|
||||
```
|
||||
|
||||
However, this will be applicable only for the current sessions. So, when you restart, it will revert to the default. To permanently change the hostname, you need to type in:
|
||||
|
||||
```
|
||||
sudo hostnamectl set-hostname CUSTOM_NAME
|
||||
```
|
||||
|
||||
Similarly, you can also change your username, but it requires some additional configuration that includes killing all the current processes associated with the active username, so we’ll avoid it to change the look/feel of the terminal.
|
||||
|
||||
#### Tip 5: NOT RECOMMENDED: Changing the font and color of the bash prompt (for advanced users)
|
||||
|
||||
However, you can tweak the font and color of the bash prompt (**[[email protected]][13]:~$**) using commands.
|
||||
|
||||
You will need to utilize the **PS1** environment variable which controls what is being displayed as the prompt. You can learn more about it in the [man page][14].
|
||||
|
||||
For instance, when you type in:
|
||||
|
||||
```
|
||||
echo $PS1
|
||||
```
|
||||
|
||||
The output in my case is:
|
||||
|
||||
```
|
||||
\[\e]0;\[email protected]\h: \w\a\]${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\[email protected]\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$
|
||||
```
|
||||
|
||||
We need to focus on the first part of the output:
|
||||
|
||||
```
|
||||
\[\e]0;\[email protected]\h: \w\a\]$
|
||||
```
|
||||
|
||||
Here, you need to know the following:
|
||||
|
||||
* **\e** is a special character that denotes the start of a color sequence
|
||||
* **\u** indicates the username followed by the @ symbol
|
||||
* **\h** denotes the hostname of the system
|
||||
* **\w** denotes the base directory
|
||||
* **\a** indicates the active directory
|
||||
* **$** indicates non-root user
|
||||
|
||||
|
||||
|
||||
The output in your case can be different, but the variables will be the same, so you need to play with the commands mentioned below depending on your output.
|
||||
|
||||
Before you do that, keep these in mind:
|
||||
|
||||
* Codes for text format: **0** for normal text, **1** for bold, **3** for italic and **4** for underline text
|
||||
* Color range for background colors: **40-47**
|
||||
* Color range for text color: **30-37**
|
||||
|
||||
|
||||
|
||||
You just need to type in the following to change the color and font:
|
||||
|
||||
```
|
||||
PS1="\e[41;3;32m[\[email protected]\h:\w\a\$]"
|
||||
```
|
||||
|
||||
This is how your bash prompt will look like after typing the command:
|
||||
|
||||
![][15]
|
||||
|
||||
If you notice the command properly, as mentioned above, \e helps us assign a color sequence.
|
||||
|
||||
In the command above, I’ve assigned a **background color first**, then the **text style**, and then the **font color** followed by “**m**“.
|
||||
|
||||
Here, “**m**” indicates the end of the color sequence.
|
||||
|
||||
So, all you have to do is, play around with this part:
|
||||
|
||||
```
|
||||
41;3;32
|
||||
```
|
||||
|
||||
Rest of the command should remain the same, you just need to assign different numbers to change the background color, text style, and text color.
|
||||
|
||||
Do note that this is in no particular order, you can assign the text style first, background color next, and the text color at the end as “**3;41;32**“, where the command becomes:
|
||||
|
||||
```
|
||||
PS1="\e[3;41;32m[\[email protected]\h:\w\a\$]"
|
||||
```
|
||||
|
||||
![][16]
|
||||
|
||||
As you can notice, the color customization is the same no matter the order. So, just keep in mind the codes for customization and play around with it till you’re sure you want this as a permanent change.
|
||||
|
||||
The above command that I mentioned temporarily customizes the bash prompt for the current session. If you close the session, you will lose the customization.
|
||||
|
||||
So, to make this a permanent change, you need to add it to **.bashrc** file (this is a configuration file that loads up every time you load up a session).
|
||||
|
||||
![][17]
|
||||
|
||||
You can access the file by simply typing:
|
||||
|
||||
```
|
||||
nano ~/.bashrc
|
||||
```
|
||||
|
||||
Unless you’re sure what you’re doing, do not change anything. And, just for the sake of restoring the settings back, you should keep a backup of the PS1 environment variable (copy-paste what’s in it by default) to a text file.
|
||||
|
||||
So, even if you need the default font and color, you can again edit the **.bashrc file** and paste the PS1 environment variable.
|
||||
|
||||
#### Bonus Tip: Change the terminal color pallet based on your wallpaper
|
||||
|
||||
If you want to change the background and text color of the terminal but you are not sure which colors to pick, you can use a Python-based tool Pywal. It [automatically changes the color of the terminal based on your wallpaper][18] or the image you provide to it.
|
||||
|
||||
![][19]
|
||||
|
||||
I have written about it in details if you are interested in using this tool.
|
||||
|
||||
**Recommended Read:**
|
||||
|
||||
![][20]
|
||||
|
||||
#### [Automatically Change Color Scheme of Your Linux Terminal Based on Your Wallpaper][18]
|
||||
|
||||
### Wrapping Up
|
||||
|
||||
Of course, it is easy to customize using the GUI while getting a better control of what you can change. But, the need to know the commands is also necessary in case you start [using WSL][21] or access a remote server using SSH, you can customize your experience no matter what.
|
||||
|
||||
How do you customize the Linux terminal? Share your secret ricing recipe with us in the comments.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://itsfoss.com/customize-linux-terminal/
|
||||
|
||||
作者:[Ankush Das][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://itsfoss.com/author/ankush/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2021/02/default-terminal.jpg?resize=773%2C493&ssl=1
|
||||
[2]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2021/01/linux-terminal-preferences.jpg?resize=800%2C350&ssl=1
|
||||
[3]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2021/02/terminal-profiles.jpg?resize=800%2C619&ssl=1
|
||||
[4]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2021/02/change-terminal-profile.jpg?resize=796%2C347&ssl=1
|
||||
[5]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2021/01/terminal-theme.jpg?resize=800%2C363&ssl=1
|
||||
[6]: https://fonts.google.com/specimen/Share+Tech+Mono
|
||||
[7]: https://www.dafont.com/larabie-font.font
|
||||
[8]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2021/01/terminal-customization-1.jpg?resize=800%2C500&ssl=1
|
||||
[9]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2021/01/terminal-color-customization.jpg?resize=759%2C607&ssl=1
|
||||
[10]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2021/01/linux-terminal.jpg?resize=800%2C571&ssl=1
|
||||
[11]: https://itsfoss.com/change-hostname-ubuntu/
|
||||
[12]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2021/01/itsfoss-hostname.jpg?resize=800%2C188&ssl=1
|
||||
[13]: https://itsfoss.com/cdn-cgi/l/email-protection
|
||||
[14]: https://linux.die.net/man/1/bash
|
||||
[15]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2021/01/terminal-bash-prompt-customization.jpg?resize=800%2C190&ssl=1
|
||||
[16]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2021/01/linux-terminal-customization-1s.jpg?resize=800%2C158&ssl=1
|
||||
[17]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2021/01/bashrch-customization-terminal.png?resize=800%2C615&ssl=1
|
||||
[18]: https://itsfoss.com/pywal/
|
||||
[19]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/08/wallpy-2.jpg?resize=800%2C442&ssl=1
|
||||
[20]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/08/pywal-linux.jpg?fit=800%2C450&ssl=1
|
||||
[21]: https://itsfoss.com/install-bash-on-windows/
|
@ -1,70 +0,0 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (stevenzdg988)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (The importance of consistency in your Python code)
|
||||
[#]: via: (https://opensource.com/article/19/12/zen-python-consistency)
|
||||
[#]: author: (Moshe Zadka https://opensource.com/users/moshez)
|
||||
|
||||
Python 代码前后一致的重要性
|
||||
======
|
||||
本部分是有关 Python 之禅的特殊系列,聚焦在第 12,13,14 规范:角色的二义和明确。
|
||||
![两台动画电脑挥舞着手臂打招呼,一台手臂脱落][1]
|
||||
|
||||
设计用户界面的规范是 [准则][2]。它说,当用户执行一个操作时,程序应该做最不会让用户感到惊讶的事情。这和孩子们喜欢一遍又一遍地读同一本书的原因是一样的:没有什么比能够预测并让预测成真更让人欣慰的了。
|
||||
|
||||
在[ABC 语言][3] (Python 的灵感来源)的发展过程中,一个重要的见解是,编程设计是用户界面,需要 UI 设计者使用相同工具来设计。值得庆幸的是,从那以后,越来越多的语言采用了 UI 设计中的可视化和人体工程学概念,即使它们的应用并不严格。
|
||||
|
||||
这就引出了 [Python 之禅][4] 中的三个规范。
|
||||
|
||||
### 当存在多种可能,不要尝试去猜测。
|
||||
|
||||
**1 + "1"**的结果应该是什么? **“11”** 和 **2** 都是猜测。这个表达是 _ambiguous_:没有任何事情可以做,这至少对某些人来说并不令人惊讶。
|
||||
|
||||
一些语言选择猜测。在 JavaScript 中,结果为 **“11”**。在 Perl 中,结果为 ** 2 **。在 C 语言中,结果自然是空字符串。面对歧义,JavaScript,Perl 和 C 都在猜测。
|
||||
|
||||
在 Python 中,这会引发 **TypeError**:不是非静音的错误。捕获 **TypeError** 是非典型的:它通常将终止程序或至少终止当前任务(例如,在大多数Web框架中,它将终止对当前请求的处理)。
|
||||
|
||||
Python 拒绝猜测 **1 + "1"**的含义。程序员被迫以明确的意图编写代码:**1 + int("1")**,即 **2**;或者 **str(1) + "1"**,即 **"11"**;或 **"1"[1:]**,这将是一个空字符串。通过拒绝猜测,Python 使程序更具可预测性。
|
||||
|
||||
### 尽量找一种,最好是唯一一种明显的解决方案。
|
||||
|
||||
断言也会出现偏差。给定一个任务,你能预知要实现该任务的代码吗?当然,不可能完美地预测。毕竟,编程是一项具有创造性的任务。
|
||||
|
||||
但是,不必有意提供多种冗余方式来实现同一目标。从某种意义上说,感觉某些解决方案或许 “更好” 或 “更 Python”。
|
||||
|
||||
对 Python 美学原则的欣赏部分是关于哪种更好的解决方案的代码健壮性讨论是非常棒的。甚至可以持不同观点保持原有编程风格。为使其达到一致,不赞同甚至也是可以的。但在这一切之下,最终,必须有一种变得容易的正确的解决方案。我们希望,通过商定实现目标的最佳方法,最终达成真正的一致。
|
||||
|
||||
### 虽然这并不容易,因为你不是 Python 之父。
|
||||
|
||||
这是一个重要的警告:首先,实现任务的最佳方法通常 _not_ 明显。观念在不断发展。 _Python_ 正在进化。读取文件数据块的最佳方法可能要等到 Python3.8 并且使用 [walrus 运算符][5]。
|
||||
|
||||
读取文件数据块这样常见任务在 Python 已有近 _30 years(30年)_ 的历史中并没有 “唯一的最佳方法”。
|
||||
|
||||
1998年当我从 Python 1.5.2 开始使用 Python 时,没有一种最佳的逐行读取文件的方法。多年来,知道在字典中使用关键字 **.haskey** 是最佳的方法,直到 **in** 操作符出现才发生改变。
|
||||
|
||||
只是要意识到,找到一种(也是唯一一种)实现目标的方法可能需要 30 年的时间来尝试,Python 可以继续寻找这些方法。历史观点认为,为了做一件事 30 年是可以接受的,但对于美国人民来说,当国家已经存在了 200 多年时,常常会感到陌生。
|
||||
|
||||
根据 Python 禅 的这一部分,无论是 Python 的创造者 [Guido van Rossum][6] 这个荷兰人,还是著名的计算机科学家 [Edsger W. Dijkstra][7],都有不同的世界观。一定程度上欧洲人对时间的重视是欣赏它的必要条件。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/19/12/zen-python-consistency
|
||||
|
||||
作者:[Moshe Zadka][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[stevenzdg988](https://github.com/stevenzdg988)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/moshez
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/rh_003499_01_other11x_cc.png?itok=I_kCDYj0 (Two animated computers waving one missing an arm)
|
||||
[2]: https://www.uxpassion.com/blog/the-principle-of-least-surprise/
|
||||
[3]: https://en.wikipedia.org/wiki/ABC_(programming_language)
|
||||
[4]: https://www.python.org/dev/peps/pep-0020/
|
||||
[5]: https://www.python.org/dev/peps/pep-0572/#abstract
|
||||
[6]: https://en.wikipedia.org/wiki/Guido_van_Rossum
|
||||
[7]: http://en.wikipedia.org/wiki/Edsger_W._Dijkstra
|
@ -0,0 +1,69 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (Chao-zhi)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (7 Bash tutorials to enhance your command line skills in 2021)
|
||||
[#]: via: (https://opensource.com/article/21/1/bash)
|
||||
[#]: author: (Jim Hall https://opensource.com/users/jim-hall)
|
||||
|
||||
7 个 Bash 教程,提高你的命令行技能,2021 年版
|
||||
======
|
||||
|
||||
Bash 是大多数 Linux 系统上的默认命令行 shell。所以你为什么不试着学习如何最大限度地利用它呢?
|
||||
|
||||
![Terminal command prompt on orange background][1]
|
||||
|
||||
Bash 是大多数 Linux 系统上的默认命令行 shell。所以你为什么不试着学习如何最大限度地利用它呢?今年,Opensource.com 推荐了许多很棒的文章来帮助您充分利用 Bash shell 的强大功能。以下是一些关于 Bash 阅读次数最多的文章:
|
||||
|
||||
## [在 Linux 终端中通过重定向从任何地方读取和写入数据 ][2]
|
||||
|
||||
输入和输出重定向是任何编程或脚本语言的基础功能。从技术上讲,只要你与电脑互动,它就会自然而然地发生。输入从 stdin( 标准输入,通常是您的键盘或鼠标)读取,输出到 stdout (标准输出,一般是文本或数据流),而错误被发送到 stderr。了解这些数据流的存在,使您能够在使用 Bash 等 shell 时控制信息的去向。Seth Kenlon 分享了这些很棒的技巧,可以让你在不需要大量鼠标移动和按键的情况下从一个地方获取数据。您可能不经常使用重定向,但学习使用它可以为您节省大量不必要的打开文件和复制粘贴数据的时间。
|
||||
|
||||
## [系统管理员 Bash 脚本入门 ][3]
|
||||
|
||||
Bash 是免费的开源软件,所以任何人都可以安装它,不管他们运行的是 Linux、BSD、OpenIndiana、Windows 还是 macOS。Seth Kenlon 帮助您学习如何使用 Bash 的命令和特性,使其成为最强大的 shell 之一。
|
||||
|
||||
## [试试这个针对大型文件系统的 Bash 脚本 ][4]
|
||||
|
||||
您是否曾经想列出一个目录中的所有文件,只显示其中的文件,不包括其他内容?或者只显示目录?如果你有,那么 Nick Clifton 的文章可能正是你正在寻找的。Nick 分享了一个漂亮的 Bash 脚本,它可以列出目录、文件、链接或可执行文件。该脚本使用 **find** 命令进行搜索,然后运行 **ls** 显示详细信息。对于管理大型 Linux 系统的人来说,这是一个漂亮的解决方案。
|
||||
|
||||
## [用 Bash 工具对你的 Linux 系统配置进行快照 ][5]
|
||||
|
||||
您可能想与他人分享您的 Linux 配置,原因有很多。您可能需要帮助排除系统上的一个问题,或者您对自己创建的环境非常自豪,想向其他开源爱好者展示它。Don Watkins 向我们展示了 screenFetch 和 Neofetch 来捕获和分享您的系统配置。
|
||||
|
||||
## [Git 的 6 个好用的 Bash 脚本 ][6]
|
||||
|
||||
Git 已经成为一个无处不在的代码管理系统。了解如何管理 Git 存储库可以简化您的开发体验。Bob Peterson 分享了 6 个 Bash 脚本,它们将使您在使用 Git 存储库时更加轻松。**gitlog** 打印当前 patch 和 主版本的缩写列表。另一种脚本可以显示 patch 的 SHA1 id 或在一组 patch 中搜索字符串。
|
||||
|
||||
## [改进你 Bash 脚本的 5 种方法 ][7]
|
||||
|
||||
系统管理员通常编写各种或长或短的 Bash 脚本,以完成各种任务。Alan Formy-Duval 解释了如何使 Bash 脚本更简单、更健壮、更易于阅读和调试。我们可能会考虑到我们需要使用诸如 Python、C 或 Java 之类的语言来实现更高的功能,但其实也不一定需要。因为 Bash 脚本语言就已经非常强大。要最大限度地发挥它的效用,还有很多东西要学。
|
||||
|
||||
## [我最喜欢的 Bash 技巧 ][8]
|
||||
|
||||
Katie McLaughlin 帮助你提高你的工作效率,用别名和其他快捷方式解决你经常忘记的事情。当你整天与计算机打交道时,找到可重复的命令并标记它们以方便以后使用是非常美妙的。Katie 总结了一些有用的 Bash 特性和帮助命令,可以节省您的时间。
|
||||
|
||||
这些 Bash 小技巧将一个已经很强大的 shell 提升到一个全新的级别。也欢迎分享你自己的建议。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/21/1/bash
|
||||
|
||||
作者:[Jim Hall][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[Chao-zhi](https://github.com/Chao-zhi)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/jim-hall
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/terminal_command_linux_desktop_code.jpg?itok=p5sQ6ODE (Terminal command prompt on orange background)
|
||||
[2]: https://opensource.com/article/20/6/redirection-bash
|
||||
[3]: https://opensource.com/article/20/4/bash-sysadmins-ebook
|
||||
[4]: https://opensource.com/article/20/2/script-large-files
|
||||
[5]: https://opensource.com/article/20/1/screenfetch-neofetch
|
||||
[6]: https://opensource.com/article/20/1/bash-scripts-git
|
||||
[7]: https://opensource.com/article/20/1/improve-bash-scripts
|
||||
[8]: https://opensource.com/article/20/1/bash-scripts-aliases
|
@ -0,0 +1,291 @@
|
||||
[#]: collector: "lujun9972"
|
||||
[#]: translator: "amwps290"
|
||||
[#]: reviewer: " "
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
[#]: subject: "Learn JavaScript by writing a guessing game"
|
||||
[#]: via: "https://opensource.com/article/21/1/learn-javascript"
|
||||
[#]: author: "Mandy Kendall https://opensource.com/users/mkendall"
|
||||
|
||||
通过编写猜数游戏学习 JavaScript
|
||||
======
|
||||
|
||||
通过使用一个简单的游戏来练习一些基本的 JavaScript 概念,迈出创建交互,动态 Web 内容的第一步。
|
||||
|
||||
![Javascript code close-up with neon graphic overlay][1]
|
||||
|
||||
可以肯定地说,没有 [JavaScript][2],大多数现代 web 都将不存在。 它是三种标准 Web 技术(以及 HTML 和 CSS )之一,它使任何人都可以创建许多交互式的动态内容,这是我们在使用万维网时所期望的。 从 [React][3] 这样的框架到 [D3][4] 这样的数据可视化库,很难想象没有它的网络。
|
||||
|
||||
现在有很多东西要学习,开始学习这种流行语言的好方法是编写一个简单的应用程序以熟悉某些概念。 最近,Opensource.com 通讯员写了一篇关于如何通过编写简单的猜谜游戏来学习自己喜欢的语言的文章,因此这是一个很好的起点!
|
||||
|
||||
### 现在开始吧
|
||||
|
||||
JavaScript 有许多种风格,但我将从最基本的开始,通常称为 “ Vanilla JavaScript”。 JavaScript 主要是一种客户端脚本语言,因此它可以在任何标准浏览器中运行,而无需安装任何程序。 您只需要一个代码编辑器([Brackets ][5] 就是一个不错的选择)和一个 Web 浏览器。
|
||||
|
||||
### HTML 用户界面
|
||||
|
||||
JavaScript 在 Web 浏览器中运行,并与其他标准 Web 技术 HTML 和 CSS 交互。 要创建此游戏,您首先需要使用 HTML(超文本标记语言)来创建供玩家使用的简单界面。 如果您不熟悉,HTML 是一种标记语言,用于为 Web 内容提供结构。
|
||||
|
||||
首先,先创建一个 HTML 文件。 该文件应具有`.html `扩展名,以使浏览器知道它是 HTML 文档。 您可以将文件命名为 `guessingGame.html`。
|
||||
|
||||
在此文件中使用一些基本的 HTML 标签来显示游戏的标题,玩法说明,供玩家用来输入和提交其猜测的交互式元素以及用于向玩家提供反馈的占位符:
|
||||
|
||||
|
||||
```
|
||||
<!DOCTYPE>
|
||||
<[html][6]>
|
||||
<[head][7]>
|
||||
<[meta][8] charset="UTF-8" />
|
||||
<[title][9]> JavaScript Guessing Game </[title][9]>
|
||||
</[head][7]>
|
||||
<[body][10]>
|
||||
<[h1][11]>Guess the Number!</[h1][11]>
|
||||
<[p][12]>I am thinking of a number between 1 and 100. Can you guess what it is?</[p][12]>
|
||||
|
||||
<[label][13] for="guess">My Guess</[label][13]>
|
||||
<[input][14] type="number" id="guess">
|
||||
<[input][14] type="submit" id="submitGuess" value="Check My Guess">
|
||||
|
||||
<[p][12] id="feedback"></[p][12]>
|
||||
</[body][10]>
|
||||
</[html][6]>
|
||||
```
|
||||
|
||||
<h1> 和 <p> 元素使浏览器知道在页面上显示什么类型的文本。 标签对 `<h1></h1>` 表示标签(`Guess the Number!`)之间的文本是标题。 后面的一组`<p>` 标签表示带有说明的短文本是一个段落。 此代码块末尾的空 `<p>` 标签用作占位符,用于根据用户的输入提供一些反馈。
|
||||
|
||||
### <script> 标签
|
||||
|
||||
在网页中包含 JavaScript 的方法有很多种,但是对于像这样的简短脚本,可以使用一组 `<script>` 标签并将 JavaScript 直接写在 HTML 文件中。 这些 `<script>` 标签应位于 HTML 文件末尾附近的 `</body>` 标签之前。
|
||||
|
||||
现在,您可以开始在这两个脚本标签之间编写 JavaScript。 最终文件如下所示:
|
||||
|
||||
```javascript
|
||||
<!DOCTYPE>
|
||||
<[html][6]>
|
||||
|
||||
<[head][7]>
|
||||
<[meta][8] charset="UTF-8" />
|
||||
<[title][9]> JavaScript Guessing Game </[title][9]>
|
||||
</[head][7]>
|
||||
|
||||
<[body][10]>
|
||||
<[h1][11]>Guess the Number!</[h1][11]>
|
||||
<[p][12]>I am thinking of a number between 1 and 100. Can you guess what it is?</[p][12]>
|
||||
|
||||
<[form][15]>
|
||||
<[label][13] for="guess">My Guess</[label][13]>
|
||||
<[input][14] type="number" id="guess">
|
||||
<[input][14] type="submit" id="submitGuess" value="Check My Guess">
|
||||
</[form][15]>
|
||||
|
||||
<[p][12] id="feedback"></[p][12]>
|
||||
|
||||
<[script][16]>
|
||||
const randomNumber = Math.floor(Math.random() * 100) + 1
|
||||
console.log('Random Number', randomNumber)
|
||||
|
||||
function checkGuess() {
|
||||
let myGuess = guess.value
|
||||
if (myGuess === randomNumber) {
|
||||
feedback.textContent = "You got it right!"
|
||||
} else if (myGuess > randomNumber) {
|
||||
feedback.textContent = "Your guess was " + myGuess + ". That's too high. Try Again!"
|
||||
} else if (myGuess < randomNumber) {
|
||||
feedback.textContent = "Your guess was " + myGuess + ". That's too low. Try Again!"
|
||||
}
|
||||
}
|
||||
submitGuess.addEventListener('click', checkGuess)
|
||||
</[script][16]>
|
||||
|
||||
</[body][10]>
|
||||
|
||||
</[html][6]>
|
||||
```
|
||||
|
||||
要在浏览器中运行此文件,请双击文件或打开您喜欢的浏览器,点击菜单,然后选择**文件->打开文件**。 (如果使用 Brackets 软件,也可以使用角落处的闪电图标在浏览器中打开文件)。
|
||||
### 生成伪随机数
|
||||
|
||||
猜谜游戏的第一步是为玩家生成一个数字供玩家猜测。 JavaScript 包含几个内置的全局对象,可帮助您编写代码。 要生成随机数,请使用 Math 对象。
|
||||
|
||||
JavaScript中的 [Math][17] 具有处理和数学相关的属性和功能。 您将使用两个数学函数来生成随机数,供您的玩家猜测。
|
||||
|
||||
[Math.random()][18],会将生成一个介于 0 和 1 之间的伪随机数。( Math.random 包含 0 但不包含 1。这意味着该函数可以生成 0 ,永远不会产生 1.)
|
||||
|
||||
对于此游戏,请将随机数设置在 1 到 100 之间以缩小玩家的选择范围。 取刚刚生成的小数,然后乘以 100,以产生一个介于 0 到......甚至不是 100 之间的小数。至此,您将需要其他步骤来解决这个问题。
|
||||
|
||||
现在,您的数字仍然是小数,但您希望它是一个整数。 为此,您可以使用属于 Math 对象的另一个函数 [Math.floor()][19]。 Math.floor() 的目的是返回小于或等于您作为参数指定的数字的最大整数,这意味着它会四舍五入为最接近的整数:
|
||||
|
||||
|
||||
```javascript
|
||||
`Math.floor(Math.random() * 100)`
|
||||
```
|
||||
|
||||
这样您将得到 0 到 99 之间的整数,这不是您想要的范围。 您可以在最后一步修复该问题,即在结果中加 1。 瞧! 现在,您有一个(有点)随机生成的数字,介于 1 到 100 之间:
|
||||
|
||||
|
||||
```javascript
|
||||
`Math.floor(Math.random() * 100) + 1`
|
||||
```
|
||||
|
||||
### 变量
|
||||
|
||||
现在,您需要存储随机生成的数字,以便可以将其与玩家的猜测进行比较。 为此,您可以将其存储到一个 **变量**。
|
||||
|
||||
JavaScript 具有不同类型的变量,您可以选择这些类型,具体取决于您要如何使用该变量。 对于此游戏,请使用 const 和 let 。
|
||||
|
||||
* **let** 用于指示变量在整个程序中可以改变
|
||||
* **const** 用于指示变量不应该被修改.
|
||||
|
||||
const 和 let 还有很多要说的,但现在知道这些就足够了。
|
||||
|
||||
随机数在游戏中仅生成一次,因此您将使用 const 变量来保存该值。 您想给变量起一个清楚地表明要存储什么值的名称,因此将其命名为 `randomNumber`:
|
||||
|
||||
|
||||
```javascript
|
||||
`const randomNumber`
|
||||
```
|
||||
|
||||
有关命名的注意事项:JavaScript 中的变量和函数名称以驼峰形式编写。 如果只有一个单词,则全部以小写形式书写。 如果有多个单词,则第一个单词均为小写,其他任何单词均以大写字母开头,且单词之间没有空格。
|
||||
|
||||
### 打印到控制台
|
||||
|
||||
通常,您不想向任何人显示随机数,但是开发人员可能想知道生成的数字以使用它来帮助调试代码。 使用 JavaScript,您可以使用另一个内置函数 [console.log()][20] 将数字输出到浏览器的控制台。
|
||||
|
||||
大多数浏览器都包含开发人员工具,您可以通过按键盘上的 **F12** 键来打开它们。 从那里,您应该看到一个标签为 **控制台** 的标签。 打印到控制台的所有信息都将显示在此处。 由于到目前为止编写的代码将在浏览器加载后立即运行,因此,如果您查看控制台,您应该会看到刚刚生成的随机数! 万岁!
|
||||
|
||||
![Javascript game with console][21]
|
||||
|
||||
### 函数
|
||||
|
||||
接下来,您需要一种方法来从数字输入字段中获得玩家的猜测,将其与您刚刚生成的随机数进行比较,并向玩家提供反馈,让他们知道他们是否正确猜到了。 为此,编写一个函数。 **函数** 是执行一定任务的代码块。 函数是可以重用的,这意味着如果您需要多次运行相同的代码,则可以调用函数,而不必重写执行任务所需的所有步骤。
|
||||
|
||||
根据您使用的 JavaScript 版本,有许多不同的方法来编写或声明函数。 由于这是该语言的基础入门,因此请使用基本函数语法声明函数。
|
||||
|
||||
以关键字 `function` 开头,然后起一个函数名。 好的做法是使用一个描述该函数的功能的名称。 在这个例子中,您正在检查玩家的猜测的数,因此此函数的名字可以是 `checkGuess`。 在函数名称之后,写上一组括号,然后写上一组花括号。 您将在以下花括号之间编写函数的主体:
|
||||
|
||||
|
||||
```
|
||||
`function checkGuess() {}`
|
||||
```
|
||||
|
||||
### 使用 DOM
|
||||
|
||||
JavaScript 的目的之一是与网页上的 HTML 交互。 它通过文档对象模型(DOM)进行此操作,DOM 是 JavaScript 用于访问和更改网页信息的对象。 现在,您需要从 HTML 中获取数字输入字段中玩家的猜测。 您可以使用分配给 HTML 元素的 `id` 属性(在这种情况下为 `guess`)来做到这一点:
|
||||
|
||||
|
||||
```
|
||||
`<input type="number" id="guess">`
|
||||
```
|
||||
|
||||
JavaScript 可以通过访问玩家输入到数字输入字段中的数来获取其值。 您可以通过引用元素的 ID 并在末尾添加 `.value` 来实现。 这次,使用 `let` 定义的变量来保存用户的猜测值:
|
||||
|
||||
```
|
||||
`let myGuess = guess.value`
|
||||
```
|
||||
|
||||
玩家在数字输入字段中输入的任何数字都将被分配给 `checkGuess` 函数中的 `myGuess` 变量。
|
||||
|
||||
### 条件语句
|
||||
下一步是将玩家的猜测与游戏产生的随机数进行比较。 您还想给玩家反馈,让他们知道他们的猜测是太高,太低还是正确。
|
||||
|
||||
您可以使用一系列条件语句来决定玩家将收到的反馈。 **条件语句** 在运行代码块之前检查是否满足条件。 如果不满足条件,则代码停止,继续检查下一个条件,或者继续执行其余代码,而无需执行条件块中的代码:
|
||||
|
||||
```
|
||||
if (myGuess === randomNumber){
|
||||
feedback.textContent = "You got it right!"
|
||||
}
|
||||
else if(myGuess > randomNumber) {
|
||||
feedback.textContent = "Your guess was " + myGuess + ". That's too high. Try Again!"
|
||||
}
|
||||
else if(myGuess < randomNumber) {
|
||||
feedback.textContent = "Your guess was " + myGuess + ". That's too low. Try Again!"
|
||||
}
|
||||
```
|
||||
|
||||
第一个条件块使用比较运算符 `===` 将玩家的猜测与游戏生成的随机数进行比较。 比较运算符检查右侧的值,将其与左侧的值进行比较,如果匹配则返回布尔值 `true` ,否则返回布尔值 `false`。
|
||||
|
||||
如果数字匹配(猜对了!),为了让玩家知道。 通过将文本添加到具有 id 属性 "feedback" 的 `<p>` 标记中来操作 DOM。 就像上面的 `guess.value` 一样工作,除了不是从 DOM 获取信息,而是更改其中的信息。 `<p>` 元素没有像 `<input>` 元素那样的值,而是具有文本,因此请使用 `.textContent` 访问元素并设置要显示的文本:
|
||||
|
||||
|
||||
```
|
||||
`feedback.textContent = "You got it right!"`
|
||||
```
|
||||
|
||||
当然,玩家很有可能在第一次尝试时就猜错了,因此,如果 `myGuess` 和 `randomNumber` 不匹配,请给玩家一个线索,以帮助他们缩小猜测范围。 如果第一个条件失败,则代码将跳过该 if 语句中的代码块,并检查下一个条件是否为 true。 这使您进入 `else if` 块:
|
||||
|
||||
```
|
||||
else if(myGuess > randomNumber) {
|
||||
feedback.textContent = "Your guess was " + myGuess + ". That's too high. Try Again!"
|
||||
}
|
||||
```
|
||||
|
||||
如果您将其作为句子阅读,则可能是这样的:“如果玩家的猜测等于随机数,请让他们知道他们猜对了。否则,请检查玩家的猜测是否大于 `randomNumber`,如果是,则显示玩家的猜测并告诉他们太高了。”
|
||||
|
||||
最后一种可能性是玩家的猜测低于随机数。 要检查这一点,再添加一个 `else if` 块:
|
||||
|
||||
```
|
||||
else if(myGuess < randomNumber) {
|
||||
feedback.textContent = "Your guess was " + myGuess + ". That's too low. Try Again!"
|
||||
}
|
||||
```
|
||||
|
||||
### 用户事件和事件监听器
|
||||
|
||||
如果您看上面的代码,则会看到某些代码在页面加载时自动运行,但有些则不会。 您想在玩游戏之前生成随机数,但是您不想在玩家将数字输入到数字输入字段并准备检查它之前检查其猜测。
|
||||
|
||||
生成随机数并将其打印到控制台的代码不在函数的范围内,因此它将在浏览器加载脚本时自动运行。 但是,要使函数内部的代码运行,您必须对其进行调用。
|
||||
|
||||
调用函数有几种方法。 在此,您希望该函数在用户单击“检查我的猜测”按钮时运行。 单击按钮将创建一个用户事件,然后 JavaScript 可以 “监听” 这个事件,以便知道何时需要运行函数。
|
||||
|
||||
代码的最后一行将事件侦听器添加到按钮上,以在单击按钮时调用函数。 当它“听到”该事件时,它将运行分配给事件侦听器的函数:
|
||||
|
||||
|
||||
```
|
||||
`submitGuess.addEventListener('click', checkGuess)`
|
||||
```
|
||||
|
||||
就像访问 DOM 元素的其他实例一样,您可以使用按钮的 ID 告诉 JavaScript 与哪个元素进行交互。 然后,您可以使用内置的 `addEventListener` 函数来告诉 JavaScript 要监听的事件。
|
||||
|
||||
您已经看到了带有参数的函数,但花点时间看一下它是如何工作的。 参数是函数执行其任务所需的信息。 并非所有函数都需要参数,但是 `addEventListener` 函数需要两个参数。 它采用的第一个参数是将为其侦听的用户事件的名称。 用户可以通过多种方式与 DOM 交互,例如键入,移动鼠标,键盘上的 TAB 键和粘贴文本。 在这种情况下,您正在监听的用户事件是单击按钮,因此第一个参数将是 ` click`。
|
||||
|
||||
`addEventListener`的第二个所需的信息是用户单击按钮时要运行的函数的名称。 这里我们需要 `checkGuess` 函数。
|
||||
|
||||
现在,当玩家按下“检查我的猜测”按钮时,`checkGuess` 函数将获得他们在数字输入字段中输入的值,将其与随机数进行比较,并在浏览器中显示反馈,以使玩家知道他们猜的怎么样。 太棒了! 您的游戏已准备就绪。
|
||||
|
||||
### 学习 JavaScript 以获取乐趣和收益
|
||||
一点点的 Vanilla JavaScript 只是这个庞大的生态系统所提供功能的一小部分。 这是一种值得花时间投入学习的语言,我鼓励您继续挖掘并学习更多。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/21/1/learn-javascript
|
||||
|
||||
作者:[Mandy Kendall][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[amwps290](https://github.com/amwps290)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/mkendall
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/code_javascript.jpg?itok=60evKmGl "Javascript code close-up with neon graphic overlay"
|
||||
[2]: https://opensource.com/tags/javascript
|
||||
[3]: https://opensource.com/article/20/11/reactjs-tutorial
|
||||
[4]: https://opensource.com/article/18/9/open-source-javascript-chart-libraries
|
||||
[5]: https://opensource.com/article/20/12/brackets
|
||||
[6]: http://december.com/html/4/element/html.html
|
||||
[7]: http://december.com/html/4/element/head.html
|
||||
[8]: http://december.com/html/4/element/meta.html
|
||||
[9]: http://december.com/html/4/element/title.html
|
||||
[10]: http://december.com/html/4/element/body.html
|
||||
[11]: http://december.com/html/4/element/h1.html
|
||||
[12]: http://december.com/html/4/element/p.html
|
||||
[13]: http://december.com/html/4/element/label.html
|
||||
[14]: http://december.com/html/4/element/input.html
|
||||
[15]: http://december.com/html/4/element/form.html
|
||||
[16]: http://december.com/html/4/element/script.html
|
||||
[17]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math
|
||||
[18]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random
|
||||
[19]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/floor
|
||||
[20]: https://developer.mozilla.org/en-US/docs/Web/API/Console/log
|
||||
[21]: https://opensource.com/sites/default/files/javascript-game-with-console.png "Javascript game with console"
|
@ -7,25 +7,25 @@
|
||||
[#]: via: (https://opensource.com/article/21/1/gimp-scripting)
|
||||
[#]: author: (Cristiano L. Fontana https://opensource.com/users/cristianofontana)
|
||||
|
||||
Write GIMP scripts to make image processing faster
|
||||
编写 GIMP 脚本使图像处理更快
|
||||
======
|
||||
Learn GIMP's scripting language Script-Fu by adding an effect to a batch
|
||||
of images.
|
||||
通过向一批图像添加效果来学习 GIMP 的脚本语言 Script-Fu。
|
||||
|
||||
![Painting art on a computer screen][1]
|
||||
|
||||
Some time ago, I wanted to give a blackboard-style look to a typeset equation. I started playing around with the [GNU Image Manipulation Program (GIMP)][2] and was satisfied with the result. The problem was that I had to perform several actions on the image, I wanted to use this style again, and I did not want to repeat the steps for all the images. Besides, I was sure that I would forget them in no time.
|
||||
前一段时间,我想给方程图片加一个黑板式的外观。 我开始使用 [GNU Image Manipulation Program (GIMP)][2] 来处理,并对结果感到满意。 问题是我必须对图像执行几个操作,当我想再次使用此样式,不想对所有图像重复这些步骤。 此外,我确信我会很快忘记他们。
|
||||
|
||||
![Fourier transform equations][3]
|
||||
|
||||
Fourier transform equations (Cristiano Fontana, [CC BY-SA 4.0][4])
|
||||
傅立叶变换方程式(Cristiano Fontana,[CC BY-SA 4.0] [4])
|
||||
|
||||
GIMP is a great open source image editor. Although I have been using it for years, I had never investigated its batch-processing abilities nor its [Script-Fu menu][5]. This was the perfect chance to explore them.
|
||||
GIMP 是一个很棒的开源图像编辑器。 尽管我已经使用了多年,但从未研究过其批处理功能或 [Script-Fu][5] 菜单。 这是探索它们的绝好机会。
|
||||
|
||||
### What is Script-Fu?
|
||||
### 什么是 Script-Fu?
|
||||
|
||||
[Script-Fu][6] is the scripting language built into GIMP. It is an implementation of the [Scheme][7] programming language. If you have never used Scheme, give it a try, as it can be very useful. I think Script-Fu is a great way to start because it has an immediate effect on image processing, so you can feel productive very quickly. You can also write scripts in [Python][8], but Script-Fu is the default option.
|
||||
[Script-Fu][6] 是 GIMP 内置的脚本语言。 是一种基于 [Scheme ][7]的编程语言。 如果您从未使用过 Scheme,请尝试一下,因为它可能非常有用。 我认为 Script-Fu 是一个很好的入门方法,因为它对图像处理具有立竿见影的效果,因此您可以非常快速地提高工作效率。 您也可以使用 [Python][8] 编写脚本,但是 Script-Fu 是默认选项。
|
||||
|
||||
To help you get acquainted with Scheme, GIMP's documentation offers an [in-depth tutorial][9]. Scheme is a [Lisp][10]-like language, so a major characteristic is that it uses a [prefix notation][11] and a [lot of parentheses][12]. Functions and operators are applied to a list of operands by prefixing them:
|
||||
为了帮助您熟悉 Scheme,GIMP 的文档提供了深入的[教程][9]。 Scheme 是一种类似于 [Lisp][10] 的语言,因此主要特征是它使用[前缀][11]表示法和[许多括号][12]。 通过为操作数和操作符添加前缀来将它们应用到操作数列表:
|
||||
|
||||
|
||||
```
|
||||
@ -38,21 +38,21 @@ To help you get acquainted with Scheme, GIMP's documentation offers an [in-depth
|
||||
↳ Returns a list containing 1, 2, 3, and 5
|
||||
```
|
||||
|
||||
It took me a while to find the documentation for the full list of GIMP's functions, but it was actually straightforward. In the **Help** menu, there is a **Procedure Browser** with very extensive and detailed documentation about all the possible functions.
|
||||
我花了一些时间才能找到 GIMP 功能完整列表的文档,但实际上很简单。 在 **Help** 菜单中,有一个 **Procedure Browser**,其中包含有关所有可能功能的非常详尽的文档。
|
||||
|
||||
![GIMP Procedure Browser][13]
|
||||
|
||||
(Cristiano Fontana, [CC BY-SA 4.0][4])
|
||||
|
||||
### Accessing GIMP's batch mode
|
||||
### 使用 GIMP 的批处理模式
|
||||
|
||||
You can run GIMP with batch mode enabled by using the `-b` option. The `-b` option's argument can be the script you want to run or a dash (`-`) that makes GIMP launch in an interactive mode instead of the command line. Normally when you start GIMP, it loads its graphical user interface (GUI), but you can disable that with the `-i` option.
|
||||
您可以使用 `-b` 选项以批处理的方式启动 GIMP. `-b` 选项的参数可以是你想要运行的脚本,或者用一个 `-` 来让 GIMP 进入交互模式而不是命令行模式。正常情况下,当你启动 GIMP 的时候,它会启动图形界面,但是你可以使用 `-i` 选项来禁用它。
|
||||
|
||||
### Writing your first script
|
||||
### 开始编写你的第一个脚本
|
||||
|
||||
Create a file called `chalk.scm` and save it to the `scripts` folder found in the **Preferences** window under **Folders → Scripts**. In my case, it is at `$HOME/.config/GIMP/2.10/scripts`.
|
||||
创建一个名为 `chalk.scm` 的文件,并把它保存在 **Preferences** 窗口中 **Folders** 选项下的 **Script** 中指定的 `script` 文件夹下。就我而言,是在 `$HOME/.config/GIMP/2.10/scripts`.
|
||||
|
||||
Inside the `chalk.scm` file, write your first script with:
|
||||
在 `chalk.scm` 文件中,写入下面的内容:
|
||||
|
||||
|
||||
```
|
||||
@ -62,7 +62,7 @@ Inside the `chalk.scm` file, write your first script with:
|
||||
(new-filename (string-append "modified_" filename)))
|
||||
(gimp-image-select-color image CHANNEL-OP-REPLACE drawable '(0 0 0))
|
||||
(gimp-selection-grow image grow-pixels)
|
||||
(gimp-context-set-foreground '(0 0 0))
|
||||
(gimp-context-set- '(0 0 0))
|
||||
(gimp-edit-bucket-fill drawable BUCKET-FILL-FG LAYER-MODE-NORMAL 100 255 TRUE 0 0)
|
||||
(gimp-selection-none image)
|
||||
(plug-in-spread RUN-NONINTERACTIVE image drawable spread-amount spread-amount)
|
||||
@ -72,20 +72,20 @@ Inside the `chalk.scm` file, write your first script with:
|
||||
(gimp-image-delete image)))
|
||||
```
|
||||
|
||||
### Defining the script variables
|
||||
### 定义脚本变量
|
||||
|
||||
In the script, the `(define (chalk filename grow-pixels spread-amound percentage) ...)` function defines a new function called `chalk` that accepts the parameters: `filename`, `grow-pixels`, `spread-amound`, and `percentage`. Everything else inside the `define` function is the body of the `chalk` function. You might have noticed that variables with long names are spelled with dashes between the words; this is the idiomatic style of Lisp-like languages.
|
||||
在脚本中, `(define (chalk filename grow-pixels spread-amound percentage) ...)` 函数定义了一个名叫 `chalk` 的新函数。它的函数参数是 `filename`, `grow-pixels`, `spread-amound` 和 `percentage`. 在 `define` 中的所有内容都是 `chalk` 函数的主体。你可能已经注意到,那些名字比较长的变量中间都有一个破折号来分割。这是类 Lisp 语言的惯用风格。
|
||||
|
||||
The `(let* ...)` function is a special procedure that allows you to define some temporary variables that are valid only inside the body. In this case, the variables are `image`, `drawable`, and `new-filename`. It loads the image with `gimp-file-load`, which returns a list that includes the image, then it selects the first entry with the `car` function. Then, it selects the first active layer and stores its reference in the `drawable` variable. Finally, it defines the string containing the new filename of the resulting image.
|
||||
`(let* ...)` 函数是一个特殊的函数可以让你定义一些只有在这个函数体中才有效的临时变量。临时变量有 `image`, `drawable`, 以及 `new-filename`. 它使用 `gimp-file-load` 来载入图片,这会返回它所包含的图片的一个列表。并通过 `car` 函数来选取第一项。 然后,它选择第一个活动层并将其引用存储在 `drawable` 变量中。 最后,它定义了包含图像新文件名的字符串。
|
||||
|
||||
To help you better understand the procedure, I'll break it down. First, start GIMP with the GUI enabled and the Script-Fu console, which is found in **Filters → Script-Fu → Console**. In this case, you cannot use `let*` because the variables must be persistent. Define the `image` variable using the `define` function, and give it the proper path to find the image:
|
||||
为了帮助您更好地了解该过程,我将对其进行分解。 首先,启动带 GUI 的 GIMP,然后你可以通过依次点击 **Filters → Script-Fu → Console** 来打开 Script-Fu 控制台。 在这种情况下,不能使用 `let *`,因为变量必须是持久的。 使用 `define` 函数定义 `image` 变量,并为其提供查找图像的正确路径:
|
||||
|
||||
|
||||
```
|
||||
`(define image (car (gimp-file-load RUN-NONINTERACTIVE "Fourier.png" "Fourier.png")))`
|
||||
```
|
||||
|
||||
It appears that nothing has happened in the GUI, but the image is loaded. You need to enable the image display with:
|
||||
似乎在 GUI 中什么也没有发生,但是图像已加载。 您需要通过以下方式来让图像显示:
|
||||
|
||||
|
||||
```
|
||||
@ -96,27 +96,27 @@ It appears that nothing has happened in the GUI, but the image is loaded. You ne
|
||||
|
||||
(Cristiano Fontana, [CC BY-SA 4.0][4])
|
||||
|
||||
Now, get the active layer and store it in the `drawable` variable:
|
||||
现在,获取活动层并将其存储在 `drawable` 变量中:
|
||||
|
||||
|
||||
```
|
||||
`(define drawable (car (gimp-image-get-active-layer image)))`
|
||||
```
|
||||
|
||||
Finally, define the image's new filename:
|
||||
最后,定义图像的新文件名:
|
||||
|
||||
|
||||
```
|
||||
`(define new-filename "modified_Fourier.png")`
|
||||
```
|
||||
|
||||
Here is what you should see in the Script-Fu console after running these commands:
|
||||
运行命令后,您将在 Script-Fu 控制台中看到以下内容:
|
||||
|
||||
![Script-Fu console][15]
|
||||
|
||||
(Cristiano Fontana, [CC BY-SA 4.0][4])
|
||||
|
||||
Before acting on the image, you need to define the variables that would be defined as the function arguments in the script:
|
||||
在对图像执行操作之前,需要定义将在脚本中作为函数参数的变量:
|
||||
|
||||
|
||||
```
|
||||
@ -125,9 +125,9 @@ Before acting on the image, you need to define the variables that would be defin
|
||||
(define percentage 3)
|
||||
```
|
||||
|
||||
### Acting on the image
|
||||
### 处理图片
|
||||
|
||||
Now that all the relevant variables are defined, you can act on the image. The script's actions can be executed directly on the console. The first step is to select the color black on the active layer. The color is written as a list of three numbers—either as `(list 0 0 0)` or `'(0 0 0)`:
|
||||
现在,所有相关变量都已定义,您可以对图像进行操作了。 脚本的操作可以直接在控制台上执行。第一步是在活动层上选择黑色。 颜色被写成一个由三个数字组成的列表,即 `(list 0 0 0)` 或者是 `'(0 0 0)`:
|
||||
|
||||
|
||||
```
|
||||
@ -138,7 +138,7 @@ Now that all the relevant variables are defined, you can act on the image. The s
|
||||
|
||||
(Cristiano Fontana, [CC BY-SA 4.0][4])
|
||||
|
||||
Grow the selection by two pixels:
|
||||
扩大选取两个像素:
|
||||
|
||||
|
||||
```
|
||||
@ -149,7 +149,7 @@ Grow the selection by two pixels:
|
||||
|
||||
(Cristiano Fontana, [CC BY-SA 4.0][4])
|
||||
|
||||
Set the foreground color to black, and fill the selection with it:
|
||||
将前景色设置为黑色,并用它填充选区:
|
||||
|
||||
|
||||
```
|
||||
@ -161,7 +161,7 @@ Set the foreground color to black, and fill the selection with it:
|
||||
|
||||
(Cristiano Fontana, [CC BY-SA 4.0][4])
|
||||
|
||||
Delete the selection:
|
||||
删除选区:
|
||||
|
||||
|
||||
```
|
||||
@ -172,7 +172,7 @@ Delete the selection:
|
||||
|
||||
(Cristiano Fontana, [CC BY-SA 4.0][4])
|
||||
|
||||
Move the pixels around randomly:
|
||||
随机移动像素:
|
||||
|
||||
|
||||
```
|
||||
@ -183,7 +183,7 @@ Move the pixels around randomly:
|
||||
|
||||
(Cristiano Fontana, [CC BY-SA 4.0][4])
|
||||
|
||||
Invert the image colors:
|
||||
反转图像颜色:
|
||||
|
||||
|
||||
```
|
||||
@ -194,7 +194,7 @@ Invert the image colors:
|
||||
|
||||
(Cristiano Fontana, [CC BY-SA 4.0][4])
|
||||
|
||||
Randomize the pixels:
|
||||
随机化像素:
|
||||
|
||||
|
||||
```
|
||||
@ -205,7 +205,7 @@ Randomize the pixels:
|
||||
|
||||
(Cristiano Fontana, [CC BY-SA 4.0][4])
|
||||
|
||||
Save the image to a new file:
|
||||
将图像保存到新文件:
|
||||
|
||||
|
||||
```
|
||||
@ -214,24 +214,24 @@ Save the image to a new file:
|
||||
|
||||
![Equations of the Fourier transform and its inverse][23]
|
||||
|
||||
Fourier transform equations (Cristiano Fontana, [CC BY-SA 4.0][4])
|
||||
傅立叶变换方程 (Cristiano Fontana, [CC BY-SA 4.0][4])
|
||||
|
||||
### Running the script in batch mode
|
||||
### 以批处理模式运行脚本
|
||||
|
||||
Now that you know what the script does, you can run it in batch mode:
|
||||
现在您知道了脚本的功能,可以在批处理模式下运行它:
|
||||
|
||||
|
||||
```
|
||||
`gimp -i -b '(chalk "Fourier.png" 2 4 3)' -b '(gimp-quit 0)'`
|
||||
```
|
||||
|
||||
After the `chalk` function runs, it calls a second function with the `-b` option to tell GIMP to quit: `gimp-quit`.
|
||||
在运行 `chalk` 函数之后,它将使用 `-b` 选项调用第二个函数 `gimp-quit` 来告诉 GIMP 退出。
|
||||
|
||||
### Learn more
|
||||
### 了解更多
|
||||
|
||||
This tutorial showed you how to get started with GIMP's built-in scripting features and introduced Script-Fu, GIMP's Scheme implementation. If you want to move forward, I suggest you look at the official documentation and its [tutorial][9]. If you are not familiar with Scheme or Lisp, the syntax could be a little intimidating at first, but I suggest you give it a try anyway. It might be a nice surprise.
|
||||
本教程向您展示了如何开始使用 GIMP 的内置脚本功能,并介绍了 GIMP 的 Scheme 实现的 Script-Fu。 如果您想继续前进,建议您查看官方文档及其[入门教程][9]。 如果您不熟悉 Scheme 或 Lisp,那么一开始的语法可能有点吓人,但我还是建议您尝试一下。 这可能是一个不错的惊喜。
|
||||
|
||||
Professional design software like Photoshop is terrific, but it’s also expensive. What do you do...
|
||||
Photoshop 之类的专业设计软件非常棒,但价格也很昂贵。 你会怎么做...
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
@ -239,7 +239,7 @@ via: https://opensource.com/article/21/1/gimp-scripting
|
||||
|
||||
作者:[Cristiano L. Fontana][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
译者:[amwps290](https://github.com/amwps290)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
@ -0,0 +1,63 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (3 wishes for open source productivity in 2021)
|
||||
[#]: via: (https://opensource.com/article/21/1/productivity-wishlist)
|
||||
[#]: author: (Kevin Sonney https://opensource.com/users/ksonney)
|
||||
|
||||
2021 年开源生产力的 3 个愿望
|
||||
======
|
||||
2021年,开源世界可以拓展的有很多。这是我特别感兴趣的三个领域。
|
||||
![Looking at a map for career journey][1]
|
||||
|
||||
在前几年,这个年度系列涵盖了单个的应用。今年,我们除了关注 2021 年的策略外,还将关注一体化解决方案。欢迎来到 2021 年 21 天生产力的最后一天。
|
||||
|
||||
我们已经到了另外一个系列的结尾处。因此,让我们谈谈我希望在 2021 年看到的更多事情。
|
||||
|
||||
### 断网
|
||||
|
||||
![Large Lego set built by the author][2]
|
||||
|
||||
我是在假期期间制作的(Kevin Sonney, [CC BY-SA 4.0][3])
|
||||
|
||||
对_许多_人来说,2020 年是非常困难的一年。疫情大流行、各种政治事件、24 小时新闻报道等等,都对我们的精神健康造成了伤害。虽然我谈到了[抽出时间进行自我护理][4],但我只提到了断网:也就是关闭提醒、手机、平板等,暂时无视这个世界。我公司的一位经理居然告诉我们,如果放假或休息一天,就把所有与工作有关的东西都关掉(除非我们在值班)。我最喜欢的“断网”活动之一就是听音乐和搭建大而复杂的乐高。
|
||||
|
||||
### 可访问性
|
||||
|
||||
尽管我谈论的许多技术都是任何人都可以做的,但是软件方面的可访问性都有一定难度。自迁移之初以来,Linux 和开源世界在辅助技术方面已经走了很长一段路。但是,仍然有太多的应用和系统不会考虑有些用户没有与设计者相同的能力。我一直在关注这一领域的发展,因为每个人都应该能够访问事物。
|
||||
|
||||
### 更多的一体化选择
|
||||
|
||||
![JPilot all in one organizer software interface][5]
|
||||
|
||||
JPilot(Kevin Sonney, [CC BY-SA 4.0][3])
|
||||
|
||||
在 FOSS 世界中,一体化的个人信息管理解决方案远没有商业软件世界中那么多。总体趋势是使用单独的应用,它们必须通过配置来相互通信或通过中介服务(如 CalDAV 服务器)。移动市场在很大程度上推动了这一趋势,但我仍然向往像 [JPilot][6] 这样无需额外插件或服务就能完成几乎所有我需要的事情的日子。
|
||||
|
||||
|
||||
非常感谢大家阅读这个年度系列。如果你认为我错过了什么,或者明年需要注意什么,请在下方评论。
|
||||
|
||||
就像我在[生产力炼金术][7]上说的那样,尽最大努力保持生产力!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/21/1/productivity-wishlist
|
||||
|
||||
作者:[Kevin Sonney][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/ksonney
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/career_journey_road_gps_path_map_520.png?itok=PpL6jJgY (Looking at a map for career journey)
|
||||
[2]: https://opensource.com/sites/default/files/day21-image1.png
|
||||
[3]: https://creativecommons.org/licenses/by-sa/4.0/
|
||||
[4]: https://opensource.com/article/21/1/self-care
|
||||
[5]: https://opensource.com/sites/default/files/day21-image2.png
|
||||
[6]: http://www.jpilot.org/
|
||||
[7]: https://productivityalchemy.com
|
Loading…
Reference in New Issue
Block a user