mirror of
https://github.com/LCTT/TranslateProject.git
synced 2024-12-26 21:30:55 +08:00
commit
e6d9a28783
@ -1,25 +1,26 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (hanwckf)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11648-1.html)
|
||||
[#]: subject: (curl exercises)
|
||||
[#]: via: (https://jvns.ca/blog/2019/08/27/curl-exercises/)
|
||||
[#]: author: (Julia Evans https://jvns.ca/)
|
||||
|
||||
curl 练习
|
||||
21 个 curl 命令练习
|
||||
======
|
||||
|
||||
最近,我对人们如何学习新事物感兴趣。我正在读 Kathy Sierra 的好书 [Badass: Making Users Awesome][1],它探讨了有关“刻意练习”的想法。这个想法是,你找到一个可以用三个45分钟课程内能够学会的小技能,并专注于学习这项小技能。因此,作为一项练习,我尝试考虑一项能够在3个45分钟课程内学会的计算机技能。
|
||||
最近,我对人们如何学习新事物感兴趣。我正在读 Kathy Sierra 的好书《[Badass: Making Users Awesome][1]》,它探讨了有关“刻意练习”的想法。这个想法是,你找到一个可以用三节 45 分钟课程内能够学会的小技能,并专注于学习这项小技能。因此,作为一项练习,我尝试考虑一项能够在三节 45 分钟课程内学会的计算机技能。
|
||||
|
||||
我认为使用 curl 构造 HTTP 请求也许就是这样的一项技能,所以这里有一些curl练习作为实验!
|
||||
我认为使用 `curl` 构造 HTTP 请求也许就是这样的一项技能,所以这里有一些 `curl` 练习作为实验!
|
||||
|
||||
### 什么是 curl ?
|
||||
|
||||
curl 是用于构造 HTTP 请求的命令行工具。我喜欢使用 curl ,因为它能够很轻松地测试服务器或API的行为是否符合预期,但是刚开始接触它的时候会让你感到一些困惑!
|
||||
`curl` 是用于构造 HTTP 请求的命令行工具。我喜欢使用 `curl`,因为它能够很轻松地测试服务器或 API 的行为是否符合预期,但是刚开始接触它的时候会让你感到一些困惑!
|
||||
|
||||
下面是一幅解释 curl 常用命令行参数的漫画 (在我的 [Bite Size Networking][2] 杂志的第6页)。
|
||||
<https://jvns.ca/images/curl.jpeg>
|
||||
下面是一幅解释 `curl` 常用命令行参数的漫画 (在我的 [Bite Size Networking][2] 杂志的第 6 页)。
|
||||
|
||||
![](https://jvns.ca/images/curl.jpeg)
|
||||
|
||||
### 熟能生巧
|
||||
|
||||
@ -35,15 +36,15 @@ curl https://api.gumroad.com/v2/sales \
|
||||
|
||||
### 21 个 curl 练习
|
||||
|
||||
这些练习是用来理解如何使用 curl 构造不同种类的 HTTP 请求的,它们是故意重复的,基本上包含了我需要 curl 做的任何事情。
|
||||
这些练习是用来理解如何使用 `curl` 构造不同种类的 HTTP 请求的,它们是故意有点重复的,基本上包含了我需要 `curl` 做的任何事情。
|
||||
|
||||
为了简单起见,我们将对 https://httpbin.org 发起一系列 HTTP 请求,httpbin 接受 HTTP 请求,然后在响应中回显你所发起的 HTTP 请求。
|
||||
|
||||
1. 请求 <https://httpbin.org>
|
||||
2. 请求 <https://httpbin.org/anything>,httpbin.org/anything 将会解析你发起的请求,并且在响应中回显。curl 默认发起的是 GET 请求
|
||||
2. 请求 <https://httpbin.org/anything>,它将会解析你发起的请求,并且在响应中回显。`curl` 默认发起的是 GET 请求
|
||||
3. 向 <https://httpbin.org/anything> 发起 GET 请求
|
||||
4. 向 <https://httpbin.org/anything> 发起 GET 请求,但是这次需要添加一些查询参数(设置 `value=panda` )
|
||||
5. 请求 Google 的 robots.txt 文件 ([www.google.com/robots.txt][3])
|
||||
4. 向 <https://httpbin.org/anything> 发起 GET 请求,但是这次需要添加一些查询参数(设置 `value=panda`)
|
||||
5. 请求 Google 的 `robots.txt` 文件 ([www.google.com/robots.txt][3])
|
||||
6. 向 <https://httpbin.org/anything> 发起 GET 请求,并且设置请求头为 `User-Agent: elephant`
|
||||
7. 向 <https://httpbin.org/anything> 发起 DELETE 请求
|
||||
8. 请求 <https://httpbin.org/anything> 并获取响应头信息
|
||||
@ -54,12 +55,12 @@ curl https://api.gumroad.com/v2/sales \
|
||||
13. 设置请求头为 `Accept: image/png` 并且向 <https://httpbin.org/image> 发起请求,将输出保存为 PNG 文件,然后使用图片浏览器打开。尝试使用不同的 `Accept:` 字段去请求此 URL
|
||||
14. 向 <https://httpbin.org/anything> 发起 PUT 请求
|
||||
15. 请求 <https://httpbin.org/image/jpeg> 并保存为文件,然后使用你的图片编辑器打开这个文件
|
||||
16. 请求 <https://www.twitter.com>,你将会得到空的响应。让 curl 显示出响应头信息,并尝试找出响应内容为空的原因
|
||||
16. 请求 <https://www.twitter.com>,你将会得到空的响应。让 `curl` 显示出响应头信息,并尝试找出响应内容为空的原因
|
||||
17. 向 <https://httpbin.org/anything> 发起任意的请求,同时设置一些无意义的请求头(例如:`panda: elephant`)
|
||||
18. 请求 <https://httpbin.org/status/404> 和 <https://httpbin.org/status/200>,然后再次请求它们并且让 curl 显示响应头信息
|
||||
19. 请求 <https://httpbin.org/anything> 并且设置用户名和密码(使用 `-u username:password`)
|
||||
20. 设置 `Accept-Language: es-ES` 的请求头用以下载 Twitter 的西班牙语主页 (<https://twitter.com>)
|
||||
21. 使用 curl 向 Stripe API 发起请求(请查看 <https://stripe.com/docs/development> 了解如何使用,他们会给你一个测试用的 API key)。尝试向 <https://httpbin.org/anything> 发起相同的请求
|
||||
21. 使用 `curl` 向 Stripe API 发起请求(请查看 <https://stripe.com/docs/development> 了解如何使用,他们会给你一个测试用的 API key)。尝试向 <https://httpbin.org/anything> 发起相同的请求
|
||||
|
||||
|
||||
|
||||
@ -70,7 +71,7 @@ via: https://jvns.ca/blog/2019/08/27/curl-exercises/
|
||||
作者:[Julia Evans][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[hanwckf](https://github.com/hanwckf)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
@ -1,8 +1,8 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (wxy)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11647-1.html)
|
||||
[#]: subject: (5 tips for GNU Debugger)
|
||||
[#]: via: (https://opensource.com/article/19/9/tips-gnu-debugger)
|
||||
[#]: author: (Tim Waugh https://opensource.com/users/twaugh)
|
||||
@ -12,7 +12,7 @@
|
||||
|
||||
> 了解如何使用 gdb 的一些鲜为人知的功能来检查和修复代码。
|
||||
|
||||
![Bug tracking magnifying glass on computer screen][1]
|
||||
![](https://img.linux.net.cn/data/attachment/album/201912/05/203701ss8onfvpsnvnsnn5.jpg)
|
||||
|
||||
[GNU 调试器][2](`gdb`)是一种宝贵的工具,可用于在开发程序时检查正在运行的进程并解决问题。
|
||||
|
||||
@ -54,7 +54,7 @@ Breakpoint 1, sometimes_crashes (f=0x0) at prog.c:5
|
||||
(gdb)
|
||||
```
|
||||
|
||||
条件断点使你不必让 `gdb` 每次调用该函数时都去问你要做什么,而是让条件断点仅在特定表达式的值为 `true` 时才使 `gdb` 停止在该位置。如果执行到达条件断点的位置,但表达式的计算结果为 `false` ,调试器会自动使程序继续运行,而无需询问用户该怎么做。
|
||||
条件断点使你不必让 `gdb` 每次调用该函数时都去问你要做什么,而是让条件断点仅在特定表达式的值为 `true` 时才使 `gdb` 停止在该位置。如果执行到达条件断点的位置,但表达式的计算结果为 `false`,调试器会自动使程序继续运行,而无需询问用户该怎么做。
|
||||
|
||||
### 断点命令
|
||||
|
||||
@ -101,14 +101,14 @@ GNU 调试器内置支持使用 `x` 命令以各种格式检查内存,包括
|
||||
|
||||
```
|
||||
(gdb) x/33xb mydata
|
||||
0x404040 <mydata>: 0x02 0x01 0x00 0x02 0x00 0x00 0x00 0x01
|
||||
0x404048 <mydata+8>: 0x01 0x47 0x00 0x12 0x61 0x74 0x74 0x72
|
||||
0x404040 <mydata> : 0x02 0x01 0x00 0x02 0x00 0x00 0x00 0x01
|
||||
0x404048 <mydata+8> : 0x01 0x47 0x00 0x12 0x61 0x74 0x74 0x72
|
||||
0x404050 <mydata+16>: 0x69 0x62 0x75 0x74 0x65 0x73 0x2d 0x63
|
||||
0x404058 <mydata+24>: 0x68 0x61 0x72 0x73 0x65 0x75 0x00 0x05
|
||||
0x404060 <mydata+32>: 0x00
|
||||
```
|
||||
|
||||
如果你想让 `gdb` 像 `hexdump` 一样显示内存怎么办?这是可以的, 实际上,你可以将这种方法用于你喜欢的任何格式。
|
||||
如果你想让 `gdb` 像 `hexdump` 一样显示内存怎么办?这是可以的,实际上,你可以将这种方法用于你喜欢的任何格式。
|
||||
|
||||
通过使用 `dump` 命令以将字节存储在文件中,结合 `shell` 命令以在文件上运行 `hexdump` 以及`define` 命令,我们可以创建自己的新的 `hexdump` 命令来使用 `hexdump` 显示内存内容。
|
||||
|
||||
@ -162,7 +162,7 @@ prog.c:
|
||||
|
||||
有时,你希望自己可以逆转时间。想象一下,你已经达到了变量的监视点。监视点像是一个断点,但不是在程序中的某个位置设置,而是在表达式上设置(使用 `watch` 命令)。每当表达式的值更改时,执行就会停止,并且调试器将获得控制权。
|
||||
|
||||
想象一下你已经达到了这个监视点,并且由该变量使用的内存已更改了值。事实证明,这可能是由更早发生的事情引起的。例如,内存已释放,现在正在重新使用。但是是何时何地被释放的呢?
|
||||
想象一下你已经达到了这个监视点,并且由该变量使用的内存已更改了值。事实证明,这可能是由更早发生的事情引起的。例如,内存已释放,现在正在重新使用。但是它是何时何地被释放的呢?
|
||||
|
||||
GNU 调试器甚至可以解决此问题,因为你可以反向运行程序!
|
||||
|
||||
@ -209,7 +209,7 @@ via: https://opensource.com/article/19/9/tips-gnu-debugger
|
||||
作者:[Tim Waugh][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[wxy](https://github.com/wxy)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
@ -1,26 +1,26 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11651-1.html)
|
||||
[#]: subject: (A quick introduction to Toolbox on Fedora)
|
||||
[#]: via: (https://fedoramagazine.org/a-quick-introduction-to-toolbox-on-fedora/)
|
||||
[#]: author: (Ryan Walter https://fedoramagazine.org/author/rwaltr/)
|
||||
|
||||
快速介绍 Fedora 中的 Toolbox
|
||||
Fedora 中的 Toolbox 简介
|
||||
======
|
||||
|
||||
![][1]
|
||||
|
||||
Toolbox 使你可以[在容器中分类和管理开发环境][2],而无需 root 权限或手动添加卷。它创建一个容器,你可以在其中安装自己的命令行工具,而无需在基础系统中安装它们。当你没有root 权限或无法直接安装程序时,也可以使用它。本文会介绍 Toolbox 及其功能。
|
||||
Toolbox 使你可以[在容器中分类和管理开发环境][2],而无需 root 权限或手动添加卷。它创建一个容器,你可以在其中安装自己的命令行工具,而无需在基础系统中安装它们。当你没有 root 权限或无法直接安装程序时,也可以使用它。本文会介绍 Toolbox 及其功能。
|
||||
|
||||
### 安装 Toolbox
|
||||
|
||||
[Silverblue][3] 默认包含 Toolbox。对于 Workstation 和 Server 版本,你可以使用 _dnf install toolbox_ 从默认仓库中获取它。
|
||||
[Silverblue][3] 默认包含 Toolbox。对于 Workstation 和 Server 版本,你可以使用 `dnf install toolbox` 从默认仓库中获取它。
|
||||
|
||||
### 创建 Toolbox
|
||||
|
||||
打开终端并运行 _toolbox enter_。程序将自动请求许可来下载最新的镜像,创建第一个容器并将你的 shell 放在该容器中。
|
||||
打开终端并运行 `toolbox enter`。程序将自动请求许可来下载最新的镜像,创建第一个容器并将你的 shell 放在该容器中。
|
||||
|
||||
```
|
||||
$ toolbox enter
|
||||
@ -29,7 +29,7 @@ Image required to create toolbox container.
|
||||
Download registry.fedoraproject.org/f30/fedora-toolbox:30 (500MB)? [y/N]: y
|
||||
```
|
||||
|
||||
当前,toolbox 和你的基本系统之间没有区别。你的文件系统和软件包未更改。这是一个使用仓库的示例,它包含 _~/src/resume_ 文件夹下的简历的文档源。简历是使用 _pandoc_ 工具构建的。
|
||||
当前,Toolbox 和你的基本系统之间没有区别。你的文件系统和软件包未曾改变。下面是一个使用仓库的示例,它包含 `~/src/resume` 文件夹下的简历的文档源文件。简历是使用 `pandoc` 工具构建的。
|
||||
|
||||
```
|
||||
$ pwd
|
||||
@ -47,7 +47,7 @@ $ pandoc -v
|
||||
bash: pandoc: command not found
|
||||
```
|
||||
|
||||
这个 toolbox 没有构建简历所需的程序。你可以通过使用 _dnf_ 安装工具来解决此问题。由于正在容器中运行,因此不会提示你输入 root 密码。
|
||||
这个 toolbox 没有构建简历所需的程序。你可以通过使用 `dnf` 安装工具来解决此问题。由于正在容器中运行,因此不会提示你输入 root 密码。
|
||||
|
||||
```
|
||||
$ sudo dnf groupinstall "Authoring and Publishing" -y && sudo dnf install pandoc make -y
|
||||
@ -63,7 +63,7 @@ $ ls BUILDS/
|
||||
resume.docx resume.html resume.pdf resume.rtf resume.txt
|
||||
```
|
||||
|
||||
运行 _exit_ 退出 toolbox。
|
||||
运行 `exit` 可以退出 toolbox。
|
||||
|
||||
```
|
||||
$ cd BUILDS/
|
||||
@ -80,21 +80,17 @@ bash: pandoc: command not found...
|
||||
resume.docx resume.html resume.pdf resume.rtf resume.txt
|
||||
```
|
||||
|
||||
你会在主目录中得到由 toolbox 创建的文件。toolbox 中安装的程序无法在外部访问。
|
||||
你会在主目录中得到由 toolbox 创建的文件。而在 toolbox 中安装的程序无法在外部访问。
|
||||
|
||||
### 提示和技巧
|
||||
|
||||
本介绍仅涉及 toolbox 的表明。还有一些其他提示,但是你也可以查看[官方文档][2]。
|
||||
本介绍仅涉及 toolbox 的表面。还有一些其他提示,但是你也可以查看[官方文档][2]。
|
||||
|
||||
* _Toolbox –help_ 会显示 Toolbox 的手册页
|
||||
* 你可以一次有多个 toolbox。使用 _toolbox create -c Toolboxname_ 和 _toolbox enter -c Toolboxname_。
|
||||
* Toolbox 使用 [Podman][4] 来完成繁重的工作。使用 _toolbox list_ 查找 Toolbox 创建的容器的 ID。Podman 可以使用这些 ID 来执行 _rm_ 和 _stop_ 之类的操作。 (你也可以在[此文章][5]中阅读有关 Podman 的更多信息。)
|
||||
* `toolbox –help` 会显示 Toolbox 的手册页。
|
||||
* 你可以一次有多个 toolbox。使用 `toolbox create -c Toolboxname` 和 `toolbox enter -c Toolboxname`。
|
||||
* Toolbox 使用 [Podman][4] 来完成繁重的工作。使用 `toolbox list` 可以查找 Toolbox 创建的容器的 ID。Podman 可以使用这些 ID 来执行 `rm` 和 `stop` 之类的操作。 (你也可以在[此文章][5]中阅读有关 Podman 的更多信息。)
|
||||
|
||||
|
||||
* * *
|
||||
|
||||
_照片出自 [Flickr][7] 的 [Florian Richter][6]。_
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://fedoramagazine.org/a-quick-introduction-to-toolbox-on-fedora/
|
||||
@ -102,7 +98,7 @@ via: https://fedoramagazine.org/a-quick-introduction-to-toolbox-on-fedora/
|
||||
作者:[Ryan Walter][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/) 荣誉推出
|
||||
|
63
published/20191202 Use the Window Maker desktop on Linux.md
Normal file
63
published/20191202 Use the Window Maker desktop on Linux.md
Normal file
@ -0,0 +1,63 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11650-1.html)
|
||||
[#]: subject: (Use the Window Maker desktop on Linux)
|
||||
[#]: via: (https://opensource.com/article/19/12/linux-window-maker-desktop)
|
||||
[#]: author: (Seth Kenlon https://opensource.com/users/seth)
|
||||
|
||||
在 Linux 上使用 Window Maker 桌面
|
||||
======
|
||||
> 本文是 24 天 Linux 桌面特别系列的一部分。让我们和 Window Maker 一起时光倒流,它为如今的用户实现了老式 Unix NeXTSTEP 环境。
|
||||
|
||||
![Penguin with green background][1]
|
||||
|
||||
在 Mac OS X 之前,有一个奇怪的闭源 Unix 系统,称为 [NeXTSTEP][2]。Sun Microsystems 后来将 NeXTSTEP 的底层设为开放规范,这使其它项目可以创建许多自由开源的 NeXT 库和组件。GNUStep 实现了许多 NeXTSTEP 库,而 [Window Maker][3] 实现了其桌面环境。
|
||||
|
||||
Window Maker 非常接近地模仿了 NeXTSTEP 桌面 GUI,并提供了一个有趣的视角,可以让人了解 80 年代末 90 年代初的 Unix 是什么样子的。它还揭示了窗口管理器(例如 Fluxbox 和 Openbox)背后的一些基本概念。
|
||||
|
||||
你可以从发行版的仓库中安装 Window Maker。要尝试它,请在安装完成后退出桌面会话。默认情况下,会话管理器(KDM、GDM、LightDM 或 XDM,这取决于你的设置)将继续将登录到默认桌面,因此登录时必须覆盖默认设置。
|
||||
|
||||
要在 GDM 上切换到 Window Maker:
|
||||
|
||||
![Selecting the Window Maker desktop in GDM][4]
|
||||
|
||||
在 KDM 上:
|
||||
|
||||
![Selecting the Window Maker desktop in KDM][5]
|
||||
|
||||
### Window Maker 程序坞
|
||||
|
||||
默认情况下,Window Maker 桌面是空的,但每个角落都有几个*程序坞*。像在 NeXTSTEP 中一样,在 Window Maker 中,在程序坞区域,应用可最小化成图标后停靠,可创建启动器来快速访问常见应用,并且可运行微型的 “dockapp”。
|
||||
|
||||
你可以在软件仓库中搜索 “dockapp” 来试用 dockapp。它们常常是网络和系统监控器、音频设置面板、时钟等。这是在 Fedora 上运行的 Window Maker:
|
||||
|
||||
![Window Maker running on Fedora][6]
|
||||
|
||||
### 应用菜单
|
||||
|
||||
要访问应用菜单,请右键单击桌面上的任意位置。要关闭它,请再次单击鼠标右键。Window Maker 不是桌面环境(DE),而是一个窗口管理器(DM)。它可以帮助你安排和管理窗口。它唯一捆绑的程序是 [WPrefs][7](或更常见的说法 Window Maker 偏好),它可帮助你配置常用设置,而应用菜单则提供对其他选项(包括主题)的访问。
|
||||
|
||||
运行什么应用完全由你决定。在 Window Maker 中,你可以选择运行 KDE 应用、GNOME 应用以及不被视为任何其他主流桌面应用的程序。你可以创建自己的工作环境,并且可以使用 Window Maker 对其进行管理。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/19/12/linux-window-maker-desktop
|
||||
|
||||
作者:[Seth Kenlon][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/seth
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/linux_penguin_green.png?itok=ENdVzW22 (Penguin with green background)
|
||||
[2]: https://en.wikipedia.org/wiki/NeXTSTEP
|
||||
[3]: https://www.windowmaker.org/
|
||||
[4]: https://opensource.com/sites/default/files/uploads/advent-windowmaker-gdm.jpg (Selecting the Window Maker desktop in GDM)
|
||||
[5]: https://opensource.com/sites/default/files/uploads/advent-windowmaker-kdm.jpg (Selecting the Window Maker desktop in KDM)
|
||||
[6]: https://opensource.com/sites/default/files/uploads/advent-windowmaker.jpg (Window Maker running on Fedora)
|
||||
[7]: http://www.windowmaker.org/docs/guidedtour/prefs.html
|
@ -1,5 +1,5 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: translator: (chai-yuan)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
|
@ -1,5 +1,5 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
|
@ -0,0 +1,85 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Researchers experiment with glass-based storage that doesn't require electronics cooling)
|
||||
[#]: via: (https://www.networkworld.com/article/3488556/researchers-experiment-with-glass-based-storage-that-doesnt-require-electronics-cooling.html)
|
||||
[#]: author: (Patrick Nelson https://www.networkworld.com/author/Patrick-Nelson/)
|
||||
|
||||
Researchers experiment with glass-based storage that doesn't require electronics cooling
|
||||
======
|
||||
A Microsoft Research project uses laser optics and artificial intelligence to store data in quartz glass.
|
||||
Thinkstock
|
||||
|
||||
Hard drives aren’t going to be capacious enough for future data archiving and retrieval requirements, scientists believe, as applications such as artificial intelligence, wide-scale Internet of Things connectivity, and virtual and augmented reality take hold. Glass could be the answer.
|
||||
|
||||
Encoding in glass would have advantages over hard drives and other mediums, experts suggest. Holding capacity is greater, and the slivers of quartz being experimented with don’t need cooling or dehumidifying environments.
|
||||
|
||||
Microsoft Research, working in the UK along with the University of Southampton, [announced][1] that it has been able to store an entire movie on a quartz, glass-based storage medium. The team stored and retrieved a full-length Superman film on a small slab of the special material that measures about 3 inches square and less than a tenth of an inch thick. .
|
||||
|
||||
[][2]
|
||||
|
||||
BrandPost Sponsored by HPE
|
||||
|
||||
[Take the Intelligent Route with Consumption-Based Storage][2]
|
||||
|
||||
Combine the agility and economics of HPE storage with HPE GreenLake and run your IT department with efficiency.
|
||||
|
||||
“It looks like we’re now in a phase where we’re working on refinement and experimentation, rather asking the question ‘can we do it?’” said Mark Russinovich, Microsoft Azure’s chief technology officer, in a statement.
|
||||
|
||||
### Laser improvements fuel glass-based storage technology
|
||||
|
||||
Improvements in laser technology are behind the proof of concept Microsoft Research dubbed Project Silica. The femtosecond infrared lasers that are used in the process function similarly to eye surgery lasers. Those kinds of laser beams are much better and more precise than traditional ones. They don’t crack the glass, for one thing.
|
||||
|
||||
The glass is, in fact, structurally changed by the laser, which means that the data could last as long as the material does—possibly centuries, unlike existing mediums like tape. It’s robust, too. Interestingly, even if one were to break the glass, the data remains encoded in the shards, the researchers say.
|
||||
|
||||
“It’s somewhat like creating upside down icebergs at a nanoscale level, with different depths and sizes and grooves that make them unique,” Microsoft said. Voxels, which are a three-dimensional version of a pixel, are embedded in the glass, one-time, rather than just written to the top, as occurs with other mediums. That three-dimensional aspect, along with the inherent opaqueness, helps with low-latency retrieval—the reading can occur rapidly along all of the axis (x, y and z).
|
||||
|
||||
* [Backup vs. archive: Why it’s important to know the difference][3]
|
||||
* [How to pick an off-site data-backup method][4]
|
||||
* [Tape vs. disk storage: Why isn’t tape dead yet?][5]
|
||||
* [The correct levels of backup save time, bandwidth, space][6]
|
||||
|
||||
|
||||
|
||||
### Cloud storage alternatives
|
||||
|
||||
Glass isn’t the only potential replacement for old-school magnetic, solid-state and tape storage as the world increasingly collects data. Chemical, molecule and DNA options are all being suggested as potential alternatives to existing cloud storage.
|
||||
|
||||
Fitting transistors onto individual molecules is one answer, [say researchers at Arizona State University][7].
|
||||
|
||||
Synthetic DNA is another proposed option. Large amounts of information last a long time in DNA; a 45,000-year-old human bone was DNA-decoded a few years ago, for example. [Synthetic DNA could end up having similar advantages to that organic version][8], scientists think.
|
||||
|
||||
A third option, at a chemical level, is storing data on molecules and then dissolving that mix into liquids. [Massive amounts of data could be held in small containers][9], Brown University has said of its experiments in that area.
|
||||
|
||||
Perhaps most interestingly, with all of the these potential storage replacements (should any of them take off), the traditional environmental controls that we require for heat-generating electronics in data center environments would become moot.
|
||||
|
||||
“Quartz glass doesn’t need energy-intensive air conditioning to keep material at a constant temperature or systems that remove moisture from the air,” Microsoft said of Project Silica. “Both of which could lower the environmental footprint of large-scale data storage.”
|
||||
|
||||
Join the Network World communities on [Facebook][10] and [LinkedIn][11] to comment on topics that are top of mind.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.networkworld.com/article/3488556/researchers-experiment-with-glass-based-storage-that-doesnt-require-electronics-cooling.html
|
||||
|
||||
作者:[Patrick Nelson][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://www.networkworld.com/author/Patrick-Nelson/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://news.microsoft.com/innovation-stories/ignite-project-silica-superman/
|
||||
[2]: https://www.networkworld.com/article/3440100/take-the-intelligent-route-with-consumption-based-storage.html?utm_source=IDG&utm_medium=promotions&utm_campaign=HPE20773&utm_content=sidebar ( Take the Intelligent Route with Consumption-Based Storage)
|
||||
[3]: https://www.networkworld.com/article/3285652/storage/backup-vs-archive-why-its-important-to-know-the-difference.html
|
||||
[4]: https://www.networkworld.com/article/3328488/backup-systems-and-services/how-to-pick-an-off-site-data-backup-method.html
|
||||
[5]: https://www.networkworld.com/article/3315156/storage/tape-vs-disk-storage-why-isnt-tape-dead-yet.html
|
||||
[6]: https://www.networkworld.com/article/3302804/storage/the-correct-levels-of-backup-save-time-bandwidth-space.html
|
||||
[7]: https://www.networkworld.com/article/3344599/new-chemistry-based-data-storage-would-blow-moores-law-out-of-the-water.html
|
||||
[8]: https://www.networkworld.com/article/3268646/dna-data-storage-closer-to-becoming-reality.html
|
||||
[9]: https://www.networkworld.com/article/3251071/data-could-one-day-be-stored-on-molecules.html
|
||||
[10]: https://www.facebook.com/NetworkWorld/
|
||||
[11]: https://www.linkedin.com/company/network-world
|
@ -0,0 +1,90 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (The current state of blockchain and where it's going)
|
||||
[#]: via: (https://opensource.com/article/19/12/blockchain-evolution)
|
||||
[#]: author: (axel simon https://opensource.com/users/axel)
|
||||
|
||||
The current state of blockchain and where it's going
|
||||
======
|
||||
Take a look at the ecosystem and the projects trying to solve some of
|
||||
the limitations of blockchain technology.
|
||||
![Arrows moving a process forward][1]
|
||||
|
||||
In an earlier post, [_Blockchain evolution: A quick guide and why open source is at the heart of it_][2], I discussed the first generations of blockchains: the public Bitcoin and cryptocurrency blockchains, followed by the Ethereum blockchain capable of executing programs ("smart contracts"), leading to permissioned versions of code-executing blockchains (e.g., Hyperledger Fabric, Quorum).
|
||||
|
||||
Let's step back into the blockchain jungle and take a look at the current state of the ecosystem and the projects trying to solve some of the limitations of blockchain technology: speed and throughput, cross-blockchain information and value exchange, governance, and identity and account management.
|
||||
|
||||
### Speeding things up
|
||||
|
||||
One of the oft-heard gripes about current blockchain technologies is their limited speed, often measured by the number of transactions per second (TPS) that they can manage. This issue strongly limits their use in systems that need to process massive amounts of events. For instance, it has often been said (correctly) that Bitcoin can't handle more than seven transactions per second, and Ethereum can't do much more. Possibly the simplest way of defining the next generation of blockchains is with novel ways to try to solve the scalability problems that current generations of blockchains constantly battle. (Permissionless ones especially. I will return to what separates permissionless and permissioned chains below.)
|
||||
|
||||
The most obvious option—and one of the most fiercely debated one in the Bitcoin community—is "simply" to make the blocks of transactions bigger so that they can handle more transactions per block, and thus per second. Opposing interests in Bitcoin have made this solution very hard to implement (a clear problem with the "governance by code" model I mentioned in my previous article, which I will return to in a future article), but it nonetheless remains a relatively straightforward option for blockchain projects in general. Increasing the frequency at which blocks are created is another one.
|
||||
|
||||
I also mentioned another way to handle more transactions per second in the first article: changing the constraints of the problem. Going from a permissionless network—one that anyone can join and participate in—to a permissioned one—where joining requires permission—changes the constraints and offers the option of reconsidering the security requirements. When you know everyone in a consortium—and have legal ties to them—you can choose to use consensus mechanisms, which don't assume everything should be verified at all times and thus speed things up. Furthermore, permissioned blockchain frameworks, such as Hyperledger Fabric, will typically offer the option to choose the number of transactions contained in a block and their frequency. Whether it's the number of transactions per block or the number of blocks generated that increases, the end result will be an increase in TPS.
|
||||
|
||||
This is how permissioned systems can reach tens of thousands of TPS, numbers far beyond the major permissionless networks. It is also unsurprising, then, that Facebook's recently announced Libra cryptocurrency plans to use a permissioned model (although its "blockchainness" is debated) to handle a high number of transactions, in line with its stated goals.
|
||||
|
||||
### Holding out for consensus
|
||||
|
||||
However, private, permissioned ledgers will not be suited to all use cases. There need to be improvements in general to permissionless networks' capacity to manage more events at a time. This leads us to where the most ambitious work might be happening: consensus mechanisms.
|
||||
|
||||
Getting all participants to come to a consensus on the "truth" of all the transactions (i.e., the changes) that happen on the network and on their order is one of the great difficulties of distributed systems. As a type of distributed system, blockchains inevitably contend with it, too.
|
||||
|
||||
Bitcoin's solution is to organize a race every 10 minutes to solve a computational puzzle and let the winner settle what transactions happened in the last time period and in which order, which everyone else can then easily verify and agree on. By virtue of the kind of puzzle used, the winner is essentially random, but the problem with this "Nakamoto-style proof of work" is that the puzzles used in this race also require horrendously high computational resources to solve (by design), and the work of everyone but the winner is thrown away after each round.
|
||||
|
||||
While it is secure, proof of work is also energy-consuming and slow.
|
||||
|
||||
What we need are better consensus mechanisms that will allow participants of blockchain networks to come to agreement more efficiently, making it possible for the whole system to process more events per second.
|
||||
|
||||
Ethereum, notably, is working on numerous innovations to solve these limitations. First of all, it plans to let go of proof of work to move to a proof of stake consensus mechanism, often referred to as the [Casper protocol][3]. It uses economic incentives and disincentives to get the nodes to secure the network and make cheating (very) costly.
|
||||
|
||||
Another problem a blockchain that can execute smart contracts must contend with is how the execution of code is guaranteed to be correct and what impact this has on the processing capacity of the overall network. Currently, Ethereum requires each validating node to execute the code to verify that the results offered by other nodes are correct. This poses scalability issues, as the greater the success of the Ethereum "world computer," the more code validators need to check: all the nodes need to agree on the order _and_ the validity of each line of code executed and will inevitably be held back by the slowest node.
|
||||
|
||||
One of the options to alleviate this issue is [_sharding_][4], a solution where only part of the network executes the code and returns results the rest of the network can verify.
|
||||
|
||||
Pushing this idea further, [ZEXE][5], a project by the team behind Zcash, deals with this situation by making it possible to submit the result of the execution of code along with a cryptographic proof that the result is correct. Other nodes can then take this proof and check it very quickly without redoing the computation. This, combined with bounties for proving results wrong, creates a system where code can be executed by a single node and checked by many, and it makes for a clever way of speeding up the execution of distributed applications (dapps).
|
||||
|
||||
Consensus in distributed systems is not exactly a new research field, but as blockchains have become popular, there has been renewed interest in consensus research. I could mention many more (Tendermint, Ouroboros, and Algorand come to mind), but I'll offer one other interesting approach regarding consensus: consensus agility. For instance, Hyperledger Sawtooth can [change consensus][6] on the fly, "putting all blockchain configuration on the chain itself." This makes it possible to start a network using a given consensus mechanism and switch to a different, more adapted one when the network and its users have changed, say going from a small-scale deployment to a large consortium.
|
||||
|
||||
This is starting to shed light on an important aspect of the evolution of blockchains: modularity. While the first projects were very tightly integrated, over time, efforts have been made to separate the different layers: networking, consensus, application, and even information storage.
|
||||
|
||||
### Layer 2 solutions: Generation 2.5?
|
||||
|
||||
Solutions baked directly into the blockchain—such as the ones above—are considered to be layer 1. Solutions built on top of a blockchain are called layer 2 solutions.
|
||||
|
||||
These layer 2 solutions, such as the [Lightning Network][7] for Bitcoin or [Raiden][8] for Ethereum, are designed to speed up the overall system by offloading transactions to a secondary network. It's designed to achieve much higher throughput while still connecting to the main blockchain and maintaining its important characteristics: distributed, permissionless, and trust-minimizing. While similar to some degree to sidechains (connecting another system to the main chain, an idea I will return to in the next article), they don't use the idea of a secondary chain. Instead, they build overlay networks that rely on the underlying chain for security and accountability but can exchange information much, much faster and in a peer-to-peer manner.
|
||||
|
||||
Layer 2 solutions are essentially built for cryptocurrencies and create payment tunnels anchored to the underlying cryptocurrency's blockchain, where the amounts exchanged between two parties are eventually settled. By taking most transactions off-chain and alleviating how much needs to happen on the main chain and offloading most transactions to the second layer, they help speed up the entire system.
|
||||
|
||||
### Conclusion
|
||||
|
||||
Speed is the great limiter on the potential of permissionless blockchains. There is a great deal of work going on to explore solutions to this challenge while maintaining the integrity of the chain. Recent research on consensus is leading to new approaches which offer less environmentally unfriendly guarantees on accuracy.
|
||||
|
||||
Open source software is constantly evolving, and as an open source ecosystem, blockchains are a prime example of this reality: Many projects are experimenting with various solutions to shared problems, and these solutions are being studied, refined, and improved by the rest of the community.
|
||||
|
||||
The next installment of this series will examine how current generations of blockchain technologies are trying not just to make individual blockchains more efficient but also capable of working together.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/19/12/blockchain-evolution
|
||||
|
||||
作者:[axel simon][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/axel
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/BUSINESS_twoforward.png?itok=exkV49ts (Arrows moving a process forward)
|
||||
[2]: https://opensource.com/article/18/6/blockchain-guide-next-generation
|
||||
[3]: https://github.com/ethereum/eth2.0-specs/tree/dev/specs/core
|
||||
[4]: https://github.com/ethereum/wiki/wiki/Sharding-FAQ
|
||||
[5]: https://eprint.iacr.org/2018/962.pdf
|
||||
[6]: https://www.hyperledger.org/blog/2017/11/22/un-pluggable-consensus-with-hyperledger-sawtooth
|
||||
[7]: https://lightning.network/
|
||||
[8]: https://raiden.network/
|
@ -1,5 +1,5 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: translator: (lxbwolf)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
@ -7,34 +7,31 @@
|
||||
[#]: via: (https://opensource.com/article/19/10/programming-bash-loops)
|
||||
[#]: author: (David Both https://opensource.com/users/dboth)
|
||||
|
||||
How to program with Bash: Loops
|
||||
Bash 编程教程之循环
|
||||
======
|
||||
Learn how to use loops for performing iterative operations, in the final
|
||||
article in this three-part series on programming with Bash.
|
||||
本文是 bash 编程系列(3 部分)的最后一篇,来学习使用循环执行迭代的操作。
|
||||
![arrows cycle symbol for failing faster][1]
|
||||
|
||||
Bash is a powerful programming language, one perfectly designed for use on the command line and in shell scripts. This three-part series, based on my [three-volume Linux self-study course][2], explores using Bash as a programming language on the command-line interface (CLI).
|
||||
Bash 是一种强大的用于命令行和 shell 脚本里的编程语言。本系列的三部分都是基于我的 [Linux 自学课程三卷][2] 写的,探索怎么用 CLI(command-line interface)进行 bash 编程。本系列的 [第一篇文章][3] 讨论了 bash 编程的一些简单命令行操作,如使用变量和控制操作符。[第二篇文章][4] 探讨了文件、字符串、数字等类型和各种各样在执行流中提供控制逻辑的的逻辑运算符,还有 bash 中不同种类的扩展。本文是第三篇(也是最后一篇),意在考察在各种迭代的操作中使用循环以及怎么合理控制循环。
|
||||
|
||||
The [first article][3] in this series explored some simple command-line programming with Bash, including using variables and control operators. The [second article][4] looked into the types of file, string, numeric, and miscellaneous logical operators that provide execution-flow control logic and different types of shell expansions in Bash. This third (and final) article examines the use of loops for performing various types of iterative operations and ways to control those loops.
|
||||
### 循环
|
||||
|
||||
### Loops
|
||||
我使用过的所有编程语言都有很多种循环结构来用来执行重复的操作。我经常使用 for 循环,然而我发现 while 和 until 循环也很有用处。
|
||||
|
||||
Every programming language I have ever used has at least a couple types of loop structures that provide various capabilities to perform repetitive operations. I use the for loop quite often but I also find the while and until loops useful.
|
||||
#### for 循环
|
||||
|
||||
#### for loops
|
||||
我的理解是,**for** 命令在 bash 中的实现比大部分语言灵活,因为它可以处理非数字的值;与之形成对比的是,诸如标准 C 语言的 **for** 循环只能处理数字类型的值。
|
||||
|
||||
Bash's implementation of the **for** command is, in my opinion, a bit more flexible than most because it can handle non-numeric values; in contrast, for example, the standard C language **for** loop can deal only with numeric values.
|
||||
|
||||
The basic structure of the Bash version of the **for** command is simple:
|
||||
Bash 版的 **for** 命令基本的结构很简单:
|
||||
|
||||
|
||||
```
|
||||
`for Var in list1 ; do list2 ; done`
|
||||
```
|
||||
|
||||
This translates to: "For each value in list1, set the **$Var** to that value and then perform the program statements in list2 using that value; when all of the values in list1 have been used, it is finished, so exit the loop." The values in list1 can be a simple, explicit string of values, or they can be the result of a command substitution (described in the second article in the series). I use this construct frequently.
|
||||
解释一下:“对于 list1 中的每一个值,把 **$Var** 设置为那个值,使用该值执行 list2 中的程序语句;list1 中的值都执行完后,整个循环结束,退出循环。” list1 中的值可以是一个简单的显式字符串值,也可以是一个命令执行后的结果(译注:**\` \`** 包含的命令执行的结果,本系列第二篇文章中有描述)。我经常使用这种结构。
|
||||
|
||||
To try it, ensure that **~/testdir** is still the present working directory (PWD). Clean up the directory, then look at a trivial example of the **for** loop starting with an explicit list of values. This list is a mix of alphanumeric values—but do not forget that all variables are strings and can be treated as such.
|
||||
确认 **~/testdir** 仍然是当前的工作目录(PWD)。删除目录下所有东西,来看下这个显式写出值列表的 **for** 循环的简单的示例。这个列表中的值是字母值 — 但是不要忘了,在 bash 中所有的变量都是 string 或者可以被当成 string 来处理。
|
||||
|
||||
|
||||
```
|
||||
@ -50,7 +47,7 @@ d
|
||||
4
|
||||
```
|
||||
|
||||
Here is a bit more useful version with a more meaningful variable name:
|
||||
给变量赋予更有意义的名字,变成前面版本的进阶版:
|
||||
|
||||
|
||||
```
|
||||
@ -64,7 +61,7 @@ Department Administration
|
||||
Department Research
|
||||
```
|
||||
|
||||
Make some directories (and show some progress information while doing so):
|
||||
创建几个目录(创建时显示一些处理信息):
|
||||
|
||||
|
||||
```
|
||||
@ -87,9 +84,9 @@ drwxrwxr-x 2 student student 4096 Apr 8 15:45 Research
|
||||
drwxrwxr-x 2 student student 4096 Apr 8 15:45 Sales
|
||||
```
|
||||
|
||||
The **$Dept** variable must be enclosed in quotes in the **mkdir** statement; otherwise, two-part department names (such as "Information Technology") will be treated as two separate departments. That highlights a best practice I like to follow: all file and directory names should be a single word. Although most modern operating systems can deal with spaces in names, it takes extra work for sysadmins to ensure that those special cases are considered in scripts and CLI programs. (They almost certainly should be considered, even if they're annoying because you never know what files you will have.)
|
||||
在 **mkdir** 语句中 **$Dept** 变量必须用引号包裹起来;否则名字中间有空格(如 `Information Technology`)会被当做两个独立的目录处理。我一直信奉的一条实践规则:所有的文件和目录都应该为一个单词(中间没有空格)。虽然大部分现代的操作系统可以处理名字中间有空格的情况,但是系统管理员需要花费额外的精力去确保脚本和 CLI 程序能正确处理这些特例。(尽管你因为不知道将要处理什么样的文件而烦恼,但是脚本和 CLI 应该已经把这些特例考虑在内了。)
|
||||
|
||||
So, delete everything in **~/testdir**—again—and do this one more time:
|
||||
再次删除 **~/testdir** 下的所有东西 — 再运行一次下面的命令:
|
||||
|
||||
|
||||
```
|
||||
@ -114,11 +111,9 @@ drwxrwxr-x 2 student student 4096 Apr 8 15:52 Research
|
||||
drwxrwxr-x 2 student student 4096 Apr 8 15:52 Sales
|
||||
```
|
||||
|
||||
Suppose someone asks for a list of all RPMs on a particular Linux computer and a short description of each. This happened to me when I worked for the State of North Carolina. Since open source was not "approved" for use by state agencies at that time, and I only used Linux on my desktop computer, the pointy-haired bosses (PHBs) needed a list of each piece of software that was installed on my computer so that they could "approve" an exception.
|
||||
假设现在有个需求,需要列出一台 Linux 机器上所有的 RPM 包并对每个包附上简短的描述。我为North Carolina 州工作的时候,曾经遇到过这种需求。由于当时州代理处不允许使用开源的工具,而且我对 Linux 不够熟悉,对技术一窍不通的老板(PHB)需要我列出我计算机上安装的所有软件,这样他们就可以“查看“计算机上有没有安装异常的软件了。
|
||||
|
||||
How would you approach that? Here is one way, starting with the knowledge that the **rpm –qa** command provides a complete description of an RPM, including the two items the PHBs want: the software name and a brief summary.
|
||||
|
||||
Build up to the final result one step at a time. First, list all RPMs:
|
||||
你怎么实现它?有一种方法是,已知 **rpm –qa** 命令提供了 RPM 包的完整描述,包括 PHB 想要的东西:软件名称和概要描述。一步步执行出最后的结果。首先,列出所有的 RPM 包:
|
||||
|
||||
|
||||
```
|
||||
@ -136,7 +131,7 @@ libfontenc-1.1.3-9.fc29.x86_64
|
||||
<snip>
|
||||
```
|
||||
|
||||
Add the **sort** and **uniq** commands to sort the list and print the unique ones (since it's possible that some RPMs with identical names are installed):
|
||||
用 **sort** 和 **uniq** 命令对列表进行排序和打印去重后的结果(有些已安装的 RPM 包具有相同的名字:)
|
||||
|
||||
|
||||
```
|
||||
@ -154,14 +149,14 @@ abrt-addon-vmcore-2.11.0-1.fc29.x86_64
|
||||
<snip>
|
||||
```
|
||||
|
||||
Since this gives the correct list of RPMs you want to look at, you can use this as the input list to a loop that will print all the details of each RPM:
|
||||
以上命令得到了想要的 RPM 列表,因此你可以把这个列表作为一个循环的输入信息,循环最终会打印每个 RPM 包的详细信息:
|
||||
|
||||
|
||||
```
|
||||
`[student@studentvm1 testdir]$ for RPM in `rpm -qa | sort | uniq` ; do rpm -qi $RPM ; done`
|
||||
[student@studentvm1 testdir]$ for RPM in `rpm -qa | sort | uniq` ; do rpm -qi $RPM ; done
|
||||
```
|
||||
|
||||
This code produces way more data than you want. Note that the loop is complete. The next step is to extract only the information the PHBs requested. So, add an **egrep** command, which is used to select **^Name** or **^Summary**. The carat (**^**) specifies the beginning of the line; thus, any line with Name or Summary at the beginning of the line is displayed.
|
||||
这段代码产出了多余的信息。当循环结束后, 下一步就是提取出 PHB 需要的信息。因此,添加一个 **egrep** 命令用来搜索匹配 **^Name** 或 **^Summary** 的行。脱字符(^)表示行首,整个命令表示显示所有以 Name 或 Summary 开头的行。
|
||||
|
||||
|
||||
```
|
||||
@ -179,42 +174,38 @@ Summary : Automatic bug detection and reporting tool
|
||||
<snip>
|
||||
```
|
||||
|
||||
You can try **grep** instead of **egrep** in the command above, but it will not work. You could also pipe the output of this command through the **less** filter to explore the results. The final command sequence looks like this:
|
||||
在上面的命令中你可以试试用 **grep** 代替 **egrep** ,你会发现用 **grep** 不能得到正确的结果。你可以通过管道把命令结果用 **less** 过滤下。最终命令像这样:
|
||||
|
||||
|
||||
```
|
||||
`[student@studentvm1 testdir]$ for RPM in `rpm -qa | sort | uniq` ; do rpm -qi $RPM ; done | egrep -i "^Name|^Summary" > RPM-summary.txt`
|
||||
[student@studentvm1 testdir]$ for RPM in `rpm -qa | sort | uniq` ; do rpm -qi $RPM ; done | egrep -i "^Name|^Summary" > RPM-summary.txt
|
||||
```
|
||||
|
||||
This command-line program uses pipelines, redirection, and a **for** loop—all on a single line. It redirects the output of your little CLI program to a file that can be used in an email or as input for other purposes.
|
||||
这个命令行程序在同一行中用到了管道、重定向和 **for** 循环。它把你 CLI 程序的结果重定向到了一个文件,这个文件可以在邮件中使用或在其他地方作为输入使用。这个一次一步构建程序的过程让你能看到每步的结果,以此来确保整个程序以你期望的流程进行且输出你想要的结果。
|
||||
|
||||
This process of building up the program one step at a time allows you to see the results of each step and ensure that it is working as you expect and provides the desired results.
|
||||
PHB 最终收到了超过 1900 个独立 RPM 包的清单,我严重怀疑根本就没人去读它。我给了他们想要的东西,没有从他们嘴里听到过任何关于 RPM 包的信息。
|
||||
|
||||
From this exercise, the PHBs received a list of over 1,900 separate RPM packages. I seriously doubt that anyone read that list. But I gave them exactly what they asked for, and I never heard another word from them about it.
|
||||
### 其他循环
|
||||
|
||||
### Other loops
|
||||
|
||||
There are two more types of loop structures available in Bash: the **while** and **until** structures, which are very similar to each other in both syntax and function. The basic syntax of these loop structures is simple:
|
||||
Bash 中还有两种其他类型的循环结构:**while** 和 **until** 结构,两者在语法和功能上都类似。这些循环结构的基础语法很简单:
|
||||
|
||||
|
||||
```
|
||||
`while [ expression ] ; do list ; done`
|
||||
while [ expression ] ; do list ; done
|
||||
```
|
||||
|
||||
and
|
||||
逻辑解释:表达式(expression)结果为 true 时,执行程序语句 `list`。表达式结果为 false 时,退出循环。
|
||||
|
||||
|
||||
```
|
||||
`until [ expression ] ; do list ; done`
|
||||
until [ expression ] ; do list ; done
|
||||
```
|
||||
|
||||
The logic of the first reads: "While the expression evaluates as true, execute the list of program statements. When the expression evaluates as false, exit from the loop." And the second: "Until the expression evaluates as true, execute the list of program statements. When the expression evaluates as true, exit from the loop."
|
||||
逻辑解释:直到表达式的结果为 true,执行程序语句 `list`。当表达式结果为 true 时,退出循环。
|
||||
|
||||
#### While loop
|
||||
#### While 循环
|
||||
|
||||
The **while** loop is used to execute a series of program statements while (so long as) the logical expression evaluates as true. Your PWD should still be **~/testdir**.
|
||||
|
||||
The simplest form of the **while** loop is one that runs forever. The following form uses the true statement to always generate a "true" return code. You could also use a simple "1"—and that would work just the same—but this illustrates the use of the true statement:
|
||||
**while** 循环用于当逻辑表达式结果为 true 时执行一系列程序语句。假设你的 PWD 仍是 **~/testdir** 。最简单的 **while** 循环会一直运行下去。下面格式的条件语句永远以 `true` 作为返回。你也可以用简单的 `1` 代替 `true` — 结果一样 — 但是这解释了 true 表达式的用法。
|
||||
|
||||
|
||||
```
|
||||
@ -232,9 +223,9 @@ The simplest form of the **while** loop is one that runs forever. The following
|
||||
[student@studentvm1 testdir]$
|
||||
```
|
||||
|
||||
This CLI program should make more sense now that you have studied its parts. First, it sets **$X** to zero in case it has a value left over from a previous program or CLI command. Then, since the logical expression **[ true ]** always evaluates to 1, which is true, the list of program instructions between **do** and **done** is executed forever—or until you press **Ctrl+C** or otherwise send a signal 2 to the program. Those instructions are an arithmetic expansion that prints the current value of **$X** and then increments it by one.
|
||||
既然你已经学了 CLI 的各部分知识,那就让它变得更有用处。首先,为了防止变量 **$X** 在前面的程序或 CLI 命令执行后有遗留的值,设置 **$X** 的值为 0。然后,因为逻辑表达式 **[ true ]** 的结果永远是 1,即 true,在 **do** 和 **done** 中间的程序指令列表会一直执行 — 或者直到你按下 **Ctrl+C** 抑或发送一个 `signal 2` 给程序。那些程序指令是算法扩展,用来打印变量 **$X** 当前的值并加 1.
|
||||
|
||||
One of the tenets of [_The Linux Philosophy for Sysadmins_][5] is to strive for elegance, and one way to achieve elegance is simplicity. You can simplify this program by using the variable increment operator, **++**. In the first instance, the current value of the variable is printed, and then the variable is incremented. This is indicated by placing the **++** operator after the variable:
|
||||
[系统管理员的 Linux 哲学][5] 的信条之一是追求优雅,实现优雅的一种方式就是简化。你可以用操作符 **++** 来简化这个程序。在第一个例子中,变量当前的值被打印出来,然后变量的值增加了。可以在变量后加一个 **++** 来表示这个逻辑:
|
||||
|
||||
|
||||
```
|
||||
@ -251,9 +242,7 @@ One of the tenets of [_The Linux Philosophy for Sysadmins_][5] is to strive for
|
||||
9
|
||||
```
|
||||
|
||||
Now delete **| head** from the end of the program and run it again.
|
||||
|
||||
In this version, the variable is incremented before its value is printed. This is specified by placing the **++** operator before the variable. Can you see the difference?
|
||||
现在删掉程序最后的 **| head** 再运行一次。在这个版本中,变量在值被打印之前就自增了。这是通过在变量之前添加 **++** 操作符实现的。你能看出区别吗?
|
||||
|
||||
|
||||
```
|
||||
@ -269,9 +258,7 @@ In this version, the variable is incremented before its value is printed. This i
|
||||
9
|
||||
```
|
||||
|
||||
You have reduced two statements into a single one that prints the value of the variable and increments that value. There is also a decrement operator, **\--**.
|
||||
|
||||
You need a method for stopping the loop at a specific number. To accomplish that, change the true expression to an actual numeric evaluation expression. Have the program loop to 5 and stop. In the example code below, you can see that **-le** is the logical numeric operator for "less than or equal to." This means: "So long as **$X** is less than or equal to 5, the loop will continue. When **$X** increments to 6, the loop terminates."
|
||||
你已经把打印变量的值和自增简化到了一条语句。类似 **++** 操作符, 也有 **--** 操作符。你需要一个在循环到某个特定数字时终止循环的方法。把 true 表达式换成一个数字比较表达式来实现它。写一个循环到 5 终止的程序。在下面的示例代码中,你可以看到 **-le** 是 ”小于或等于“ 的数字逻辑操作符。整个语句的意思:只要 **$X** 的值小于或等于 5,循环就一直运行。当 **$X** 增加到 6时,循环终止。
|
||||
|
||||
|
||||
```
|
||||
@ -285,9 +272,11 @@ You need a method for stopping the loop at a specific number. To accomplish that
|
||||
[student@studentvm1 ~]$
|
||||
```
|
||||
|
||||
#### Until loop
|
||||
#### Until 循环
|
||||
|
||||
The **until** command is very much like the **while** command. The difference is that it will continue to loop until the logical expression evaluates to "true." Look at the simplest form of this construct:
|
||||
|
||||
|
||||
*until** 命令非常像 **while** 命令。不同之处是,它直到逻辑表达式的值是 `true` 之前,会一直循环。看一下这种结构最简单的格式:
|
||||
|
||||
|
||||
```
|
||||
@ -305,7 +294,7 @@ The **until** command is very much like the **while** command. The difference is
|
||||
[student@studentvm1 ~]$
|
||||
```
|
||||
|
||||
It uses a logical comparison to count to a specific value:
|
||||
它用一个逻辑比较表达式来数到一个特定的值:
|
||||
|
||||
|
||||
```
|
||||
@ -324,13 +313,9 @@ It uses a logical comparison to count to a specific value:
|
||||
[student@studentvm1 ~]$
|
||||
```
|
||||
|
||||
### Summary
|
||||
### 总结:
|
||||
|
||||
This series has explored many powerful tools for building Bash command-line programs and shell scripts. But it has barely scratched the surface on the many interesting things you can do with Bash; the rest is up to you.
|
||||
|
||||
I have discovered that the best way to learn Bash programming is to do it. Find a simple project that requires multiple Bash commands and make a CLI program out of them. Sysadmins do many tasks that lend themselves to CLI programming, so I am sure that you will easily find tasks to automate.
|
||||
|
||||
Many years ago, despite being familiar with other shell languages and Perl, I made the decision to use Bash for all of my sysadmin automation tasks. I have discovered that—sometimes with a bit of searching—I have been able to use Bash to accomplish everything I need.
|
||||
本系列探讨了构建 bash 命令行程序和 shell 脚本的很多强大的工具。但是这仅仅是你能用 Bash 做的很多有意思的事中的冰山一角,接下来就看你的了。我发现学习 Bash 编程最好的方法就是实践。找一个需要多个 Bash 命令的简单项目然后写一个 CLI 程序。系统管理员们做了很多工作让任务变成 CLI 编程,因此我确信你很容易能找到自动化的任务。很多年前,尽管我对其他的 Shell 语言和 Perl 很熟悉,但还是决定用 Bash 做所有系统管理员的自动化任务。我发现 — 有时稍微搜索一下 — 我可以用 Bash 实现我需要的所有事情。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
@ -338,7 +323,7 @@ via: https://opensource.com/article/19/10/programming-bash-loops
|
||||
|
||||
作者:[David Both][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
译者:[lxbwolf](https://github.com/lxbwolf)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
@ -1,243 +0,0 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (How to remove duplicate lines from files with awk)
|
||||
[#]: via: (https://opensource.com/article/19/10/remove-duplicate-lines-files-awk)
|
||||
[#]: author: (Lazarus Lazaridis https://opensource.com/users/iridakos)
|
||||
|
||||
How to remove duplicate lines from files with awk
|
||||
======
|
||||
Learn how to use awk '!visited[$0]++' without sorting or changing their
|
||||
order.
|
||||
![Coding on a computer][1]
|
||||
|
||||
Suppose you have a text file and you need to remove all of its duplicate lines.
|
||||
|
||||
### TL;DR
|
||||
|
||||
To remove the duplicate lines while _preserving their order in the file_, use:
|
||||
|
||||
|
||||
```
|
||||
`awk '!visited[$0]++' your_file > deduplicated_file`
|
||||
```
|
||||
|
||||
### How it works
|
||||
|
||||
The script keeps an associative array with _indices_ equal to the unique lines of the file and _values_ equal to their occurrences. For each line of the file, if the line occurrences are zero, then it increases them by one and _prints the line_, otherwise, it just increases the occurrences _without printing the line_.
|
||||
|
||||
I was not familiar with **awk**, and I wanted to understand how this can be accomplished with such a short script (**awk**ward). I did my research, and here is what is going on:
|
||||
|
||||
* The awk "script" **!visited[$0]++** is executed for _each line_ of the input file.
|
||||
* **visited[]** is a variable of type [associative array][2] (a.k.a. [Map][3]). We don't have to initialize it because **awk** will do it the first time we access it.
|
||||
* The **$0** variable holds the contents of the line currently being processed.
|
||||
* **visited[$0]** accesses the value stored in the map with a key equal to **$0** (the line being processed), a.k.a. the occurrences (which we set below).
|
||||
* The **!** negates the occurrences' value:
|
||||
* In awk, [any nonzero numeric value or any nonempty string value is true][4].
|
||||
* By default, [variables are initialized to the empty string][5], which is zero if converted to a number.
|
||||
* That being said:
|
||||
* If **visited[$0]** returns a number greater than zero, this negation is resolved to **false**.
|
||||
* If **visited[$0]** returns a number equal to zero or an empty string, this negation is resolved to **true**.
|
||||
* The **++** operation increases the variable's value (**visited[$0]**) by one.
|
||||
* If the value is empty, **awk** converts it to **0** (number) automatically and then it gets increased.
|
||||
* **Note:** The operation is executed after we access the variable's value.
|
||||
|
||||
|
||||
|
||||
Summing up, the whole expression evaluates to:
|
||||
|
||||
* **true** if the occurrences are zero/empty string
|
||||
* **false** if the occurrences are greater than zero
|
||||
|
||||
|
||||
|
||||
**awk** statements consist of a [_pattern-expression_ and an _associated action_][6].
|
||||
|
||||
|
||||
```
|
||||
`<pattern/expression> { <action> }`
|
||||
```
|
||||
|
||||
If the pattern succeeds, then the associated action is executed. If we don't provide an action, **awk**, by default, **print**s the input.
|
||||
|
||||
> An omitted action is equivalent to **{ print $0 }**.
|
||||
|
||||
Our script consists of one **awk** statement with an expression, omitting the action. So this:
|
||||
|
||||
|
||||
```
|
||||
`awk '!visited[$0]++' your_file > deduplicated_file`
|
||||
```
|
||||
|
||||
is equivalent to this:
|
||||
|
||||
|
||||
```
|
||||
`awk '!visited[$0]++ { print $0 }' your_file > deduplicated_file`
|
||||
```
|
||||
|
||||
For every line of the file, if the expression succeeds, the line is printed to the output. Otherwise, the action is not executed, and nothing is printed.
|
||||
|
||||
### Why not use the **uniq** command?
|
||||
|
||||
The **uniq** command removes only the _adjacent duplicate lines_. Here's a demonstration:
|
||||
|
||||
|
||||
```
|
||||
$ cat test.txt
|
||||
A
|
||||
A
|
||||
A
|
||||
B
|
||||
B
|
||||
B
|
||||
A
|
||||
A
|
||||
C
|
||||
C
|
||||
C
|
||||
B
|
||||
B
|
||||
A
|
||||
$ uniq < test.txt
|
||||
A
|
||||
B
|
||||
A
|
||||
C
|
||||
B
|
||||
A
|
||||
```
|
||||
|
||||
### Other approaches
|
||||
|
||||
#### Using the sort command
|
||||
|
||||
We can also use the following [**sort**][7] command to remove the duplicate lines, but _the line order is not preserved_.
|
||||
|
||||
|
||||
```
|
||||
`sort -u your_file > sorted_deduplicated_file`
|
||||
```
|
||||
|
||||
#### Using cat, sort, and cut
|
||||
|
||||
The previous approach would produce a de-duplicated file whose lines would be sorted based on the contents. [Piping a bunch of commands][8] can overcome this issue:
|
||||
|
||||
|
||||
```
|
||||
`cat -n your_file | sort -uk2 | sort -nk1 | cut -f2-`
|
||||
```
|
||||
|
||||
##### How it works
|
||||
|
||||
Suppose we have the following file:
|
||||
|
||||
|
||||
```
|
||||
abc
|
||||
ghi
|
||||
abc
|
||||
def
|
||||
xyz
|
||||
def
|
||||
ghi
|
||||
klm
|
||||
```
|
||||
|
||||
**cat -n test.txt** prepends the order number in each line.
|
||||
|
||||
|
||||
```
|
||||
1 abc
|
||||
2 ghi
|
||||
3 abc
|
||||
4 def
|
||||
5 xyz
|
||||
6 def
|
||||
7 ghi
|
||||
8 klm
|
||||
```
|
||||
|
||||
**sort -uk2** sorts the lines based on the second column (**k2** option) and keeps only the first occurrence of the lines with the same second column value (**u** option).
|
||||
|
||||
|
||||
```
|
||||
1 abc
|
||||
4 def
|
||||
2 ghi
|
||||
8 klm
|
||||
5 xyz
|
||||
```
|
||||
|
||||
**sort -nk1** sorts the lines based on their first column (**k1** option) treating the column as a number (**-n** option).
|
||||
|
||||
|
||||
```
|
||||
1 abc
|
||||
2 ghi
|
||||
4 def
|
||||
5 xyz
|
||||
8 klm
|
||||
```
|
||||
|
||||
Finally, **cut -f2-** prints each line starting from the second column until its end (**-f2-** option: _Note the **-** suffix, which instructs it to include the rest of the line_).
|
||||
|
||||
|
||||
```
|
||||
abc
|
||||
ghi
|
||||
def
|
||||
xyz
|
||||
klm
|
||||
```
|
||||
|
||||
### References
|
||||
|
||||
* [The GNU awk user's guide][9]
|
||||
* [Arrays in awk][2]
|
||||
* [Awk—Truth values][4]
|
||||
* [Awk expressions][5]
|
||||
* [How can I delete duplicate lines in a file in Unix?][10]
|
||||
* [Remove duplicate lines without sorting [duplicate]][11]
|
||||
* [How does awk '!a[$0]++' work?][12]
|
||||
|
||||
|
||||
|
||||
That's all. Cat photo.
|
||||
|
||||
![Duplicate cat][13]
|
||||
|
||||
* * *
|
||||
|
||||
_This article originally appeared on the iridakos blog by [Lazarus Lazaridis][14] under a [CC BY-NC 4.0 License][15] and is republished with the author's permission._
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/19/10/remove-duplicate-lines-files-awk
|
||||
|
||||
作者:[Lazarus Lazaridis][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/iridakos
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/code_computer_laptop_hack_work.png?itok=aSpcWkcl (Coding on a computer)
|
||||
[2]: http://kirste.userpage.fu-berlin.de/chemnet/use/info/gawk/gawk_12.html
|
||||
[3]: https://en.wikipedia.org/wiki/Associative_array
|
||||
[4]: https://www.gnu.org/software/gawk/manual/html_node/Truth-Values.html
|
||||
[5]: https://ftp.gnu.org/old-gnu/Manuals/gawk-3.0.3/html_chapter/gawk_8.html
|
||||
[6]: http://kirste.userpage.fu-berlin.de/chemnet/use/info/gawk/gawk_9.html
|
||||
[7]: http://man7.org/linux/man-pages/man1/sort.1.html
|
||||
[8]: https://stackoverflow.com/a/20639730/2292448
|
||||
[9]: https://www.gnu.org/software/gawk/manual/html_node/
|
||||
[10]: https://stackoverflow.com/questions/1444406/how-can-i-delete-duplicate-lines-in-a-file-in-unix
|
||||
[11]: https://stackoverflow.com/questions/11532157/remove-duplicate-lines-without-sorting
|
||||
[12]: https://unix.stackexchange.com/questions/159695/how-does-awk-a0-work/159734#159734
|
||||
[13]: https://opensource.com/sites/default/files/uploads/duplicate-cat.jpg (Duplicate cat)
|
||||
[14]: https://iridakos.com/about/
|
||||
[15]: http://creativecommons.org/licenses/by-nc/4.0/
|
@ -1,212 +0,0 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (How to port an awk script to Python)
|
||||
[#]: via: (https://opensource.com/article/19/11/awk-to-python)
|
||||
[#]: author: (Moshe Zadka https://opensource.com/users/moshez)
|
||||
|
||||
How to port an awk script to Python
|
||||
======
|
||||
Porting an awk script to Python is more about code style than
|
||||
transliteration.
|
||||
![Woman sitting in front of her laptop][1]
|
||||
|
||||
Scripts are potent ways to solve a problem repeatedly, and awk is an excellent language for writing them. It excels at easy text processing in particular, and it can bring you through some complicated rewriting of config files or reformatting file names in a directory.
|
||||
|
||||
### When to move from awk to Python
|
||||
|
||||
At some point, however, awk's limitations start to show. It has no real concept of breaking files into modules, it lacks quality error reporting, and it's missing other things that are now considered fundamentals of how a language works. When these rich features of a programming language are helpful to maintain a critical script, porting becomes a good option.
|
||||
|
||||
My favorite modern programming language that is perfect for porting awk is Python.
|
||||
|
||||
Before porting an awk script to Python, it is often worthwhile to consider its original context. For example, because of awk's limitations, the awk code is commonly called from a Bash script and includes some calls to other command-line favorites like sed, sort, and the gang. It's best to convert all of it into one coherent Python program. Other times, the script makes overly broad assumptions; for example, the code might allow for any number of files, even though it's run with only one in practice.
|
||||
|
||||
After carefully considering the context and determining the thing to substitute with Python, it is time to write code.
|
||||
|
||||
### Standard awk to Python functionality
|
||||
|
||||
The following Python functionality is useful to remember:
|
||||
|
||||
|
||||
```
|
||||
with open(some_file_name) as fpin:
|
||||
for line in fpin:
|
||||
pass # do something with line
|
||||
```
|
||||
|
||||
This code will loop through a file line-by-line and process the lines.
|
||||
|
||||
If you want to access a line number (equivalent to awk's **NR**), you can use the following code:
|
||||
|
||||
|
||||
```
|
||||
with open(some_file_name) as fpin:
|
||||
for nr, line in enumerate(fpin):
|
||||
pass # do something with line
|
||||
```
|
||||
|
||||
### awk-like behavior over multiple files in Python
|
||||
|
||||
If you need to be able to iterate through any number of files while keeping a persistent count of the number of lines (like awk's **FNR**), this loop can do it:
|
||||
|
||||
|
||||
```
|
||||
def awk_like_lines(list_of_file_names):
|
||||
def _all_lines():
|
||||
for filename in list_of_file_names:
|
||||
with open(filename) as fpin:
|
||||
yield from fpin
|
||||
yield from enumerate(_all_lines())
|
||||
```
|
||||
|
||||
This syntax uses Python's _generators_ and **yield from** to build an _iterator_ that loops through all lines and keeps a persistent count.
|
||||
|
||||
If you need the equivalent of both **FNR** and **NR**, here is a more sophisticated loop:
|
||||
|
||||
|
||||
```
|
||||
def awk_like_lines(list_of_file_names):
|
||||
def _all_lines():
|
||||
for filename in list_of_file_names:
|
||||
with open(filename) as fpin:
|
||||
yield from enumerate(fpin)
|
||||
for nr, (fnr, line) in _all_lines:
|
||||
yield nr, fnr, line
|
||||
```
|
||||
|
||||
### More complex awk functionality with FNR, NR, and line
|
||||
|
||||
The question remains if you need all three: **FNR**, **NR**, and **line**. If you really do, using a three-tuple where two of the items are numbers can lead to confusion. Named parameters can make this code easier to read, so it's better to use a **dataclass**:
|
||||
|
||||
|
||||
```
|
||||
import dataclass
|
||||
|
||||
@dataclass.dataclass(frozen=True)
|
||||
class AwkLikeLine:
|
||||
content: str
|
||||
fnr: int
|
||||
nr: int
|
||||
|
||||
def awk_like_lines(list_of_file_names):
|
||||
def _all_lines():
|
||||
for filename in list_of_file_names:
|
||||
with open(filename) as fpin:
|
||||
yield from enumerate(fpin)
|
||||
for nr, (fnr, line) in _all_lines:
|
||||
yield AwkLikeLine(nr=nr, fnr=fnr, line=line)
|
||||
```
|
||||
|
||||
You might wonder, why not start with this approach? The reason to start elsewhere is that this is almost always too complicated. If your goal is to make a generic library that makes porting awk to Python easier, then consider doing so. But writing a loop that gets you exactly what you need for a specific case is usually easier to do and easier to understand (and thus maintain).
|
||||
|
||||
### Understanding awk fields
|
||||
|
||||
Once you have a string that corresponds to a line, if you are converting an awk program, you often want to break it up into _fields_. Python has several ways of doing that. This will return a list of strings, splitting the line on any number of consecutive whitespaces:
|
||||
|
||||
|
||||
```
|
||||
`line.split()`
|
||||
```
|
||||
|
||||
If another field separator is needed, something like this will split the line by **:**; the **rstrip** method is needed to remove the last newline:
|
||||
|
||||
|
||||
```
|
||||
`line.rstrip("\n").split(":")`
|
||||
```
|
||||
|
||||
After doing the following, the list **parts** will have the broken-up string:
|
||||
|
||||
|
||||
```
|
||||
`parts = line.rstrip("\n").split(":")`
|
||||
```
|
||||
|
||||
This split is good for choosing what to do with the parameters, but we are in an [off-by-one error][2] scenario. Now **parts[0]** will correspond to awk's **$1**, **parts[1]** will correspond to awk's **$2**, etc. This off-by-one is because awk starts counting the "fields" from 1, while Python counts from 0. In awk's **$0** is the whole line -- equivalent to **line.rstrip("\n") **and awk's **NF** (number of fields) is more easily retrieved as **len(parts)**.
|
||||
|
||||
### Porting awk fields in Python
|
||||
|
||||
As an example, let's convert the one-liner from "[How to remove duplicate lines from files with awk][3]" to Python.
|
||||
|
||||
The original in awk is:
|
||||
|
||||
|
||||
```
|
||||
`awk '!visited[$0]++' your_file > deduplicated_file`
|
||||
```
|
||||
|
||||
An "authentic" Python conversion would be:
|
||||
|
||||
|
||||
```
|
||||
import collections
|
||||
import sys
|
||||
|
||||
visited = collections.defaultdict(int)
|
||||
for line in open("your_file"):
|
||||
did_visit = visited[line]
|
||||
visited[line] += 1
|
||||
if not did_visit:
|
||||
sys.stdout.write(line)
|
||||
```
|
||||
|
||||
However, Python has more data structures than awk. Instead of _counting_ visits (which we do not use, except to know whether we saw a line), why not record the visited lines?
|
||||
|
||||
|
||||
```
|
||||
import sys
|
||||
|
||||
visited = set()
|
||||
for line in open("your_file"):
|
||||
if line in visited:
|
||||
continue
|
||||
visited.add(line)
|
||||
sys.stdout.write(line)
|
||||
```
|
||||
|
||||
### Making Pythonic awk code
|
||||
|
||||
The Python community advocates for writing Pythonic code, which means it follows a commonly agreed-upon code style. An even more Pythonic approach will separate the concerns of _uniqueness_ and _input/output_. This change would make it easier to unit test your code:
|
||||
|
||||
|
||||
```
|
||||
def unique_generator(things):
|
||||
visited = set()
|
||||
for thing in things:
|
||||
if thing in visited:
|
||||
continue
|
||||
visited.add(things)
|
||||
yield thing
|
||||
|
||||
import sys
|
||||
|
||||
for line in unique_generator(open("your_file")):
|
||||
sys.stdout.write(line)
|
||||
```
|
||||
|
||||
Putting all logic away from the input/output code leads to better separation of concerns and more usability and testability of code.
|
||||
|
||||
### Conclusion: Python can be a good choice
|
||||
|
||||
Porting an awk script to Python is often more a matter of reimplementing the core requirements while thinking about proper Pythonic code style than a slavish transliteration of condition/action by condition/action. Take the original context into account and produce a quality Python solution. While there are times when a Bash one-liner with awk can get the job done, Python coding is a path toward more easily maintainable code.
|
||||
|
||||
Also, if you're writing awk scripts, I am confident you can learn Python as well! Let me know if you have any questions in the comments.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/19/11/awk-to-python
|
||||
|
||||
作者:[Moshe Zadka][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/moshez
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/OSDC_women_computing_4.png?itok=VGZO8CxT (Woman sitting in front of her laptop)
|
||||
[2]: https://en.wikipedia.org/wiki/Off-by-one_error
|
||||
[3]: https://opensource.com/article/19/10/remove-duplicate-lines-files-awk
|
@ -1,64 +0,0 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Use the Window Maker desktop on Linux)
|
||||
[#]: via: (https://opensource.com/article/19/12/linux-window-maker-desktop)
|
||||
[#]: author: (Seth Kenlon https://opensource.com/users/seth)
|
||||
|
||||
Use the Window Maker desktop on Linux
|
||||
======
|
||||
This article is part of a special series of 24 days of Linux desktops.
|
||||
Take a step back in time with Window Maker, which implements the old
|
||||
Unix NeXTSTEP environment for today's users.
|
||||
![Penguin with green background][1]
|
||||
|
||||
Before Mac OS X, there was a quirky closed-source Unix system called [NeXTSTEP][2]. Sun Microsystems later made NeXTSTEP's underpinnings an open specification, which enabled other projects to create free and open source versions of many NeXT libraries and components. GNUStep implemented the bulk of NeXTSTEP's libraries, and [Window Maker][3] implemented its desktop environment.
|
||||
|
||||
Window Maker mimics the NeXTSTEP desktop GUI closely and provides some interesting insight into what Unix was like in the late '80s and early '90s. It also reveals some of the foundational concepts behind window managers like Fluxbox and Openbox.
|
||||
|
||||
You can install Window Maker from your distribution's repository. To try it out, log out of your desktop session after the installation is complete. By default, your session manager (KDM, GDM, LightDM, or XDM, depending on your setup) will continue to log you into your default desktop, so you must override the default when logging in.
|
||||
|
||||
To switch to Window Maker on GDM:
|
||||
|
||||
![Selecting the Window Maker desktop in GDM][4]
|
||||
|
||||
And on KDM:
|
||||
|
||||
![Selecting the Window Maker desktop in KDM][5]
|
||||
|
||||
### Window Maker dock
|
||||
|
||||
By default, the Window Maker desktop is empty but for a few _docks_ in each corner. As in NeXTSTEP, in Window Maker, a dock area is where major applications can go to be minimized as icons, where launchers can be created for quick access to common applications, and where tiny "dockapps" can run.
|
||||
|
||||
You can try out a dockapp by searching for "dockapp" in your software repository. They tend to be network and system monitors, audio-setting panels, clocks, and similar. Here's Window Maker running on Fedora:
|
||||
|
||||
![Window Maker running on Fedora][6]
|
||||
|
||||
### Application menu
|
||||
|
||||
To access the application menu, right-click anywhere on the desktop. To close it again, right-click. Window Maker isn't a desktop environment; rather it's a window manager. It helps you arrange and manage windows. Its only bundled application is called [WPrefs][7] (or more commonly, Window Maker Preferences), a settings application that helps you configure commonly used settings, while the application menu provides access to other options, including themes.
|
||||
|
||||
The applications you run are entirely up to you. Within Window Maker, you can choose to run KDE applications, GNOME applications, and applications that are not considered part of any major desktop. Your work environment is yours to create, and you can manage it with Window Maker.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/19/12/linux-window-maker-desktop
|
||||
|
||||
作者:[Seth Kenlon][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/seth
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/linux_penguin_green.png?itok=ENdVzW22 (Penguin with green background)
|
||||
[2]: https://en.wikipedia.org/wiki/NeXTSTEP
|
||||
[3]: https://www.windowmaker.org/
|
||||
[4]: https://opensource.com/sites/default/files/uploads/advent-windowmaker-gdm.jpg (Selecting the Window Maker desktop in GDM)
|
||||
[5]: https://opensource.com/sites/default/files/uploads/advent-windowmaker-kdm.jpg (Selecting the Window Maker desktop in KDM)
|
||||
[6]: https://opensource.com/sites/default/files/uploads/advent-windowmaker.jpg (Window Maker running on Fedora)
|
||||
[7]: http://www.windowmaker.org/docs/guidedtour/prefs.html
|
@ -1,5 +1,5 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: translator: (algzjh)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
|
@ -0,0 +1,65 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Dell XPS 13 7390 Review: The Best Laptop For Desktop Linux Users)
|
||||
[#]: via: (https://www.linux.com/articles/dell-xps-13-7390-review-the-best-laptop-for-desktop-linux-user/)
|
||||
[#]: author: (Swapnil Bhartiya https://www.linux.com/author/swapnil/)
|
||||
|
||||
Dell XPS 13 7390 Review: The Best Laptop For Desktop Linux Users
|
||||
======
|
||||
|
||||
[![][1]][2]
|
||||
|
||||
[![][1]][2]
|
||||
|
||||
Gone are the days when we had to do a lot of research and read a lot of reviews to find a machine that would work with the least amount of trouble with the desktop Linux distribution of choice. Today, almost every machine out there can run Linux. The kernel community has done an incredible job with device driver support to make everything work out of the box.
|
||||
|
||||
Still, there are machines that can run Linux, and then there are machines that run Linux. Dell machines fall in the latter category. Five years ago, Barton George started a program within Dell to bring desktop Linux to consumer grade, high-end Dell systems. What started as one machine is now an entire line of high-end laptops and desktops.
|
||||
|
||||
Among these machines, XPS 13 is my favorite. While I need a really powerful desktop to handle my 4K UHD, multicam video production, I also need an ultra-portable laptop that I can bring with me anywhere without having to worry about a bulky backpack and charger. XPS 13 was also my very first laptop, which lasted me more than 7 years. So, yes, there is that nostalgic factor, too.
|
||||
|
||||
Dell updates the XPS line almost every year and the latest [rollout was announced in October][3] (link to video interview). [XPS 13 (7390)][4] is an incremental update to the series, and Dell was kind enough to send me a review unit.
|
||||
|
||||
It is powered by a 6-core, Core i7-10710U CPU. It comes with 16GB of memory and 1TB SSD. At the base frequency of 1.10 GHz, which can boost to 4.1 GHz, this is a great machine for average workloads. It doesn’t have any dedicated GPU, so it’s not meant for gaming or compiling from source for Gentoo Linux or Arch Linux. However, I did manage to run some Steam games on it.
|
||||
|
||||
If you are looking to run your Kubernetes clusters, AI frameworks or Virtual Reality, then there are more powerful machines from the Precision line, which are certified to run Red Hat Enterprise Linux and Ubuntu.
|
||||
|
||||
The machine’s chassis is identical to the previous generation. The bezels remains as thin as they were in the previous generation, still thinner than MacBook and Microsoft’s Surface Pro.
|
||||
|
||||
It has three ports, two of which are USB-C Thunderbolt 3, which can be used to connect to 4K monitors, USB accessories, and high-speed data transfer between machines with peer-to-peer networking.
|
||||
|
||||
It also has a microSD slot. As a video journalist, a slot for an SD card would have been more useful. Heavy users of Raspberry Pis would also love this card.
|
||||
|
||||
It has 4 microphones and an improved camera, which is now located at the top (goodbye, nosecam!).
|
||||
|
||||
XPS 13 (7390) is sleek and slim. At 2.7 lbs, it is certainly comparable to Apple’s MacBook Air. This machine is meant to be your travel companion and for everyday tasks like checking emails, browsing the web, and writing.
|
||||
|
||||
Its 4K UHD screen supports HDR, which means you will be able to enjoy Mandalorian in all its full glory. That said, the on-board speakers are not that great and sound muffled. They are OK for video chats or casual YouTube viewing, but if you want to enjoy the The Witcher later this year, or if you want to enjoy music from Amazon, Apple Music or YouTube Music, you need headphones or external speakers.
|
||||
|
||||
But how much fun can you get out of this machine before you reach for charging cable? It gave me around 7-8 hours of battery life with average workload: browsing the web with a few tabs, just watching a movie or listening to music. Multi-tasking, especially any kind of web activity, will drain the battery. Some fine-tuning on Linux may give you even more life. On Windows 10, I was able to get more than 10 hours!
|
||||
|
||||
As a video journalist who is still doing a fair amount of writing, I really like the keyboard. However, the trackpad is the same story that we have been hearing on desktop Linux for ages: it’s nowhere near the quality on MacBook or Windows machines. Maybe one day. To Dell’s credit, they do release drivers for the trackpad that enhances the experience, but I am not running the stock Ubuntu 18.04 LTS that came with this system. I did a fresh install of Ubuntu 19.10 because Gnome is painfully slow in 18.04. I tried openSUSE Tumbleweed, Zorin OS, elementary OS, Fedora, KDE’s neon and Arch Linux. All worked, although some needed extra effort to run.
|
||||
|
||||
So, who is this system for? It’s certainly for professionals who want a well designed, high-end machine from a brand they can trust. It’s for those who like a MacBook Air, but prefer the desktop Linux ecosystem. It’s for those who want to use Linux for work, instead of working on it to make it work.
|
||||
|
||||
Spending a week with this machine reinforced why I love Dell’s XPS series so much. They are the best Linux laptops out there. And this XPS 13 (7390) packs a punch.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.linux.com/articles/dell-xps-13-7390-review-the-best-laptop-for-desktop-linux-user/
|
||||
|
||||
作者:[Swapnil Bhartiya][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://www.linux.com/author/swapnil/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://www.linux.com/wp-content/uploads/2019/12/dell-xps-13-7390-1068x665.jpg (dell-xps-13-7390)
|
||||
[2]: https://www.linux.com/wp-content/uploads/2019/12/dell-xps-13-7390.jpg
|
||||
[3]: https://bartongeorge.io/2019/08/21/please-welcome-the-9th-generation-of-the-xps-13-developer-edition/
|
||||
[4]: https://blog.dell.com/en-us/dells-new-consumer-pc-portfolio-unveiled-ifa-2019/
|
@ -0,0 +1,512 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Add jumping to your Python platformer game)
|
||||
[#]: via: (https://opensource.com/article/19/12/jumping-python-platformer-game)
|
||||
[#]: author: (Seth Kenlon https://opensource.com/users/seth)
|
||||
|
||||
Add jumping to your Python platformer game
|
||||
======
|
||||
Learn how to fight gravity with jumping in this installment on
|
||||
programming video games with Python's Pygame module.
|
||||
![Arcade games][1]
|
||||
|
||||
In the [previous article][2] in this series, you simulated gravity, but now you need to give your player a way to fight against gravity by jumping.
|
||||
|
||||
A jump is a temporary reprieve from gravity. For a few moments, you jump _up_ instead of falling down, the way gravity is pulling you. But once you hit the peak of your jump, gravity kicks in again and pulls you back down to earth.
|
||||
|
||||
In code, this translates to variables. First, you must establish variables for the player sprite so that Python can track whether or not the sprite is jumping. Once the player sprite is jumping, then gravity is applied to the player sprite again, pulling it back down to the nearest object.
|
||||
|
||||
### Setting jump state variables
|
||||
|
||||
You must add two new variables to your Player class:
|
||||
|
||||
* One to track whether your player is jumping or not, determined by whether or not your player sprite is standing on solid ground
|
||||
* One to bring the player back down to the ground
|
||||
|
||||
|
||||
|
||||
Add these variables to your **Player** class. In the following code, the lines above the comment are for context, so just add the final two lines:
|
||||
|
||||
|
||||
```
|
||||
self.movex = 0
|
||||
self.movey = 0
|
||||
self.frame = 0
|
||||
self.health = 10
|
||||
# gravity variables here
|
||||
self.collide_delta = 0
|
||||
self.jump_delta = 6
|
||||
```
|
||||
|
||||
The first variable (**collide_delta**) is set to 0 because, in its natural state, the player sprite is not in a mid-jump. The other variable (**jump_delta**) is set to 6 to prevent the sprite from bouncing (actually, jumping) when it first lands in the game world. When you've finished this article's examples, try setting it to 0 to see what happens.
|
||||
|
||||
### Colliding mid-jump
|
||||
|
||||
If you jump on a trampoline, your jumps are pretty impressive. But what would happen if you jumped into a wall? (Don't try it to find out!) Your jump, no matter how impressively it started, would end very quickly when you collide with something much larger and much more solid than you.
|
||||
|
||||
To mimic this in your video game, you must set the **self.collide_delta** variable to 0 whenever your player sprite collides with something, like the ground. If **self.collide_delta** is anything other than 0, then your player is jumping, and your player can't jump when it hits a wall or the ground.
|
||||
|
||||
In the **update** function of your **Player** class, modify the ground collision block to look like this:
|
||||
|
||||
|
||||
```
|
||||
ground_hit_list = pygame.sprite.spritecollide(self, ground_list, False)
|
||||
for g in ground_hit_list:
|
||||
self.movey = 0
|
||||
self.rect.y = worldy-ty-ty
|
||||
self.collide_delta = 0 # stop jumping
|
||||
if self.rect.y > g.rect.y:
|
||||
self.health -=1
|
||||
print(self.health)
|
||||
```
|
||||
|
||||
This code block checks for collisions happening between the ground sprites and the player sprite. In the event of a collision, it sets the Y-position of the player to a value equal to the height of the game window (**worldy**) minus the height of a tile minus the height of another tile (so that the player sprite appears to be standing on top of the ground and not in the middle of it). It also sets **self.collide_delta** to 0 so that the program is aware that the player is not in mid-jump. Additionally, it sets **self.movey** to 0 so that the program is aware that the player is not being pulled by gravity (it's a quirk of game physics that you don't need to continue to pull your player toward earth once the player has been grounded).
|
||||
|
||||
The **if** statement detects whether the player has descended _below_ the level of the ground; if so, it deducts health points as a penalty. This assumes that you want your player to lose health points for falling off the world. That's not strictly necessary; it's just a common convention in platformers. More than likely, you want this event to trigger something, though, or else your real-world player will be stuck playing a game with a sprite that's fallen off the screen. An easy recovery is to set **self.rect.y** to 0 again so that when the player sprite falls off the world, it respawns at the top of the world and falls back onto solid ground.
|
||||
|
||||
### Hitting the ground
|
||||
|
||||
Your simulated gravity wants your player's Y-axis movement to be 0 or more. To create a jump, write code that sends your player sprite off solid ground and into the air.
|
||||
|
||||
In the **update** function of your **Player** class, add a temporary reprieve from gravity:
|
||||
|
||||
|
||||
```
|
||||
if self.collide_delta < 6 and self.jump_delta < 6:
|
||||
self.jump_delta = 6*2
|
||||
self.movey -= 33 # how high to jump
|
||||
self.collide_delta += 6
|
||||
self.jump_delta += 6
|
||||
```
|
||||
|
||||
According to this code, a jump sends the player sprite 33 pixels into the air. It's _negative_ 33 because a lower number in Pygame means it's closer to the top of the screen.
|
||||
|
||||
This event is conditional, though. It only happens if **self.collide_delta** is less than 6 (its default value established in the **init** function of your **Player** sprite) and if **self.jump_delta** is less than 6. This condition prevents the player from triggering another jump until it collides with a platform. In other words, it prevents mid-air jumps.
|
||||
|
||||
You don't have to prevent mid-air jumps, or you can allow for mid-air jumps under special conditions; for instance, if a player obtains a special loot item, then you could grant it the ability to perform mid-air jumps until the next time it is hit by an enemy.
|
||||
|
||||
When you've finished this article's examples, try setting **self.collide_delta** and **self.jump_delta** to 0 for a 100% chance to jump in mid-air.
|
||||
|
||||
### Landing on a platform
|
||||
|
||||
So far, you've defined an anti-gravity condition for when the player sprite hits the ground, but the game code keeps platforms and the ground in separate lists. (As with so many choices made in this article, that's not strictly necessary, and you can experiment with treating the ground as just another platform.) To enable a player sprite to stand on top of a platform, you must detect a collision between the player sprite and a platform sprite and then perform the same actions as you did for a ground collision. Place this code into your **update** function:
|
||||
|
||||
|
||||
```
|
||||
plat_hit_list = pygame.sprite.spritecollide(self, plat_list, False)
|
||||
for p in plat_hit_list:
|
||||
self.collide_delta = 0 # stop jumping
|
||||
self.movey = 0
|
||||
```
|
||||
|
||||
There's one additional concern, though: platforms hang in the air, meaning the player can interact with them by approaching them from either the top or the bottom.
|
||||
|
||||
It's up to you how you want the platforms to react to your player. It's not uncommon to block a player from accessing a platform from below. Add this code to the above code block to treat platforms as a sort of ceiling or pergola, such that the player sprite can jump onto a platform as long as it jumps higher than the platform's topside, but obstructs the player when it tries to jump from beneath:
|
||||
|
||||
|
||||
```
|
||||
if self.rect.y > p.rect.y:
|
||||
self.rect.y = p.rect.y+ty
|
||||
else:
|
||||
self.rect.y = p.rect.y-ty
|
||||
```
|
||||
|
||||
The first clause of this **if** statement blocks the player from accessing a platform when the player sprite is directly under the platform. It does this by detecting that the player sprite's position is greater (in Pygame, that means lower on the screen, from top to bottom), and then sets the player sprite's new Y position to its current Y position plus the height of a tile, effectively keeping the player one tile's height away from ever passing through a platform from beneath it.
|
||||
|
||||
The **else** clause does the opposite. If the program is running this code, then the player sprite's Y position is _not_ greater than the platforms, meaning that the player sprite is falling from the sky (either because it has been freshly spawned there or because the player has jumped). In this event, the player sprite's position is set to the position of the platform minus one tile's height (because, remember, in Pygame, lower numbers mean something is higher up on the screen). This keeps the player on top of the platform unless it jumps or walks off of it.
|
||||
|
||||
You can experiment with other ways of dealing with sprite and platform interaction. For instance, maybe the player is assumed to be "in front" of the platforms and can seamlessly jump through them to stand on top of one. Or a platform could slow a player's leap but not block it entirely. You can even mix and match by grouping platforms into different lists.
|
||||
|
||||
### Triggering a jump
|
||||
|
||||
Your code now simulates all the necessary jump conditions, but it still lacks a jump trigger. Your player sprite's **self.jump_delta** is set to 6 initially, and the jump update code is triggered only when it's less than 6.
|
||||
|
||||
To trigger a new setting for the jumping variable, create a **jump** function in your **Player** class that sets the **self.jump_delta** to less than 6, causing gravity to be temporarily reprieved by sending your player sprite 33 pixels into the air:
|
||||
|
||||
|
||||
```
|
||||
def jump(self,platform_list):
|
||||
self.jump_delta = 0
|
||||
```
|
||||
|
||||
That's all the **jump** function requires, believe it or not. The rest happens in the **update** function, and you've already written that code.
|
||||
|
||||
There's one last thing to do before jumping is functional in your game. If you can't think of what it is, try playing your game to see how jumping works for you.
|
||||
|
||||
The problem is that nothing in your main loop is calling the **jump** function. You made a placeholder keypress for it early on, but right now, all the jump key does is print **jump** to the terminal.
|
||||
|
||||
### Calling the jump function
|
||||
|
||||
In your main loop, change the result of the Up arrow from printing a debug statement to calling the **jump** function.
|
||||
|
||||
Notice that the **jump** function, like the **update** function, needs to know about collisions, so you have to tell it which **plat_list** to use.
|
||||
|
||||
|
||||
```
|
||||
if event.key == pygame.K_UP or event.key == ord('w'):
|
||||
player.jump(plat_list)
|
||||
```
|
||||
|
||||
If you would rather use the Spacebar for jumping, set the key to **pygame.K_SPACE** instead of **pygame.K_UP**. Alternately, you can use both (as separate **if** statements) so that the player has a choice.
|
||||
|
||||
Try your game now. In the next article, you'll make your world scroll.
|
||||
|
||||
![Pygame platformer][3]
|
||||
|
||||
Here's all the code so far:
|
||||
|
||||
|
||||
```
|
||||
#!/usr/bin/env python3
|
||||
# draw a world
|
||||
# add a player and player control
|
||||
# add player movement
|
||||
# add enemy and basic collision
|
||||
# add platform
|
||||
# add gravity
|
||||
# add jumping
|
||||
|
||||
# GNU All-Permissive License
|
||||
# Copying and distribution of this file, with or without modification,
|
||||
# are permitted in any medium without royalty provided the copyright
|
||||
# notice and this notice are preserved. This file is offered as-is,
|
||||
# without any warranty.
|
||||
|
||||
import pygame
|
||||
import sys
|
||||
import os
|
||||
|
||||
'''
|
||||
Objects
|
||||
'''
|
||||
|
||||
class Platform(pygame.sprite.Sprite):
|
||||
# x location, y location, img width, img height, img file
|
||||
def __init__(self,xloc,yloc,imgw,imgh,img):
|
||||
pygame.sprite.Sprite.__init__(self)
|
||||
self.image = pygame.image.load(os.path.join('images',img)).convert()
|
||||
self.image.convert_alpha()
|
||||
self.rect = self.image.get_rect()
|
||||
self.rect.y = yloc
|
||||
self.rect.x = xloc
|
||||
|
||||
class Player(pygame.sprite.Sprite):
|
||||
'''
|
||||
Spawn a player
|
||||
'''
|
||||
def __init__(self):
|
||||
pygame.sprite.Sprite.__init__(self)
|
||||
self.movex = 0
|
||||
self.movey = 0
|
||||
self.frame = 0
|
||||
self.health = 10
|
||||
self.collide_delta = 0
|
||||
self.jump_delta = 6
|
||||
self.score = 1
|
||||
self.images = []
|
||||
for i in range(1,9):
|
||||
img = pygame.image.load(os.path.join('images','hero' + str(i) + '.png')).convert()
|
||||
img.convert_alpha()
|
||||
img.set_colorkey(ALPHA)
|
||||
self.images.append(img)
|
||||
self.image = self.images[0]
|
||||
self.rect = self.image.get_rect()
|
||||
|
||||
def jump(self,platform_list):
|
||||
self.jump_delta = 0
|
||||
|
||||
def gravity(self):
|
||||
self.movey += 3.2 # how fast player falls
|
||||
|
||||
if self.rect.y > worldy and self.movey >= 0:
|
||||
self.movey = 0
|
||||
self.rect.y = worldy-ty
|
||||
|
||||
def control(self,x,y):
|
||||
'''
|
||||
control player movement
|
||||
'''
|
||||
self.movex += x
|
||||
self.movey += y
|
||||
|
||||
def update(self):
|
||||
'''
|
||||
Update sprite position
|
||||
'''
|
||||
|
||||
self.rect.x = self.rect.x + self.movex
|
||||
self.rect.y = self.rect.y + self.movey
|
||||
|
||||
# moving left
|
||||
if self.movex < 0:
|
||||
self.frame += 1
|
||||
if self.frame > ani*3:
|
||||
self.frame = 0
|
||||
self.image = self.images[self.frame//ani]
|
||||
|
||||
# moving right
|
||||
if self.movex > 0:
|
||||
self.frame += 1
|
||||
if self.frame > ani*3:
|
||||
self.frame = 0
|
||||
self.image = self.images[(self.frame//ani)+4]
|
||||
|
||||
# collisions
|
||||
enemy_hit_list = pygame.sprite.spritecollide(self, enemy_list, False)
|
||||
for enemy in enemy_hit_list:
|
||||
self.health -= 1
|
||||
#print(self.health)
|
||||
|
||||
plat_hit_list = pygame.sprite.spritecollide(self, plat_list, False)
|
||||
for p in plat_hit_list:
|
||||
self.collide_delta = 0 # stop jumping
|
||||
self.movey = 0
|
||||
if self.rect.y > p.rect.y:
|
||||
self.rect.y = p.rect.y+ty
|
||||
else:
|
||||
self.rect.y = p.rect.y-ty
|
||||
|
||||
ground_hit_list = pygame.sprite.spritecollide(self, ground_list, False)
|
||||
for g in ground_hit_list:
|
||||
self.movey = 0
|
||||
self.rect.y = worldy-ty-ty
|
||||
self.collide_delta = 0 # stop jumping
|
||||
if self.rect.y > g.rect.y:
|
||||
self.health -=1
|
||||
print(self.health)
|
||||
|
||||
if self.collide_delta < 6 and self.jump_delta < 6:
|
||||
self.jump_delta = 6*2
|
||||
self.movey -= 33 # how high to jump
|
||||
self.collide_delta += 6
|
||||
self.jump_delta += 6
|
||||
|
||||
class Enemy(pygame.sprite.Sprite):
|
||||
'''
|
||||
Spawn an enemy
|
||||
'''
|
||||
def __init__(self,x,y,img):
|
||||
pygame.sprite.Sprite.__init__(self)
|
||||
self.image = pygame.image.load(os.path.join('images',img))
|
||||
self.movey = 0
|
||||
#self.image.convert_alpha()
|
||||
#self.image.set_colorkey(ALPHA)
|
||||
self.rect = self.image.get_rect()
|
||||
self.rect.x = x
|
||||
self.rect.y = y
|
||||
self.counter = 0
|
||||
|
||||
|
||||
def move(self):
|
||||
'''
|
||||
enemy movement
|
||||
'''
|
||||
distance = 80
|
||||
speed = 8
|
||||
|
||||
self.movey += 3.2
|
||||
|
||||
if self.counter >= 0 and self.counter <= distance:
|
||||
self.rect.x += speed
|
||||
elif self.counter >= distance and self.counter <= distance*2:
|
||||
self.rect.x -= speed
|
||||
else:
|
||||
self.counter = 0
|
||||
|
||||
self.counter += 1
|
||||
|
||||
if not self.rect.y >= worldy-ty-ty:
|
||||
self.rect.y += self.movey
|
||||
|
||||
plat_hit_list = pygame.sprite.spritecollide(self, plat_list, False)
|
||||
for p in plat_hit_list:
|
||||
self.movey = 0
|
||||
if self.rect.y > p.rect.y:
|
||||
self.rect.y = p.rect.y+ty
|
||||
else:
|
||||
self.rect.y = p.rect.y-ty
|
||||
|
||||
ground_hit_list = pygame.sprite.spritecollide(self, ground_list, False)
|
||||
for g in ground_hit_list:
|
||||
self.rect.y = worldy-ty-ty
|
||||
|
||||
|
||||
class Level():
|
||||
def bad(lvl,eloc):
|
||||
if lvl == 1:
|
||||
enemy = Enemy(eloc[0],eloc[1],'yeti.png') # spawn enemy
|
||||
enemy_list = pygame.sprite.Group() # create enemy group
|
||||
enemy_list.add(enemy) # add enemy to group
|
||||
|
||||
if lvl == 2:
|
||||
print("Level " + str(lvl) )
|
||||
|
||||
return enemy_list
|
||||
|
||||
def loot(lvl,lloc):
|
||||
print(lvl)
|
||||
|
||||
def ground(lvl,gloc,tx,ty):
|
||||
ground_list = pygame.sprite.Group()
|
||||
i=0
|
||||
if lvl == 1:
|
||||
while i < len(gloc):
|
||||
ground = Platform(gloc[i],worldy-ty,tx,ty,'ground.png')
|
||||
ground_list.add(ground)
|
||||
i=i+1
|
||||
|
||||
if lvl == 2:
|
||||
print("Level " + str(lvl) )
|
||||
|
||||
return ground_list
|
||||
|
||||
def platform(lvl,tx,ty):
|
||||
plat_list = pygame.sprite.Group()
|
||||
ploc = []
|
||||
i=0
|
||||
if lvl == 1:
|
||||
ploc.append((0,worldy-ty-128,3))
|
||||
ploc.append((300,worldy-ty-256,3))
|
||||
ploc.append((500,worldy-ty-128,4))
|
||||
|
||||
while i < len(ploc):
|
||||
j=0
|
||||
while j <= ploc[i][2]:
|
||||
plat = Platform((ploc[i][0]+(j*tx)),ploc[i][1],tx,ty,'ground.png')
|
||||
plat_list.add(plat)
|
||||
j=j+1
|
||||
print('run' + str(i) + str(ploc[i]))
|
||||
i=i+1
|
||||
|
||||
if lvl == 2:
|
||||
print("Level " + str(lvl) )
|
||||
|
||||
return plat_list
|
||||
|
||||
'''
|
||||
Setup
|
||||
'''
|
||||
worldx = 960
|
||||
worldy = 720
|
||||
|
||||
fps = 40 # frame rate
|
||||
ani = 4 # animation cycles
|
||||
clock = pygame.time.Clock()
|
||||
pygame.init()
|
||||
main = True
|
||||
|
||||
BLUE = (25,25,200)
|
||||
BLACK = (23,23,23 )
|
||||
WHITE = (254,254,254)
|
||||
ALPHA = (0,255,0)
|
||||
|
||||
world = pygame.display.set_mode([worldx,worldy])
|
||||
backdrop = pygame.image.load(os.path.join('images','stage.png')).convert()
|
||||
backdropbox = world.get_rect()
|
||||
player = Player() # spawn player
|
||||
player.rect.x = 0
|
||||
player.rect.y = 0
|
||||
player_list = pygame.sprite.Group()
|
||||
player_list.add(player)
|
||||
steps = 10 # how fast to move
|
||||
jump = -24
|
||||
|
||||
eloc = []
|
||||
eloc = [200,20]
|
||||
gloc = []
|
||||
#gloc = [0,630,64,630,128,630,192,630,256,630,320,630,384,630]
|
||||
tx = 64 #tile size
|
||||
ty = 64 #tile size
|
||||
|
||||
i=0
|
||||
while i <= (worldx/tx)+tx:
|
||||
gloc.append(i*tx)
|
||||
i=i+1
|
||||
|
||||
enemy_list = Level.bad( 1, eloc )
|
||||
ground_list = Level.ground( 1,gloc,tx,ty )
|
||||
plat_list = Level.platform( 1,tx,ty )
|
||||
|
||||
'''
|
||||
Main loop
|
||||
'''
|
||||
while main == True:
|
||||
for event in pygame.event.get():
|
||||
if event.type == pygame.QUIT:
|
||||
pygame.quit(); sys.exit()
|
||||
main = False
|
||||
|
||||
if event.type == pygame.KEYDOWN:
|
||||
if event.key == pygame.K_LEFT or event.key == ord('a'):
|
||||
print("LEFT")
|
||||
player.control(-steps,0)
|
||||
if event.key == pygame.K_RIGHT or event.key == ord('d'):
|
||||
print("RIGHT")
|
||||
player.control(steps,0)
|
||||
if event.key == pygame.K_UP or event.key == ord('w'):
|
||||
print('jump')
|
||||
|
||||
if event.type == pygame.KEYUP:
|
||||
if event.key == pygame.K_LEFT or event.key == ord('a'):
|
||||
player.control(steps,0)
|
||||
if event.key == pygame.K_RIGHT or event.key == ord('d'):
|
||||
player.control(-steps,0)
|
||||
if event.key == pygame.K_UP or event.key == ord('w'):
|
||||
player.jump(plat_list)
|
||||
|
||||
if event.key == ord('q'):
|
||||
pygame.quit()
|
||||
sys.exit()
|
||||
main = False
|
||||
|
||||
# world.fill(BLACK)
|
||||
world.blit(backdrop, backdropbox)
|
||||
player.gravity() # check gravity
|
||||
player.update()
|
||||
player_list.draw(world) #refresh player position
|
||||
enemy_list.draw(world) # refresh enemies
|
||||
ground_list.draw(world) # refresh enemies
|
||||
plat_list.draw(world) # refresh platforms
|
||||
for e in enemy_list:
|
||||
e.move()
|
||||
pygame.display.flip()
|
||||
clock.tick(fps)
|
||||
```
|
||||
|
||||
This is the 7th installment in an ongoing series about creating video games in [Python 3][4] using the [Pygame][5] module. Previous articles are:
|
||||
|
||||
* [Learn how to program in Python by building a simple dice game][6]
|
||||
* [Build a game framework with Python using the Pygame module][7]
|
||||
* [How to add a player to your Python game][8]
|
||||
* [Using Pygame to move your game character around][9]
|
||||
* [What's a hero without a villain? How to add one to your Python game][10]
|
||||
* [Simulate gravity in your Python game][2]
|
||||
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/19/12/jumping-python-platformer-game
|
||||
|
||||
作者:[Seth Kenlon][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/seth
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/arcade_game_gaming.jpg?itok=84Rjk_32 (Arcade games)
|
||||
[2]: https://opensource.com/article/19/11/simulate-gravity-python
|
||||
[3]: https://opensource.com/sites/default/files/uploads/pygame-jump.jpg (Pygame platformer)
|
||||
[4]: https://www.python.org/
|
||||
[5]: https://www.pygame.org/
|
||||
[6]: https://opensource.com/article/17/10/python-101
|
||||
[7]: https://opensource.com/article/17/12/game-framework-python
|
||||
[8]: https://opensource.com/article/17/12/game-python-add-a-player
|
||||
[9]: https://opensource.com/article/17/12/game-python-moving-player
|
||||
[10]: https://opensource.com/article/18/5/pygame-enemy
|
@ -0,0 +1,320 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (6 Ways to Send Email from the Linux Command Line)
|
||||
[#]: via: (https://www.2daygeek.com/6-ways-to-send-email-from-the-linux-command-line/)
|
||||
[#]: author: (Magesh Maruthamuthu https://www.2daygeek.com/author/magesh/)
|
||||
|
||||
6 Ways to Send Email from the Linux Command Line
|
||||
======
|
||||
|
||||
Sending email from the command line is required when you need to create emails from a shell script.
|
||||
|
||||
There are several commands on Linux to send emails from the Linux command line.
|
||||
|
||||
I’ve included the Top 6 Command Line Mail Clients in this tutorial.
|
||||
|
||||
You can use any one of the following to send email from the Linux command line.
|
||||
|
||||
This can be done using the following six commands.
|
||||
|
||||
* mail
|
||||
* mailx
|
||||
* mutt
|
||||
* mpack
|
||||
* sendmail
|
||||
* ssmtp
|
||||
|
||||
|
||||
|
||||
### How does it work?
|
||||
|
||||
Let me give you an overall explanation of how the mail command delivers the mails to recipients on Linux.
|
||||
|
||||
The mail command compose emails and sends them to a local mail transfer agent (MTA), such as sendmail, postfix, and so on.
|
||||
|
||||
The mail server actually communicates with remote mail servers for sending and receiving emails.
|
||||
|
||||
The flow chart below can explain more about that.
|
||||
|
||||
[![][1]][2]
|
||||
|
||||
### 1) How to Install mail Command on Linux
|
||||
|
||||
The mail command is most popular command to send emails from Linux terminal.
|
||||
|
||||
The mail command can be installed from the distribution official repository as follows.
|
||||
|
||||
For **“Debian/Ubuntu”** systems, use **[APT-GET Command][3]** or **[APT Command][4]** to install mailutils.
|
||||
|
||||
```
|
||||
$ sudo apt-get install mailutils
|
||||
```
|
||||
|
||||
For **“RHEL/CentOS”** systems, use **[YUM Command][5]** to install mailx.
|
||||
|
||||
```
|
||||
$ sudo yum install mailx
|
||||
```
|
||||
|
||||
For **“Fedora”** system, use the **[DNF Command][6]** to install mailx.
|
||||
|
||||
```
|
||||
$ sudo dnf install mailx
|
||||
```
|
||||
|
||||
### 1a) How to Use mail Command on Linux to Send a Mail
|
||||
|
||||
It’s straightforward and easy to use.
|
||||
|
||||
Use the following format to send mail using the mail command without an attachment.
|
||||
|
||||
```
|
||||
$ echo "This is the mail body" | mail -s "Subject" [email protected]
|
||||
```
|
||||
|
||||
Use the following format to send mail using the mail command with attachment.
|
||||
|
||||
```
|
||||
$ echo "This is the mail body" | mail -a test1.txt -s "Subject" [email protected]
|
||||
```
|
||||
|
||||
```
|
||||
+---------+----------------------------------------------------+
|
||||
| Options | Description |
|
||||
+---------+----------------------------------------------------+
|
||||
| -a | It's used for attachment on Red Hat based systems. |
|
||||
| -A | It's used for attachment on Debian based systems. |
|
||||
| -s | Specify the subject of the message |
|
||||
+--------------------------------------------------------------+
|
||||
```
|
||||
|
||||
### 2) How to Install mutt Command on Linux
|
||||
|
||||
The mutt is another popular command to send emails from Linux terminal.
|
||||
|
||||
Mutt is a small but very powerful text based program for reading and sending electronic mail under unix operating systems, including support for color terminals, MIME, OpenPGP, and a threaded sorting mode.
|
||||
|
||||
The mail command can be installed from the distribution official repository as follows.
|
||||
|
||||
For **“Debian/Ubuntu”** systems, use **[APT-GET Command][3]** or **[APT Command][4]** to install mutt.
|
||||
|
||||
```
|
||||
$ sudo apt-get install mutt
|
||||
```
|
||||
|
||||
For **“RHEL/CentOS”** systems, use **[YUM Command][5]** to install mutt.
|
||||
|
||||
```
|
||||
$ sudo yum install mutt
|
||||
```
|
||||
|
||||
For **“Fedora”** system, use the **[DNF Command][6]** to install mutt.
|
||||
|
||||
```
|
||||
$ sudo dnf install mutt
|
||||
```
|
||||
|
||||
### 2b) How to Use mutt Command on Linux to Send a Mail
|
||||
|
||||
This is also straightforward and easy to use.
|
||||
|
||||
Use the following format to send mail using the mutt command without an attachment.
|
||||
|
||||
```
|
||||
$ echo "This is the mail body" | mutt -s "Subject" [email protected]
|
||||
```
|
||||
|
||||
Use the following format to send mail using the mutt command with attachment.
|
||||
|
||||
```
|
||||
$ echo "This is the mail body" | mutt -s "Subject" [email protected] -a test1.txt
|
||||
```
|
||||
|
||||
### 3) How to Install mpack Command on Linux
|
||||
|
||||
The mpack is another popular command to send emails from Linux terminal.
|
||||
|
||||
The mpack program encodes the the named file in one or more MIME messages. The resulting messages are mailed to one or more recipients.
|
||||
|
||||
The mpack command can be installed from the distribution official repository as follows.
|
||||
|
||||
For **“Debian/Ubuntu”** systems, use **[APT-GET Command][3]** or **[APT Command][4]** to install mpack.
|
||||
|
||||
```
|
||||
$ sudo apt-get install mpack
|
||||
```
|
||||
|
||||
For **“RHEL/CentOS”** systems, use **[YUM Command][5]** to install mpack.
|
||||
|
||||
```
|
||||
$ sudo yum install mpack
|
||||
```
|
||||
|
||||
For **“Fedora”** system, use the **[DNF Command][6]** to install mpack.
|
||||
|
||||
```
|
||||
$ sudo dnf install mpack
|
||||
```
|
||||
|
||||
### 3a) How to Use mpack Command on Linux to Send a Mail
|
||||
|
||||
This is also straight forward and easy to use.
|
||||
|
||||
Use the following format to send mail using the mpack command without an attachment.
|
||||
|
||||
```
|
||||
$ echo "This is the mail body" | mpack -s "Subject" [email protected]
|
||||
```
|
||||
|
||||
Use the following format to send mail using the mpack command with attachment.
|
||||
|
||||
```
|
||||
$ echo "This is the mail body" | mpack -s "Subject" [email protected] -a test1.txt
|
||||
```
|
||||
|
||||
### 4) How to Install mail Command on Linux
|
||||
|
||||
Mailx is the newer version of mail command.
|
||||
|
||||
It is based on Berkeley Mail 8.1, is intended to provide the functionality of the POSIX mailx command, and offers extensions for MIME, IMAP, POP3, SMTP, and S/MIME.
|
||||
|
||||
Mailx provides enhanced features for interactive use, such as caching message threading, scoring, and filtering.
|
||||
|
||||
The mailx command can be installed from the distribution official repository as follows.
|
||||
|
||||
For **“Debian/Ubuntu”** systems, use **[APT-GET Command][3]** or **[APT Command][4]** to install mailutils.
|
||||
|
||||
```
|
||||
$ sudo apt-get install mailutils
|
||||
```
|
||||
|
||||
For **“RHEL/CentOS”** systems, use **[YUM Command][5]** to install mailx.
|
||||
|
||||
```
|
||||
$ sudo yum install mailx
|
||||
```
|
||||
|
||||
For **“Fedora”** system, use the **[DNF Command][6]** to install mailx.
|
||||
|
||||
```
|
||||
$ sudo dnf install mailx
|
||||
```
|
||||
|
||||
### 4a) How to Use mailx Command on Linux to Send a Mail
|
||||
|
||||
It’s straight forward and easy to use.
|
||||
|
||||
Use the following format to send mail using the mailx command without an attachment.
|
||||
|
||||
```
|
||||
$ echo "This is the mail body" | mail -s "Subject" [email protected]
|
||||
```
|
||||
|
||||
Use the following format to send mail using the mailx command with attachment.
|
||||
|
||||
```
|
||||
$ echo "This is the mail body" | mail -a test1.txt -s "Subject" [email protected]
|
||||
```
|
||||
|
||||
### 5) How to Install sendmail Command on Linux
|
||||
|
||||
Sendmail is a most popular and general purpose SMTP server used in most of Linux distribution.
|
||||
|
||||
Also, it allows you to sending email from command line.
|
||||
|
||||
The sendmail command can be installed from the distribution official repository as follows.
|
||||
|
||||
For **“Debian/Ubuntu”** systems, use **[APT-GET Command][3]** or **[APT Command][4]** to install sendmail.
|
||||
|
||||
```
|
||||
$ sudo apt-get install sendmail
|
||||
```
|
||||
|
||||
For **“RHEL/CentOS”** systems, use **[YUM Command][5]** to install sendmail.
|
||||
|
||||
```
|
||||
$ sudo yum install sendmail
|
||||
```
|
||||
|
||||
For **“Fedora”** system, use the **[DNF Command][6]** to install sendmail.
|
||||
|
||||
```
|
||||
$ sudo dnf install sendmail
|
||||
```
|
||||
|
||||
### 5a) How to Use sendmail Command on Linux to Send a Mail
|
||||
|
||||
It’s straight forward and easy to use.
|
||||
|
||||
Use the following format to send mail using the sendmail command.
|
||||
|
||||
```
|
||||
$ echo -e "Subject: Test Mail\nThis is the mail body" > /tmp/send-mail.txt
|
||||
```
|
||||
|
||||
```
|
||||
$ sendmail [email protected] < send-mail.txt
|
||||
```
|
||||
|
||||
### 6) How to Install ssmtp Command on Linux
|
||||
|
||||
ssmtp is a send-only sendmail emulator for machines which delivers email from a local computer to a configured mailhost (mailhub).
|
||||
|
||||
SSMTP allows users to transfer emails through an SMTP server from the Linux command line.
|
||||
|
||||
The sendmail command can be installed from the distribution official repository as follows.
|
||||
|
||||
For **“Debian/Ubuntu”** systems, use **[APT-GET Command][3]** or **[APT Command][4]** to install ssmtp.
|
||||
|
||||
```
|
||||
$ sudo apt-get install ssmtp
|
||||
```
|
||||
|
||||
For **“RHEL/CentOS”** systems, use **[YUM Command][5]** to install ssmtp.
|
||||
|
||||
```
|
||||
$ sudo yum install ssmtp
|
||||
```
|
||||
|
||||
For **“Fedora”** system, use the **[DNF Command][6]** to install ssmtp.
|
||||
|
||||
```
|
||||
$ sudo dnf install ssmtp
|
||||
```
|
||||
|
||||
### 6a) How to Use ssmtp Command on Linux to Send a Mail
|
||||
|
||||
It’s straight forward and easy to use.
|
||||
|
||||
Use the following format to send mail using the ssmtp command.
|
||||
|
||||
```
|
||||
$ echo -e "Subject: Test Mail\nThis is the mail body" > /tmp/ssmtp-mail.txt
|
||||
```
|
||||
|
||||
```
|
||||
$ ssmtp [email protected] < /tmp/ssmtp-mail.txt
|
||||
```
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.2daygeek.com/6-ways-to-send-email-from-the-linux-command-line/
|
||||
|
||||
作者:[Magesh Maruthamuthu][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://www.2daygeek.com/author/magesh/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7
|
||||
[2]: https://www.2daygeek.com/wp-content/uploads/2019/12/smtp-simple-mail-transfer-protocol.png
|
||||
[3]: https://www.2daygeek.com/apt-get-apt-cache-command-examples-manage-packages-debian-ubuntu-systems/
|
||||
[4]: https://www.2daygeek.com/apt-command-examples-manage-packages-debian-ubuntu-systems/
|
||||
[5]: https://www.2daygeek.com/yum-command-examples-manage-packages-rhel-centos-systems/
|
||||
[6]: https://www.2daygeek.com/dnf-command-examples-manage-packages-fedora-system/
|
@ -0,0 +1,242 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (lxbwolf)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (How to remove duplicate lines from files with awk)
|
||||
[#]: via: (https://opensource.com/article/19/10/remove-duplicate-lines-files-awk)
|
||||
[#]: author: (Lazarus Lazaridis https://opensource.com/users/iridakos)
|
||||
|
||||
怎样使用 awk 删掉文件中重复的行
|
||||
======
|
||||
学习怎样使用 awk 的 `!visited[$0]++` 在不重新排序或改变原排列顺序的前提下删掉重复的行。
|
||||
![Coding on a computer][1]
|
||||
|
||||
假设你有一个文本文件,你需要删掉所有重复的行。
|
||||
|
||||
### 这篇内容篇幅比较长,如果不想深入探讨或时间有限,可以看总结。
|
||||
|
||||
*保持原来的排列顺序*删掉重复行,使用:
|
||||
|
||||
|
||||
```
|
||||
`awk '!visited[$0]++' your_file > deduplicated_file`
|
||||
```
|
||||
|
||||
### 工作原理
|
||||
|
||||
这个脚本维持一个关联数组,*index 总数*为文件去重后的行数,每个 index 对应的 *value* 为某行出现的次数。对于文件的每一行,如果这行出现的次数为 0,则 value 加 1 *并打印这行*,否则 value 加 1 *不打印这行*。
|
||||
|
||||
我之前不熟悉 **awk**,我想弄清楚这么短小的一个脚本是怎么实现的。我调研了下,下面是调研心得:
|
||||
|
||||
* awk “脚本” **!visited[$0]++** 对输入文件的*每一行*都执行
|
||||
* **visited[]** 是一个 [关联数组][2] (又名 [Map][3])的变量。 **awk** 会在第一次执行时初始化它,因此我们不需要初始化。
|
||||
* **$0** 变量的值是当前正在被处理的行的内容
|
||||
* **visited[$0]** 通过与 **$0**(正在被处理的行)相等的 key 访问 map 中的值,即出现次数(我们在下面设置的)
|
||||
* **!** 对表示出现次数的值取反
|
||||
* 在 awk 中,[任意非零的数或任意非空的字符串的值是 true][4]。
|
||||
* [变量默认的初始值为空字符串][5],如果被转换为数字,则为 0.
|
||||
* 也就是说:
|
||||
* 如果 **visited[$0]** 的值是一个比 0 大的数,取反后被解析成 **false**。
|
||||
* 如果 **visited[$0]** 的值为等于 0 的数字或空字符串,取反后被解析成 **true** 。
|
||||
* **++** 表示变量(visited[$0])的值加 1.
|
||||
* 如果值为空,**awk** 自动把它转换为 **0**(数字) 后加 1。
|
||||
* **注意:**加 1 操作是在我们取到了变量的值之后执行的。
|
||||
|
||||
|
||||
|
||||
总的来说,整个表达式的意思是:
|
||||
|
||||
* **true** 如果表示出现次数的值为 0 或空字符串
|
||||
* **false** 如果出现的次数大于 0
|
||||
|
||||
|
||||
|
||||
**awk** 由 [_pattern 表达式和一个与之关联的 action_][6] 组成
|
||||
|
||||
|
||||
```
|
||||
`<pattern/expression> { <action> }`
|
||||
```
|
||||
|
||||
如果匹配到了 pattern,就会执行后面的 action。如果没有 action,**awk** 默认会 **print** 输入。
|
||||
|
||||
> 省略 action 等于 **{print $0}**。
|
||||
|
||||
我们的脚本由一个 **awk** 表达式语句组成,省略了 action。因此这样写:
|
||||
|
||||
|
||||
```
|
||||
`awk '!visited[$0]++' your_file > deduplicated_file`
|
||||
```
|
||||
|
||||
等于这样写:
|
||||
|
||||
|
||||
```
|
||||
`awk '!visited[$0]++ { print $0 }' your_file > deduplicated_file`
|
||||
```
|
||||
|
||||
对于文件的每一行,如果表达式匹配到了,这行内容被 print 到输出。否则,不执行 action,不打印任何东西。
|
||||
|
||||
### 为什么不用 uniq 命令?
|
||||
|
||||
**uniq** 命令仅能对相邻的行去重。这是一个示例:
|
||||
|
||||
|
||||
```
|
||||
$ cat test.txt
|
||||
A
|
||||
A
|
||||
A
|
||||
B
|
||||
B
|
||||
B
|
||||
A
|
||||
A
|
||||
C
|
||||
C
|
||||
C
|
||||
B
|
||||
B
|
||||
A
|
||||
$ uniq < test.txt
|
||||
A
|
||||
B
|
||||
A
|
||||
C
|
||||
B
|
||||
A
|
||||
```
|
||||
|
||||
### 其他方法
|
||||
|
||||
#### 使用 sort 命令
|
||||
|
||||
我们也可以用下面的 [**sort**][7] 命令来去除重复的行,但是*行原来的顺序没有被保留*。
|
||||
|
||||
|
||||
```
|
||||
`sort -u your_file > sorted_deduplicated_file`
|
||||
```
|
||||
|
||||
#### 使用 cat + sort + cut
|
||||
|
||||
上面的方法会产出一个去重的文件,各行是基于内容进行排序的。[通过管道连接命令][8] 可以解决这个问题。
|
||||
|
||||
|
||||
```
|
||||
`cat -n your_file | sort -uk2 | sort -nk1 | cut -f2-`
|
||||
```
|
||||
|
||||
##### 工作原理
|
||||
|
||||
假设我们有下面一个文件
|
||||
|
||||
|
||||
```
|
||||
abc
|
||||
ghi
|
||||
abc
|
||||
def
|
||||
xyz
|
||||
def
|
||||
ghi
|
||||
klm
|
||||
```
|
||||
|
||||
**cat -n test.txt** 在每行前面显示序号。
|
||||
|
||||
|
||||
```
|
||||
1 abc
|
||||
2 ghi
|
||||
3 abc
|
||||
4 def
|
||||
5 xyz
|
||||
6 def
|
||||
7 ghi
|
||||
8 klm
|
||||
```
|
||||
|
||||
**sort -uk2** 基于第二列(**k2** 选项)进行排序,对于第二列相同的值只保留一次(**u** 选项)。
|
||||
|
||||
|
||||
```
|
||||
1 abc
|
||||
4 def
|
||||
2 ghi
|
||||
8 klm
|
||||
5 xyz
|
||||
```
|
||||
|
||||
**sort -nk1** 基于第一列排序(**k1** 选项),把列的值作为数字来处理(**-n** 选项)。
|
||||
|
||||
|
||||
```
|
||||
1 abc
|
||||
2 ghi
|
||||
4 def
|
||||
5 xyz
|
||||
8 klm
|
||||
```
|
||||
|
||||
最后,**cut -f2-** 打印每一行从第二列开始直到最后的内容(**-f2-** 选项:留意 - 后缀,- 表示这行后面的内容都包含在内)。
|
||||
|
||||
|
||||
```
|
||||
abc
|
||||
ghi
|
||||
def
|
||||
xyz
|
||||
klm
|
||||
```
|
||||
|
||||
### 参考
|
||||
|
||||
* [GNU awk 用户手册][9]
|
||||
* [awk 中的数组][2]
|
||||
* [Awk—Truth values][4]
|
||||
* [Awk 表达式][5]
|
||||
* [Unix 怎么删除文件中重复的行?][10]
|
||||
* [不用排序去掉重复的行【去重】][11]
|
||||
* ['!a[$0]++' 工作原理][12]
|
||||
|
||||
|
||||
|
||||
以上为全文。附上猫照。
|
||||
|
||||
![Duplicate cat][13]
|
||||
|
||||
* * *
|
||||
|
||||
本文首发在 [Lazarus Lazaridis][14] 的 iridakos 博客,遵照 [CC BY-NC 4.0 License][15] ,转载已获得作者授权。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/19/10/remove-duplicate-lines-files-awk
|
||||
|
||||
作者:[Lazarus Lazaridis][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[lxbwolf](https://github.com/lxbwolf)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/iridakos
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/code_computer_laptop_hack_work.png?itok=aSpcWkcl (Coding on a computer)
|
||||
[2]: http://kirste.userpage.fu-berlin.de/chemnet/use/info/gawk/gawk_12.html
|
||||
[3]: https://en.wikipedia.org/wiki/Associative_array
|
||||
[4]: https://www.gnu.org/software/gawk/manual/html_node/Truth-Values.html
|
||||
[5]: https://ftp.gnu.org/old-gnu/Manuals/gawk-3.0.3/html_chapter/gawk_8.html
|
||||
[6]: http://kirste.userpage.fu-berlin.de/chemnet/use/info/gawk/gawk_9.html
|
||||
[7]: http://man7.org/linux/man-pages/man1/sort.1.html
|
||||
[8]: https://stackoverflow.com/a/20639730/2292448
|
||||
[9]: https://www.gnu.org/software/gawk/manual/html_node/
|
||||
[10]: https://stackoverflow.com/questions/1444406/how-can-i-delete-duplicate-lines-in-a-file-in-unix
|
||||
[11]: https://stackoverflow.com/questions/11532157/remove-duplicate-lines-without-sorting
|
||||
[12]: https://unix.stackexchange.com/questions/159695/how-does-awk-a0-work/159734#159734
|
||||
[13]: https://opensource.com/sites/default/files/uploads/duplicate-cat.jpg (Duplicate cat)
|
||||
[14]: https://iridakos.com/about/
|
||||
[15]: http://creativecommons.org/licenses/by-nc/4.0/
|
201
translated/tech/20191115 How to port an awk script to Python.md
Normal file
201
translated/tech/20191115 How to port an awk script to Python.md
Normal file
@ -0,0 +1,201 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (wxy)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (How to port an awk script to Python)
|
||||
[#]: via: (https://opensource.com/article/19/11/awk-to-python)
|
||||
[#]: author: (Moshe Zadka https://opensource.com/users/moshez)
|
||||
|
||||
如何把 awk 脚本移植到 Python
|
||||
======
|
||||
|
||||
> 将一个 awk 脚本移植到 Python 主要在于代码风格而不是转译。
|
||||
|
||||
![Woman sitting in front of her laptop][1]
|
||||
|
||||
脚本是解决问题的有效方法,而 awk 是编写脚本的出色语言。它特别擅长于简单的文本处理,它可以带你完成配置文件的某些复杂重写或目录中文件名的重新格式化。
|
||||
|
||||
### 何时从 awk 转向 Python
|
||||
|
||||
但是在某写方面,awk 的限制开始显现出来。它没有将文件分解为模块的真正概念,它缺乏质量错误报告,并且缺少了现在被认为是编程语言工作原理的其他内容。当编程语言的这些丰富功能有助于维护关键脚本时,移植将是一个不错的选择。
|
||||
|
||||
我最喜欢的完美移植 awk 的现代编程语言是 Python。
|
||||
|
||||
在将 awk 脚本移植到 Python 之前,通常值得考虑一下其原始使用场景。例如,由于 awk 的局限性,通常从 Bash 脚本调用 awk 代码,其中包括一些对 `sed`、`sort` 之类的其它命令行常见工具的调用。 最好将所有内容转换为一个一致的 Python 程序。有时,脚本会做出过于宽泛的假设,例如,即使实际上只运行一个文件,该代码也可能允许任意数量的文件。
|
||||
|
||||
在仔细考虑了上下文并确定了要用 Python 替代的东西之后,该编写代码了。
|
||||
|
||||
### 标准 awk 到 Python 功能
|
||||
|
||||
以下 Python 功能是有用的,需要记住:
|
||||
|
||||
```
|
||||
with open(some_file_name) as fpin:
|
||||
for line in fpin:
|
||||
pass # do something with line
|
||||
```
|
||||
|
||||
此代码将逐行循环遍历文件并处理这些行。
|
||||
|
||||
如果要访问行号(相当于 awk 的 `NR`),则可以使用以下代码:
|
||||
|
||||
```
|
||||
with open(some_file_name) as fpin:
|
||||
for nr, line in enumerate(fpin):
|
||||
pass # do something with line
|
||||
```
|
||||
|
||||
### 在 Python 中实现多文件的 awk 式行为
|
||||
|
||||
如果你需要能够遍历任意数量的文件同时保持行数的持续计数(类似 awk 的 `FNR`),则此循环可以做到这一点:
|
||||
|
||||
```
|
||||
def awk_like_lines(list_of_file_names):
|
||||
def _all_lines():
|
||||
for filename in list_of_file_names:
|
||||
with open(filename) as fpin:
|
||||
yield from fpin
|
||||
yield from enumerate(_all_lines())
|
||||
```
|
||||
|
||||
此语法使用 Python 的*生成器*和 `yield from` 来构建*迭代器*,该迭代器将遍历所有行并保持一个持久计数。
|
||||
|
||||
如果你需要同时使用 `FNR` 和 `NR`,这是一个更复杂的循环:
|
||||
|
||||
```
|
||||
def awk_like_lines(list_of_file_names):
|
||||
def _all_lines():
|
||||
for filename in list_of_file_names:
|
||||
with open(filename) as fpin:
|
||||
yield from enumerate(fpin)
|
||||
for nr, (fnr, line) in _all_lines:
|
||||
yield nr, fnr, line
|
||||
```
|
||||
|
||||
### 更复杂的 FNR、NR 和行数的 awk 行为
|
||||
|
||||
如果 `FNR`、`NR` 和行数这三个你全部需要,仍然会有问题。如果确实如此,则使用三元组(其中两个项目是数字)会导致混淆。命名参数可使该代码更易于阅读,因此最好使用 `dataclass:
|
||||
|
||||
```
|
||||
import dataclass
|
||||
|
||||
@dataclass.dataclass(frozen=True)
|
||||
class AwkLikeLine:
|
||||
content: str
|
||||
fnr: int
|
||||
nr: int
|
||||
|
||||
def awk_like_lines(list_of_file_names):
|
||||
def _all_lines():
|
||||
for filename in list_of_file_names:
|
||||
with open(filename) as fpin:
|
||||
yield from enumerate(fpin)
|
||||
for nr, (fnr, line) in _all_lines:
|
||||
yield AwkLikeLine(nr=nr, fnr=fnr, line=line)
|
||||
```
|
||||
|
||||
你可能想知道,为什么不总用这种方法呢?用其它方式的的原因是这总是太复杂了。如果你的目标是把一个通用库更容易地从 awk 移植到 Python,请考虑这样做。但是编写一个可以使你确切地了解特定情况所需的循环的方法通常更容易实现,也更容易理解(因而易于维护)。
|
||||
|
||||
### 理解 awk 字段
|
||||
|
||||
一旦有了与一行相对应的字符串,如果要转换 awk 程序,则通常需要将其分解为*字段*。Python 有几种方法可以做到这一点。这将把行按任意数量的连续空格拆分,返回一个字符串列表:
|
||||
|
||||
```
|
||||
line.split()
|
||||
```
|
||||
|
||||
如果需要另一个字段分隔符,比如以 `:` 分隔行,则需要 `rstrip` 方法来删除最后一个换行符:
|
||||
|
||||
```
|
||||
line.rstrip("\n").split(":")
|
||||
```
|
||||
|
||||
完成以下操作后,列表 `parts` 将存有分解的字符串:
|
||||
|
||||
```
|
||||
parts = line.rstrip("\n").split(":")
|
||||
```
|
||||
|
||||
这种拆分非常适合用来处理参数,但是我们处于[偏差一个的错误][2]场景中。现在 `parts[0]` 将对应于 awk 的 `$1`,`parts[1]` 将对应于 awk 的 `$2`,依此类推。之所以偏差一个,是因为 awk 计数“字段”从 1 开始,而 Python 从 0 开始计数。在 awk 中,`$0` 是整个行 —— 等同于 `line.rstrip("\n")`,而 awk 的 `NF`(字段数)更容易以 `len(parts)` 的形式得到。
|
||||
|
||||
### 移植 awk 字段到 Python
|
||||
|
||||
例如,让我们将这个单行代码“[如何使用 awk 从文件中删除重复行][3]”转换为 Python。
|
||||
|
||||
`awk` 中的原始代码是:
|
||||
|
||||
```
|
||||
awk '!visited[$0]++' your_file > deduplicated_file
|
||||
```
|
||||
|
||||
“真实的” Python 转换将是:
|
||||
|
||||
```
|
||||
import collections
|
||||
import sys
|
||||
|
||||
visited = collections.defaultdict(int)
|
||||
for line in open("your_file"):
|
||||
did_visit = visited[line]
|
||||
visited[line] += 1
|
||||
if not did_visit:
|
||||
sys.stdout.write(line)
|
||||
```
|
||||
|
||||
但是,Python 比 awk 具有更多的数据结构。与其计数访问次数(除了知道是否看到一行,我们不使用它),为什么不记录访问的行呢?
|
||||
|
||||
```
|
||||
import sys
|
||||
|
||||
visited = set()
|
||||
for line in open("your_file"):
|
||||
if line in visited:
|
||||
continue
|
||||
visited.add(line)
|
||||
sys.stdout.write(line)
|
||||
```
|
||||
|
||||
### 编写 Python 化的 awk 代码
|
||||
|
||||
Python 社区提倡编写 Python 化的代码,这意味着它要遵循公认的代码风格。更加 Python 化的方法将区分*唯一性*和输入/输出的关注点。此更改将使对代码进行单元测试更加容易:
|
||||
|
||||
```
|
||||
def unique_generator(things):
|
||||
visited = set()
|
||||
for thing in things:
|
||||
if thing in visited:
|
||||
continue
|
||||
visited.add(things)
|
||||
yield thing
|
||||
|
||||
import sys
|
||||
|
||||
for line in unique_generator(open("your_file")):
|
||||
sys.stdout.write(line)
|
||||
```
|
||||
|
||||
将所有逻辑置于输入/输出代码之外,可以更好地分离问题,并提高代码的可用性和可测试性。
|
||||
|
||||
### 结论:Python 可能是一个不错的选择
|
||||
|
||||
将 awk 脚本移植到 Python 时,通常是在考虑适当的 Python 代码风格时重新实现核心需求,而不是按条件/操作进行笨拙的音译。考虑原始上下文并产生高质量的 Python 解决方案。虽然有时候使用 awk 的 Bash 单行代码可以完成这项工作,但 Python 编码是通往更易于维护的代码的途径。
|
||||
|
||||
另外,如果你正在编写awk脚本,我相信您也可以学习 Python!如果你有任何疑问,请告诉我。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/19/11/awk-to-python
|
||||
|
||||
作者:[Moshe Zadka][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[wxy](https://github.com/wxy)
|
||||
校对:[校对者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/OSDC_women_computing_4.png?itok=VGZO8CxT (Woman sitting in front of her laptop)
|
||||
[2]: https://en.wikipedia.org/wiki/Off-by-one_error
|
||||
[3]: https://opensource.com/article/19/10/remove-duplicate-lines-files-awk
|
@ -7,34 +7,18 @@
|
||||
[#]: via: (https://www.2daygeek.com/linux-command-check-website-is-up-down-alive/)
|
||||
[#]: author: (Magesh Maruthamuthu https://www.2daygeek.com/author/magesh/)
|
||||
|
||||
6 Methods to Quickly Check if a Website is up or down from the Linux Terminal
|
||||
在 Linux Terminal 快速检测网站是否宕机的 6 个方法
|
||||
======
|
||||
|
||||
This tutorial shows you how to quickly check whether a given website is up (alive) or down from a Linux terminal.
|
||||
本教程教你怎样在 Linux terminal 快速检测一个网站是否宕机。
|
||||
|
||||
You may already know some of these commands to verify about this, namely ping, curl, and wget.
|
||||
你可能已经了解了一些类似的命令,像 ping,curl 和 wget。我们在本教程中又加入了一些其他命令。同时,对于要检测单个和多个主机的信息我们也加入了不同的选项。
|
||||
|
||||
But we have added some other commands as well in this tutorial.
|
||||
本文将帮助你检测网站是否宕机。但是如果你在维护一个网站,希望网站宕掉时得到实时的报警,我推荐你去使用实时网站监控工具。这种工具有很多,有些是免费的,大部分收费。根据你的需求,选择合适的工具。在后续的文章中我们会涉及这个主题。
|
||||
|
||||
Also, we have added various options to check this information for single host and multiple hosts.
|
||||
### 方法 1:使用 fping 命令检测一个网站是否宕机
|
||||
|
||||
This article will help you to check whether the website is up or down.
|
||||
|
||||
But if you maintain some websites and want to get real-time alerts when the website is down.
|
||||
|
||||
I recommend you to use real-time website monitoring tools. There are many tools for this, and some are free and most of them are paid.
|
||||
|
||||
So choose the preferred one based on your needs. We will cover this topic in our upcoming article.
|
||||
|
||||
### Method-1: How to Check if a Website is up or down Using the fping Command
|
||||
|
||||
**[fping command][1]** is a program such as ping, which uses the Internet Control Message Protocol (ICMP) echo request to determine whether a target host is responding.
|
||||
|
||||
fping differs from ping because it allows users to ping any number of host in parallel. Also, hosts can be entered from a text file.
|
||||
|
||||
fping sends an ICMP echo request, moves the next target in a round-robin fashion, and does not wait until the target host responds.
|
||||
|
||||
If a target host replies, it is noted as active and removed from the list of targets to check; if a target does not respond within a certain time limit and/or retry limit it is designated as unreachable.
|
||||
**[fping 命令][1]** 是一个类似 ping 的程序,使用互联网控制消息协议回应请求报文(ICMP echo request)来判断目标主机是否能回应。fping 与 ping 的不同之处在于它可以并行地 ping 任意数量的主机,也可以从一个文本文件读入主机。fping 发送一个 ICMP echo request 后不等待目标主机响应,就以 round-robin 模式向下一个目标主机发请求。如果一个目标主机有响应,那么它就被标记为存活的(active)然后从检查目标列表里去掉。如果一个目标主机在限定的时间和(或)重试次数内没有响应,则被指定为网站无法到达(unreachable)。
|
||||
|
||||
```
|
||||
# fping 2daygeek.com linuxtechnews.com magesh.co.in
|
||||
@ -44,15 +28,9 @@ linuxtechnews.com is alive
|
||||
magesh.co.in is alive
|
||||
```
|
||||
|
||||
### Method-2: How to Quickly Check Whether a Website is up or down Using the http Command
|
||||
### 方法 2:使用 http 命令检测一个网站是否宕机
|
||||
|
||||
HTTPie (pronounced aitch-tee-tee-pie) is a command line HTTP client.
|
||||
|
||||
The **[httpie tool][2]** is a modern command line http client which makes CLI interaction with web services.
|
||||
|
||||
It provides a simple http command that allows for sending arbitrary HTTP requests using a simple and natural syntax, and displays colorized output.
|
||||
|
||||
HTTPie can be used for testing, debugging, and generally interacting with HTTP servers.
|
||||
HTTPie(读作 aitch-tee-tee-pie)是一个命令行 HTTP 客户端。**[httpie tool][2]** 是一个可以与 web 服务通过 CLI(command-line interface)进行交互的现代工具。httpie tool 提供了简单的 http 命令,可以通过发送简单的、自然语言语法的任意 HTTP 请求得到多彩的结果输出。HTTPie 可以用来对 HTTP 服务器进行测试、调试和基本的交互。
|
||||
|
||||
```
|
||||
# http 2daygeek.com
|
||||
@ -69,15 +47,9 @@ Transfer-Encoding: chunked
|
||||
Vary: Accept-Encoding
|
||||
```
|
||||
|
||||
### Method-3: How to Check if a Website is up or down Using the curl Command
|
||||
### 方法 3:使用 curl 命令检测一个网站是否宕机
|
||||
|
||||
**[curl command][3]** is a tool to transfer data from a server or to server, using one of the supported protocols (DICT, FILE, FTP, FTPS, GOPHER, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, POP3, POP3S, RTMP, RTSP, SCP, SFTP, SMTP, SMTPS, TELNET and TFTP).
|
||||
|
||||
The command is designed to work without user interaction.
|
||||
|
||||
Also curl support proxy support, user authentication, FTP upload, HTTP post, SSL connections, cookies, file transfer resume, Metalink, and more.
|
||||
|
||||
curl is powered by libcurl for all transfer-related features.
|
||||
**[curl 命令](https://www.2daygeek.com/curl-linux-command-line-download-manager/)** 是一个用于在服务器间通过支持的协议(DICT, FILE, FTP, FTPS, GOPHER, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, POP3, POP3S, RTMP, RTSP, SCP, SFTP, SMTP, SMTPS, TELNET 和 TFTP)传输数据的工具。这个工具不支持用户交互。curl 也支持使用代理、用户认证、FTP 上传、HTTP post、SSL 连接、cookies、断点续传、Metalink等等。curl 由 libcurl 库提供所有与传输有关的能力。
|
||||
|
||||
```
|
||||
# curl -I https://www.magesh.co.in
|
||||
@ -95,14 +67,14 @@ server: cloudflare
|
||||
cf-ray: 535b74123ca4dbf3-LHR
|
||||
```
|
||||
|
||||
Use the following curl command if you want to see only the HTTP status code instead of entire output.
|
||||
如果你只想看 HTTP 状态码而不是返回的全部信息,用下面的 curl 命令:
|
||||
|
||||
```
|
||||
# curl -I "www.magesh.co.in" 2>&1 | awk '/HTTP\// {print $2}'
|
||||
200
|
||||
```
|
||||
|
||||
If you want to see if a given website is up or down, use the following Bash script.
|
||||
如果你想看一个网站是否宕机,用下面的 bash 脚本:
|
||||
|
||||
```
|
||||
# vi curl-url-check.sh
|
||||
@ -115,7 +87,7 @@ else
|
||||
fi
|
||||
```
|
||||
|
||||
Once you have added the above script to a file, run the file to see the output.
|
||||
当你把脚本内容添加到一个文件后,执行文件,查看结果
|
||||
|
||||
```
|
||||
# sh curl-url-check.sh
|
||||
@ -124,7 +96,7 @@ HTTP/2 200
|
||||
magesh.co.in is up
|
||||
```
|
||||
|
||||
Use the following shell script if you want to see the status of multiple websites.
|
||||
如果你想看多个网站的状态,使用下面的 shell 脚本:
|
||||
|
||||
```
|
||||
# vi curl-url-check-1.sh
|
||||
@ -141,7 +113,7 @@ echo "----------------------------------"
|
||||
done
|
||||
```
|
||||
|
||||
Once you have added the above script to a file, run the file to see the output.
|
||||
当你把上面脚本内容添加到一个文件后,执行文件,查看结果
|
||||
|
||||
```
|
||||
# sh curl-url-check-1.sh
|
||||
@ -156,13 +128,9 @@ www.xyzzz.com is down
|
||||
----------------------------------
|
||||
```
|
||||
|
||||
### Method-4: How to Quickly Check Whether a Website is up or down Using the wget Command
|
||||
### 方法 4:使用 wget 命令检测一个网站是否宕机
|
||||
|
||||
**[wget command][4]** (formerly known as Geturl) is a Free, open source, command line download tool which is retrieving files using HTTP, HTTPS and FTP, the most widely-used Internet protocols.
|
||||
|
||||
It is a non-interactive command line tool and Its name is derived from World Wide Web and get.
|
||||
|
||||
wget handle download pretty much good compared with other tools, futures included working in background, recursive download, multiple file downloads, resume downloads, non-interactive downloads & large file downloads.
|
||||
**[wget 命令][4]** (前身是 Geturl)是一个免费的开源命令行下载工具,通过 HTTP、HTTPS、FTP和其他广泛使用的互联网协议检索文件。wget 是非交互式的命令行工具,由 World Wide Web 和 get 得名。wget 相对于其他工具来说更优秀,功能包括后台运行、递归下载、多文件下载、断点续传、非交互式下载和大文件下载。
|
||||
|
||||
```
|
||||
# wget -S --spider https://www.magesh.co.in
|
||||
@ -190,14 +158,14 @@ Remote file exists and could contain further links,
|
||||
but recursion is disabled -- not retrieving.
|
||||
```
|
||||
|
||||
Use the following wget command if you want to see only the HTTP status code instead of entire output.
|
||||
如果你只想看 HTTP 状态码而不是返回的全部结果,用下面的 wget 命令:
|
||||
|
||||
```
|
||||
# wget --spider -S "www.magesh.co.in" 2>&1 | awk '/HTTP\// {print $2}'
|
||||
200
|
||||
```
|
||||
|
||||
If you want to see if a given website is up or down, use the following Bash script.
|
||||
如果你想看一个网站是否宕机,用下面的 bash 脚本:
|
||||
|
||||
```
|
||||
# vi wget-url-check.sh
|
||||
@ -210,7 +178,7 @@ else
|
||||
fi
|
||||
```
|
||||
|
||||
Once you have added the above script to a file, run the file to see the output.
|
||||
当你把脚本内容添加到一个文件后,执行文件,查看结果
|
||||
|
||||
```
|
||||
# wget-url-check.sh
|
||||
@ -219,7 +187,7 @@ HTTP/1.1 200 OK
|
||||
Google.com is up
|
||||
```
|
||||
|
||||
Use the following shell script if you want to see the status of multiple websites.
|
||||
如果你想看多个网站的状态,使用下面的 shell 脚本:
|
||||
|
||||
```
|
||||
# vi curl-url-check-1.sh
|
||||
@ -236,7 +204,7 @@ echo "----------------------------------"
|
||||
done
|
||||
```
|
||||
|
||||
Once you have added the above script to a file, run the file to see the output.
|
||||
当你把上面脚本内容添加到一个文件后,执行文件,查看结果:
|
||||
|
||||
```
|
||||
# sh wget-url-check-1.sh
|
||||
@ -251,9 +219,9 @@ www.xyzzz.com is down
|
||||
----------------------------------
|
||||
```
|
||||
|
||||
### Method-5: How to Quickly Check Whether a Website is up or down Using the lynx Command
|
||||
### 方法 5:使用 lynx 命令检测一个网站是否宕机
|
||||
|
||||
**[lynx][5]** is a highly configurable text-based web browser for use on cursor-addressable character cell terminals. It’s the oldest web browser and it’s still in active development.
|
||||
**[lynx][5]** 是一个在可寻址光标字符单元终端上使用的基于文本的高度可配的 web 浏览器,它是最古老的 web 浏览器并且现在仍在开发。
|
||||
|
||||
```
|
||||
# lynx -head -dump http://www.magesh.co.in
|
||||
@ -272,14 +240,14 @@ Server: cloudflare
|
||||
CF-RAY: 535fc5704a43e694-LHR
|
||||
```
|
||||
|
||||
Use the following lynx command if you want to see only the HTTP status code instead of entire output.
|
||||
如果你只想看 HTTP 状态码而不是返回的全部结果,用下面的 lynx 命令:
|
||||
|
||||
```
|
||||
# lynx -head -dump https://www.magesh.co.in 2>&1 | awk '/HTTP\// {print $2}'
|
||||
200
|
||||
```
|
||||
|
||||
If you want to see if a given website is up or down, use the following Bash script.
|
||||
如果你想看一个网站是否宕机,用下面的 bash 脚本:
|
||||
|
||||
```
|
||||
# vi lynx-url-check.sh
|
||||
@ -292,7 +260,7 @@ else
|
||||
fi
|
||||
```
|
||||
|
||||
Once you have added the above script to a file, run the file to see the output.
|
||||
当你把脚本内容添加到一个文件后,执行文件,查看结果
|
||||
|
||||
```
|
||||
# sh lynx-url-check.sh
|
||||
@ -301,7 +269,7 @@ HTTP/1.1 200 OK
|
||||
magesh.co.in is up
|
||||
```
|
||||
|
||||
Use the following shell script if you want to see the status of multiple websites.
|
||||
如果你想看多个网站的状态,使用下面的 shell 脚本:
|
||||
|
||||
```
|
||||
# vi lynx-url-check-1.sh
|
||||
@ -318,7 +286,7 @@ echo "----------------------------------"
|
||||
done
|
||||
```
|
||||
|
||||
Once you have added the above script to a file, run the file to see the output.
|
||||
当你把上面脚本内容添加到一个文件后,执行文件,查看结果:
|
||||
|
||||
```
|
||||
# sh lynx-url-check-1.sh
|
||||
@ -333,13 +301,9 @@ www.xyzzz.com is down
|
||||
----------------------------------
|
||||
```
|
||||
|
||||
### Method-6: How to Check if a Website is up or down Using the ping Command
|
||||
### 方法 6:使用 ping 命令检测一个网站是否宕机
|
||||
|
||||
**[ping command][1]** stands for (Packet Internet Groper) command is a networking utility that used to test the target of a host availability/connectivity on an Internet Protocol (IP) network.
|
||||
|
||||
It’s verify a host availability by sending Internet Control Message Protocol (ICMP) Echo Request packets to the target host and waiting for an ICMP Echo Reply.
|
||||
|
||||
It summarize statistical results based on the packets transmitted, packets received, packet loss, typically including the min/avg/max times.
|
||||
**[ping 命令][1]** (Packet Internet Groper)是网络工具的代表,用于在互联网协议(IP)的网络中测试一个目标主机是否可用/可连接。通过向目标主机发送 ICMP 回应请求报文包并等待 ICMP 回应响应报文来检测主机的可用性。它基于已发送的包、接收到的包和丢失了的包来统计结果数据,通常包含最小/平均/最大响应时间。
|
||||
|
||||
```
|
||||
# ping -c 5 2daygeek.com
|
||||
@ -356,15 +320,9 @@ PING 2daygeek.com (104.27.157.177) 56(84) bytes of data.
|
||||
rtt min/avg/max/mdev = 170.668/213.824/250.295/28.320 ms
|
||||
```
|
||||
|
||||
### Method-7: How to Quickly Check Whether a Website is up or down Using the telnet Command
|
||||
### 方法 7:使用 telnet 命令检测一个网站是否宕机
|
||||
|
||||
The Telnet command is an old network protocol used to communicate with another host over a TCP/IP network using the TELNET protocol.
|
||||
|
||||
It uses port 23 to connect to other devices, such as computer and network equipment.
|
||||
|
||||
Telnet is not a secure protocol and is now not recommended to use because the data sent to the protocol is not encrypted and can be intercepted by hackers.
|
||||
|
||||
Everyone uses SSH protocol instead of telnet, which is encrypted and very secure.
|
||||
telnet 命令是一个使用 TELNET 协议用于 TCP/IP 网络中多个主机相互通信的古老的网络协议。它通过 23 端口连接其他设备如计算机和网络设备。telnet 是不安全的协议,现在由于用这个协议发送的数据没有经过加密可能被黑客拦截,所以不推荐使用。大家都使用经过加密且非常安全的 SSH 协议来代替 telnet。
|
||||
|
||||
```
|
||||
# telnet google.com 80
|
||||
@ -377,13 +335,11 @@ telnet> quit
|
||||
Connection closed.
|
||||
```
|
||||
|
||||
### Method-8: How to Check if a Website is up or down Using the Bash Script
|
||||
### 方法 8:使用 bash 脚本检测一个网站是否宕机
|
||||
|
||||
In simple words, a **[shell script][6]** is a file that contains a series of commands. The shell reads this file and executes the commands one by one as they are entered directly on the command line.
|
||||
简而言之,一个 **[shell 脚本][6]** 就是一个包含一系列命令的文件。shell 从文件读取内容按输入顺序逐行在命令行执行。为了让它更有效,我们添加一些条件。这也减轻了 Linux 管理员的负担。
|
||||
|
||||
To make this more useful we can add some conditions. This reduces the Linux admin task.
|
||||
|
||||
If you want to see the status of multiple websites using the wget command, use the following shell script.
|
||||
如果你想想用 wget 命令看多个网站的状态,使用下面的 shell 脚本:
|
||||
|
||||
```
|
||||
# vi wget-url-check-2.sh
|
||||
@ -399,7 +355,7 @@ fi
|
||||
done
|
||||
```
|
||||
|
||||
Once you have added the above script to a file, run the file to see the output.
|
||||
当你把上面脚本内容添加到一个文件后,执行文件,查看结果:
|
||||
|
||||
```
|
||||
# sh wget-url-check-2.sh
|
||||
@ -409,7 +365,7 @@ google.co.in is up
|
||||
www.xyzzz.com is down
|
||||
```
|
||||
|
||||
If you want to see the status of multiple websites using the curl command, use the following **[bash script][7]**.
|
||||
如果你想想用 wget 命令看多个网站的状态,使用下面的 **[shell 脚本][7]**:
|
||||
|
||||
```
|
||||
# vi curl-url-check-2.sh
|
||||
@ -425,7 +381,7 @@ fi
|
||||
done
|
||||
```
|
||||
|
||||
Once you have added the above script to a file, run the file to see the output.
|
||||
当你把上面脚本内容添加到一个文件后,执行文件,查看结果:
|
||||
|
||||
```
|
||||
# sh curl-url-check-2.sh
|
||||
@ -441,7 +397,7 @@ via: https://www.2daygeek.com/linux-command-check-website-is-up-down-alive/
|
||||
|
||||
作者:[Magesh Maruthamuthu][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
译者:[lxbwolf](https://github.com/lxbwolf)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
Loading…
Reference in New Issue
Block a user