mirror of
https://github.com/LCTT/TranslateProject.git
synced 2024-12-26 21:30:55 +08:00
Merge branch 'master' of https://github.com/LCTT/TranslateProject into translating
This commit is contained in:
commit
c868f51bc6
200
published/20191004 What-s in an open source name.md
Normal file
200
published/20191004 What-s in an open source name.md
Normal file
@ -0,0 +1,200 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (laingke)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11688-1.html)
|
||||
[#]: subject: (What's in an open source name?)
|
||||
[#]: via: (https://opensource.com/article/19/10/open-source-name-origins)
|
||||
[#]: author: (Joshua Allen Holm https://opensource.com/users/holmja)
|
||||
|
||||
开源软件名称中的故事
|
||||
======
|
||||
|
||||
> 有没有想过你喜欢的开源项目或编程语言的名称来自何处?让我们按字母顺序了解一下流行的技术术语背后的起源故事。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/201912/17/225902ogkk85zm4gqlim9h.jpg)
|
||||
|
||||
GNOME、Java、Jupyter、Python……如果你的朋友或家人曾留意过你的工作对话,他们可能会认为你从事文艺复兴时期的民间文学艺术、咖啡烘焙、天文学或动物学工作。这些开源技术的名称从何而来?我们请我们的作者社区提供意见,并汇总了一些我们最喜欢的技术名称的起源故事。
|
||||
|
||||
### Ansible
|
||||
|
||||
“Ansible”这个名称直接来自科幻小说。Ursula Le Guin 的《Rocannon's World》一书中能进行即时(比光速更快)通信的设备被称为 ansibles(显然来自 “answerable” 一词)。Ansibles 开始流行于科幻小说之中,Orson Scott Card 的《Ender's Game》(后来成为受欢迎的电影)中,该设备控制了许多远程太空飞船。对于控制分布式机器的软件来说,这似乎是一个很好的模型,因此 Michael DeHaan(Ansible 的创建者和创始人)借用了这个名称。
|
||||
|
||||
### Apache
|
||||
|
||||
[Apache][2] 是最初于 1995 年发布的开源 Web 服务器。它的名称与著名的美国原住民部落无关;相反,它是指对原始软件代码的重复补丁。因此称之为,“<ruby>一个修补的<rt>A-patchy</rt></ruby>服务器”。
|
||||
|
||||
### awk
|
||||
|
||||
“awk(1) 代表着 Aho、Weinberger、Kernighan(作者)”—— Michael Greenberg
|
||||
|
||||
### Bash
|
||||
|
||||
“最初的 Unix shell,即 Bourne shell,是以其创造者的名字命名的。在开发出来 Bash 时,csh(发音为 ‘seashell’)实际上更受交互登录用户的欢迎。Bash 项目旨在赋予 Bourne shell 新的生命,使其更适合于交互式使用,因此它被命名为 ‘Bourne again shell’,是‘<ruby>重生<rt>born again</rt></ruby>’的双关语。”——Ken Gaillot
|
||||
|
||||
### C
|
||||
|
||||
在早期,AT&T 的 Ken Thompson 和 Dennis Ritchie 发现可以使用更高级的编程语言(而不是低级的、可移植性更低的汇编编程)来编写操作系统和工具。早期有一个叫做 BCPL(<ruby>基本组合编程语言<rt>Basic Combined programming Language</rt></ruby>)的编程系统,Thompson 创建了一个名为 B 的简化版 BCPL,但 B 的灵活性和速度都不高。然后,Ritchie 把 B 的思想扩展成一种叫做 C 的编译语言。”——Jim Hall
|
||||
|
||||
### dd
|
||||
|
||||
“我想你发表这样一篇文章不能不提到 dd。我的外号叫 Didi。发音正确的话听起来像 ‘dd’。我开始学的是 Unix,然后是 Linux,那是在 1993 年,当时我还是个学生。然后我去了军队,来到了我的部队中少数几个使用 Unix(Ultrix)的部门之一(其它部门主要是 VMS),那里的一个人说:‘这么说,你是一个黑客,对吗?你以为你了解 Unix 吗?好的,那么 dd 这个名字的是怎么来的呢?’我不知道,试着猜道:‘<ruby>数据复印机<rt>Data duplicator</rt></ruby>?’所以他说,‘我要告诉你 dd 的故事。dd 是<ruby>转换<rt>convert</rt></ruby>和<ruby>复制<rt>copy</rt></ruby>的缩写(如今人们仍然可以在手册页中看到),但由于 cc 这个缩写已经被 C 编译器占用,所以它被命名为 dd。’就在几年后,我听闻了关于 JCL 的数据定义和 Unix dd 命令不统一的、半开玩笑的语法的真实故事,某种程度是基于此的。”——Yedidyah Bar David
|
||||
|
||||
### Emacs
|
||||
|
||||
经典的<ruby>反 vi<rt>anti-vi</rt></ruby>编辑器,其名称的真正词源并不明显,因为它源自“<ruby>编辑宏<rt>Editing MACroS</rt></ruby>”。但是,它作为一个伟大的宗教亵渎和崇拜的对象,吸引了许多恶作剧般的缩写,例如“Escape Meta Alt Control Shift”(以调侃其对键盘的大量依赖),“<ruby>8MB 并经常发生内存交换<rt>Eight Megabytes And Constantly Swapping</rt></ruby>”(从那时起就很吃内存了),“<ruby>最终分配了所有的计算机存储空间<rt>Eventually malloc()s All Computer Storage</rt></ruby>”和 “<ruby>EMACS 使一台计算机慢<rt>EMACS Makes A Computer Slow</rt></ruby>”——改编自 Jargon File/Hacker's Dictionary
|
||||
|
||||
### Enarx
|
||||
|
||||
[Enarx][3] 是机密计算领域的一个新项目。该项目的设计原则之一是它应该是“可替代的”。因此最初的名字是“psilocybin”(著名的魔术蘑菇)。一般情况下,经理级别的人可能会对这个名称有所抵触,因此考虑使用新名称。该项目的两位创始人 Mike Bursell 和 Nathaniel McCallum 都是古老语言极客,因此他们考虑了许多不同的想法,包括 тайна(Tayna——俄语中代表秘密或神秘——虽然俄语并不是一门古老的语言,但你就不要在乎这些细节了),crypticon(希腊语的意思是完全私生的),cryptidion(希腊中表示小密室),arconus(拉丁语中表示秘密的褒义形容词),arcanum(拉丁语中表示秘密的中性形容词)和 ærn(盎格鲁撒克逊人表示地方、秘密的地方、壁橱、住所、房子,或小屋的词汇)。最后,由于各种原因,包括域名和 GitHub 项目名称的可用性,他们选择了 enarx,这是两个拉丁词根的组合:en-(表示内部)和 -arx(表示城堡、要塞或堡垒)。
|
||||
|
||||
### GIMP
|
||||
|
||||
没有 [GIMP][4] 我们会怎么样?<ruby>GNU 图像处理项目<rt>GNU Image Manipulation Project</rt></ruby>多年来一直是开源的重要基础。[维基百科][5]指出,“1995 年,[Spencer Kimball][6] 和 [Peter Mattis][7] 在加州大学伯克利分校开始为<ruby>实验计算设施<rt>eXperimental Computing Facility</rt></ruby>开发 GIMP,这是一个为期一个学期的项目。”
|
||||
|
||||
### GNOME
|
||||
|
||||
你有没有想过为什么 GNOME 被称为 GNOME?根据[维基百科][8],GNOME 最初是一个表示“<ruby>GNU 网络对象模型环境<rt>GNU Network Object Model Environment</rt></ruby>”的缩写词。现在,该名称不再表示该项目,并且该项目已被放弃,但这个名称仍然保留了下来。[GNOME 3][9] 是 Fedora、红帽企业版、Ubuntu、Debian、SUSE Linux 企业版等发行版的默认桌面环境。
|
||||
|
||||
### Java
|
||||
|
||||
你能想象这种编程语言还有其它名称吗?Java 最初被称为 Oak,但是遗憾的是,Sun Microsystems 的法律团队由于已有该商标而否决了它。所以开发团队又重新给它命名。[据说][10]该语言的工作组在 1995 年 1 月举行了一次大规模的头脑风暴。许多其它名称也被扔掉了,包括 Silk、DNA、WebDancer 等。该团队不希望新名称与过度使用的术语“web”或“net”有任何关系。取而代之的是,他们在寻找更有活力、更有趣、更容易记住的东西。Java 满足了这些要求,并且奇迹般地,团队同意通过了!
|
||||
|
||||
### Jupyter
|
||||
|
||||
现在许多数据科学家和学生在工作中使用 [Jupyter][11] 笔记本。“Jupyter”这个名字是三种开源计算机语言的融合,这三种语言在这个笔记本中都有使用,在数据科学中也很突出:[Julia][12]、[Python][13] 和 [R][14]。
|
||||
|
||||
### Kubernetes
|
||||
|
||||
Kubernetes 源自希腊语中的舵手。Kubernetes 项目创始人 Craig McLuckie 在 [2015 Hacker News][15] 回应中证实了这种词源。他坚持航海主题,解释说,这项技术可以驱动集装箱,就像舵手或驾驶员驾驶集装箱船一样,因此,他选择了 Kubernetes 这个名字。我们中的许多人仍然在尝试正确的发音(koo-bur-NET-eez),因此 替代使用 K8s 也是可以接受的。有趣的是,它与英语单词“<ruby>行政长官<rt>governor</rt></ruby>”具有相同的词源,也与蒸汽机上的机械负反馈装置相同。
|
||||
|
||||
### KDE
|
||||
|
||||
那 K 桌面呢?KDE 最初代表“<ruby>酷桌面环境<rt>Kool Desktop Environment</rt></ruby>”。 它由 [Matthias Ettrich][16] 于 1996 年创立。根据[维基百科][17]上的说法,该名称是对 Unix 上 <ruby>[通用桌面环境][18]<rt>Common Desktop Environment</rt></ruby>(CDE)一词的调侃。
|
||||
|
||||
### Linux
|
||||
|
||||
[Linux][19] 因其发明者 Linus Torvalds 的名字命名的。Linus 最初想将他的作品命名为“Freax”,因为他认为以他自己的名字命名太自负了。根据[维基百科][19]的说法,“赫尔辛基科技大学 Torvalds 的同事 Ari Lemmke 当时是 FTP 服务器的志愿管理员之一,他并不认为‘Freax’是个好名字。因此,他没有征询 Torvalds 就将服务器上的这个项目命名为‘Linux’。”
|
||||
|
||||
以下是一些最受欢迎的 Linux 发行版。
|
||||
|
||||
#### CentOS
|
||||
|
||||
[CentOS][20] 是<ruby>社区企业操作系统<rt>Community Enterprise Operating System</rt></ruby>的缩写。它包含来自 Red Hat Enterprise Linux 的上游软件包。
|
||||
|
||||
#### Debian
|
||||
|
||||
[Debian][21] Linux 创建于 1993 年 9 月,是其创始人 Ian Murdock 和他当时的女友 Debra Lynn 的名字的混成词。
|
||||
|
||||
#### RHEL
|
||||
|
||||
[Red Hat Linux][22] 得名于它的创始人 Marc Ewing,他戴着一顶祖父送给他的康奈尔大学红色<ruby>软呢帽<rt>fedora</rt></ruby>。红帽公司成立于 1993 年 3 月 26 日。[Fedora Linux][23] 最初是一个志愿者项目,旨在为红帽发行版提供额外的软件,它的名字来自红帽的“Shadowman”徽标。
|
||||
|
||||
#### Ubuntu
|
||||
|
||||
[Ubuntu][24] 旨在广泛分享开源软件,它以非洲哲学“<ruby>人的本质<rt>ubuntu</rt></ruby>”命名,可以翻译为“对他人的人道主义”或“我之所以是我,是因为我们都是这样的人”。
|
||||
|
||||
### Moodle
|
||||
|
||||
开源学习平台 [Moodle][25] 是“<ruby>模块化面向对象动态学习环境<rt>modular object-oriented dynamic learning environment</rt></ruby>”的首字母缩写。Moodle 仍然是领先的线上学习平台。全球有近 10.4 万个注册的 Moodle 网站。
|
||||
|
||||
另外两个流行的开源内容管理系统是 Drupal 和 Joomla。Drupal 的名字来自荷兰语 “druppel”,意思是“掉落”。根据维基百科,Joomla 是斯瓦希里语单词“jumla”的[英式拼写][26],在阿拉伯语、乌尔都语和其他语言中是“在一起”的意思。
|
||||
|
||||
### Mozilla
|
||||
|
||||
[Mozilla][27] 是一个成立于 1998 年的开源软件社区。根据其网站,“Mozilla 项目创建于 1998 年,发布了 Netscape 浏览器套件源代码。其旨在利用互联网上成千上万的程序员的创造力,并推动浏览器市场上前所未有的创新水平。” 这个名字是 [Mosaic] [28] 和 Godzilla 的混成词。
|
||||
|
||||
### Nginx
|
||||
|
||||
“许多技术人员都试图装酷,并将它念成‘n’‘g’‘n’‘x’。实际上,很少的一些人做点基本的调查工作,就可以很快发现该名称实际上应该被念成是“EngineX”,指的是功能强大的 web 服务器,像个引擎。”——Jean Sebastien Tougne
|
||||
|
||||
### Perl
|
||||
|
||||
Perl 的创始人 Larry Wall 最初将他的项目命名为“Pearl”。根据维基百科,Wall 想给这种语言起一个有积极含义的简短名字。在 Perl 正式发布之前,Wall 发现了已有 [PEARL][29] 编程语言,于是更改了名称的拼写。
|
||||
|
||||
### Piet 和 Mondrian
|
||||
|
||||
“有两种编程语言以艺术家 Piet Mondrian 命名。一种叫做‘Piet’,另一种叫做‘Mondrian’。(David Morgan-Mar [写道][30]):‘Piet 是一种编程语言,其中的程序看起来像抽象绘画。该语言以几何抽象艺术的开创者 Piet Mondrian 的名字命名。我曾想将这种语言命名为 Mondrian,但是有人告诉我这会让它看起来像一种很普通的脚本语言。哦,好吧,我想我们不能都是深奥的语言作家。’”——Yuval Lifshitz
|
||||
|
||||
### Python
|
||||
|
||||
Python 编程语言的独特名称来自其创建者 Guido Van Rossum,他是英国六人喜剧团体 Monty Python 的粉丝。
|
||||
|
||||
### Raspberry Pi
|
||||
|
||||
Raspberry Pi 以其微小但强大的功能和对低廉的价格而闻名,在开源社区中是最受欢迎的。但是它可爱(和好吃)的名字是从哪里来的呢?在 70 年代和 80 年代,以水果命名的计算机是一种流行的趋势。苹果、橘子、杏……有人饿了吗?根据创始人 Eben Upton 的 [2012 采访] [31],“<ruby>树莓派<rt>Raspberry Pi</rt></ruby>”这个名称是对这种趋势的致敬。树莓也很小,但却很有味道。名称中的“Pi”暗示着这样的事实:最初,该计算机只能运行 Python。
|
||||
|
||||
### Samba
|
||||
|
||||
[Server Message Block][32] 用于在 Linux 上共享 Windows 文件。
|
||||
|
||||
### ScummVM
|
||||
|
||||
[ScummVM][33](《疯狂大楼》虚拟机的脚本创建实用程序)是一个程序,可以在现代计算机上运行一些经典的计算机冒险游戏。最初,它旨在玩用 SCUMM 构建的 LucasArts 的冒险游戏,该游戏最初用于开发《疯狂大楼》,后来又被用来开发 LucasArts 的其它大多数冒险游戏。目前,ScummVM 支持大量游戏引擎,包括 Sierra Online 的 AGI 和 SCI,但仍保留着名称 ScummVM。
|
||||
|
||||
有一个相关的项目 [ResidualVM][34] 之所以得名,是因为它涵盖了 ScummVM 未涵盖的“<ruby>剩余的<rt>residual</rt></ruby>” LucasArts 冒险游戏。 ResidualVM 涵盖的 LucasArts 游戏是使用 GrimE(Grim Engine)开发的,该引擎最初用于开发 Grim Fandango,因此 ResidualVM 的名称是双关语。
|
||||
|
||||
### SQL
|
||||
|
||||
“你可能知道 SQL 代表<ruby>结构化查询语言<rt>Structured Query Language</rt></ruby>,但你知道为什么它经常被读作‘sequel’吗?它是作为原本的‘QUEL’(<ruby>查询语言<rt>QUEry Language</rt></ruby>)的后续(如<ruby>结局<rt>sequel</rt></ruby>)而创建的。”——Ken Gaillot
|
||||
|
||||
### XFCE
|
||||
|
||||
[XFCE][35] 是由 [Olivier Fourdan][36] 创建的一个流行的桌面。它在 1996 年作为 CDE 的替代品出现,最初是 <ruby>XForms 公共环境<rt>XForms Common Environment</rt></ruby>的缩写。
|
||||
|
||||
### Zsh
|
||||
|
||||
Zsh 是一个交互式登录 shell。1990 年,普林斯顿大学的学生 Paul Falstad 写了该 shell 的第一个版本。他在看到当时在普林斯顿大学担任助教的 Zhong Sha 的登录 ID(zsh)后,觉得这个名字听起来像 [shell 的好名字][37],给它起了这个名字。
|
||||
|
||||
还有更多的项目和名称还没有包括在这个列表中。请一定要在评论中分享你的收藏。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/19/10/open-source-name-origins
|
||||
|
||||
作者:[Joshua Allen Holm][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[laingke](https://github.com/laingke)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/holmja
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/rh_003784_02_os.comcareers_resume_rh1x.png?itok=S3HGxi6E (A person writing.)
|
||||
[2]: https://httpd.apache.org/
|
||||
[3]: https://enarx.io
|
||||
[4]: https://www.gimp.org/
|
||||
[5]: https://en.wikipedia.org/wiki/GIMP
|
||||
[6]: https://en.wikipedia.org/wiki/Spencer_Kimball_(computer_programmer)
|
||||
[7]: https://en.wikipedia.org/wiki/Peter_Mattis
|
||||
[8]: https://en.wikipedia.org/wiki/GNOME
|
||||
[9]: https://www.gnome.org/gnome-3/
|
||||
[10]: https://www.javaworld.com/article/2077265/so-why-did-they-decide-to-call-it-java-.html
|
||||
[11]: https://jupyter.org/
|
||||
[12]: https://julialang.org/
|
||||
[13]: https://www.python.org/
|
||||
[14]: https://www.r-project.org/
|
||||
[15]: https://news.ycombinator.com/item?id=9653797
|
||||
[16]: https://en.wikipedia.org/wiki/Matthias_Ettrich
|
||||
[17]: https://en.wikipedia.org/wiki/KDE
|
||||
[18]: https://sourceforge.net/projects/cdesktopenv/
|
||||
[19]: https://en.wikipedia.org/wiki/Linux
|
||||
[20]: https://www.centos.org/
|
||||
[21]: https://www.debian.org/
|
||||
[22]: https://www.redhat.com/en/technologies/linux-platforms/enterprise-linux
|
||||
[23]: https://getfedora.org/
|
||||
[24]: https://ubuntu.com/about
|
||||
[25]: https://moodle.org/
|
||||
[26]: https://en.wikipedia.org/wiki/Joomla#Historical_background
|
||||
[27]: https://www.mozilla.org/en-US/
|
||||
[28]: https://en.wikipedia.org/wiki/Mosaic_(web_browser)
|
||||
[29]: https://en.wikipedia.org/wiki/PEARL_(programming_language)
|
||||
[30]: http://www.dangermouse.net/esoteric/piet.html
|
||||
[31]: https://www.techspot.com/article/531-eben-upton-interview/
|
||||
[32]: https://www.samba.org/
|
||||
[33]: https://www.scummvm.org/
|
||||
[34]: https://www.residualvm.org/
|
||||
[35]: https://www.xfce.org/
|
||||
[36]: https://en.wikipedia.org/wiki/Olivier_Fourdan
|
||||
[37]: http://www.zsh.org/mla/users/2005/msg00951.html
|
@ -0,0 +1,467 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (lxbwolf)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-11687-1.html)
|
||||
[#]: subject: (How to program with Bash: Logical operators and shell expansions)
|
||||
[#]: via: (https://opensource.com/article/19/10/programming-bash-logical-operators-shell-expansions)
|
||||
[#]: author: (David Both https://opensource.com/users/dboth)
|
||||
|
||||
怎样用 Bash 编程:逻辑操作符和 shell 扩展
|
||||
======
|
||||
|
||||
> 学习逻辑操作符和 shell 扩展,本文是三篇 Bash 编程系列的第二篇。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/201912/17/173459pxhz0aiicimzd1m2.jpg)
|
||||
|
||||
Bash 是一种强大的编程语言,完美契合命令行和 shell 脚本。本系列(三篇文章,基于我的 [三集 Linux 自学课程][2])讲解如何在 CLI 使用 Bash 编程。
|
||||
|
||||
[第一篇文章][3] 讲解了 Bash 的一些简单命令行操作,包括如何使用变量和控制操作符。第二篇文章探讨文件、字符串、数字等类型和各种各样在执行流中提供控制逻辑的的逻辑运算符,还有 Bash 中的各类 shell 扩展。本系列第三篇也是最后一篇文章,将会探索能重复执行操作的 `for` 、`while` 和 `until` 循环。
|
||||
|
||||
逻辑操作符是程序中进行判断的根本要素,也是执行不同的语句组合的依据。有时这也被称为流控制。
|
||||
|
||||
### 逻辑操作符
|
||||
|
||||
Bash 中有大量的用于不同条件表达式的逻辑操作符。最基本的是 `if` 控制结构,它判断一个条件,如果条件为真,就执行一些程序语句。操作符共有三类:文件、数字和非数字操作符。如果条件为真,所有的操作符返回真值(`0`),如果条件为假,返回假值(`1`)。
|
||||
|
||||
这些比较操作符的函数语法是,一个操作符加一个或两个参数放在中括号内,后面跟一系列程序语句,如果条件为真,程序语句执行,可能会有另一个程序语句列表,该列表在条件为假时执行:
|
||||
|
||||
|
||||
```
|
||||
if [ arg1 operator arg2 ] ; then list
|
||||
或
|
||||
if [ arg1 operator arg2 ] ; then list ; else list ; fi
|
||||
```
|
||||
|
||||
像例子中那样,在比较表达式中,空格不能省略。中括号的每部分,`[` 和 `]`,是跟 `test` 命令一样的传统的 Bash 符号:
|
||||
|
||||
```
|
||||
if test arg1 operator arg2 ; then list
|
||||
```
|
||||
|
||||
还有一个更新的语法能提供一点点便利,一些系统管理员比较喜欢用。这种格式对于不同版本的 Bash 和一些 shell 如 ksh(Korn shell)兼容性稍差。格式如下:
|
||||
|
||||
```
|
||||
if [[ arg1 operator arg2 ]] ; then list
|
||||
```
|
||||
|
||||
#### 文件操作符
|
||||
|
||||
文件操作符是 Bash 中一系列强大的逻辑操作符。图表 1 列出了 20 多种不同的 Bash 处理文件的操作符。在我的脚本中使用频率很高。
|
||||
|
||||
操作符 | 描述
|
||||
---|---
|
||||
`-a filename` | 如果文件存在,返回真值;文件可以为空也可以有内容,但是只要它存在,就返回真值
|
||||
`-b filename` | 如果文件存在且是一个块设备,如 `/dev/sda` 或 `/dev/sda1`,则返回真值
|
||||
`-c filename` | 如果文件存在且是一个字符设备,如 `/dev/TTY1`,则返回真值
|
||||
`-d filename` | 如果文件存在且是一个目录,返回真值
|
||||
`-e filename` | 如果文件存在,返回真值;与上面的 `-a` 相同
|
||||
`-f filename` | 如果文件存在且是一个一般文件,不是目录、设备文件或链接等的其他的文件,则返回 真值
|
||||
`-g filename` | 如果文件存在且 `SETGID` 标记被设置在其上,返回真值
|
||||
`-h filename` | 如果文件存在且是一个符号链接,则返回真值
|
||||
`-k filename` | 如果文件存在且粘滞位已设置,则返回真值
|
||||
`-p filename` | 如果文件存在且是一个命名的管道(FIFO),返回真值
|
||||
`-r filename` | 如果文件存在且有可读权限(它的可读位被设置),返回真值
|
||||
`-s filename` | 如果文件存在且大小大于 0,返回真值;如果一个文件存在但大小为 0,则返回假值
|
||||
`-t fd` | 如果文件描述符 `fd` 被打开且被关联到一个终端设备上,返回真值
|
||||
`-u filename` | 如果文件存在且它的 `SETUID` 位被设置,返回真值
|
||||
`-w filename` | 如果文件存在且有可写权限,返回真值
|
||||
`-x filename` | 如果文件存在且有可执行权限,返回真值
|
||||
`-G filename` | 如果文件存在且文件的组 ID 与当前用户相同,返回真值
|
||||
`-L filename` | 如果文件存在且是一个符号链接,返回真值(同 `-h`)
|
||||
`-N filename` | 如果文件存在且从文件上一次被读取后文件被修改过,返回真值
|
||||
`-O filename` | 如果文件存在且你是文件的拥有者,返回真值
|
||||
`-S filename` | 如果文件存在且文件是套接字,返回真值
|
||||
`file1 -ef file2` | 如果文件 `file1` 和文件 `file2` 指向同一设备的同一 INODE 号,返回真值(即硬链接)
|
||||
`file1 -nt file2` | 如果文件 `file1` 比 `file2` 新(根据修改日期),或 `file1` 存在而 `file2` 不存在,返回真值
|
||||
`file1 -ot file2` | 如果文件 `file1` 比 `file2` 旧(根据修改日期),或 `file1` 不存在而 `file2` 存在
|
||||
|
||||
*图表 1:Bash 文件操作符*
|
||||
|
||||
以测试一个文件存在与否来举例:
|
||||
|
||||
```
|
||||
[student@studentvm1 testdir]$ File="TestFile1" ; if [ -e $File ] ; then echo "The file $File exists." ; else echo "The file $File does not exist." ; fi
|
||||
The file TestFile1 does not exist.
|
||||
[student@studentvm1 testdir]$
|
||||
```
|
||||
|
||||
创建一个用来测试的文件,命名为 `TestFile1`。目前它不需要包含任何数据:
|
||||
|
||||
```
|
||||
[student@studentvm1 testdir]$ touch TestFile1
|
||||
```
|
||||
|
||||
在这个简短的 CLI 程序中,修改 `$File` 变量的值相比于在多个地方修改表示文件名的字符串的值要容易:
|
||||
|
||||
```
|
||||
[student@studentvm1 testdir]$ File="TestFile1" ; if [ -e $File ] ; then echo "The file $File exists." ; else echo "The file $File does not exist." ; fi
|
||||
The file TestFile1 exists.
|
||||
[student@studentvm1 testdir]$
|
||||
```
|
||||
|
||||
现在,运行一个测试来判断一个文件是否存在且长度不为 0(表示它包含数据)。假设你想判断三种情况:
|
||||
|
||||
1. 文件不存在;
|
||||
2. 文件存在且为空;
|
||||
3. 文件存在且包含数据。
|
||||
|
||||
因此,你需要一组更复杂的测试代码 — 为了测试所有的情况,使用 `if-elif-else` 结构中的 `elif` 语句:
|
||||
|
||||
```
|
||||
[student@studentvm1 testdir]$ File="TestFile1" ; if [ -s $File ] ; then echo "$File exists and contains data." ; fi
|
||||
[student@studentvm1 testdir]$
|
||||
```
|
||||
|
||||
在这个情况中,文件存在但不包含任何数据。向文件添加一些数据再运行一次:
|
||||
|
||||
```
|
||||
[student@studentvm1 testdir]$ File="TestFile1" ; echo "This is file $File" > $File ; if [ -s $File ] ; then echo "$File exists and contains data." ; fi
|
||||
TestFile1 exists and contains data.
|
||||
[student@studentvm1 testdir]$
|
||||
```
|
||||
|
||||
这组语句能返回正常的结果,但是仅仅是在我们已知三种可能的情况下测试某种确切的条件。添加一段 `else` 语句,这样你就可以更精确地测试。把文件删掉,你就可以完整地测试这段新代码:
|
||||
|
||||
```
|
||||
[student@studentvm1 testdir]$ File="TestFile1" ; rm $File ; if [ -s $File ] ; then echo "$File exists and contains data." ; else echo "$File does not exist or is empty." ; fi
|
||||
TestFile1 does not exist or is empty.
|
||||
```
|
||||
|
||||
现在创建一个空文件用来测试:
|
||||
|
||||
```
|
||||
[student@studentvm1 testdir]$ File="TestFile1" ; touch $File ; if [ -s $File ] ; then echo "$File exists and contains data." ; else echo "$File does not exist or is empty." ; fi
|
||||
TestFile1 does not exist or is empty.
|
||||
```
|
||||
|
||||
向文件添加一些内容,然后再测试一次:
|
||||
|
||||
```
|
||||
[student@studentvm1 testdir]$ File="TestFile1" ; echo "This is file $File" > $File ; if [ -s $File ] ; then echo "$File exists and contains data." ; else echo "$File does not exist or is empty." ; fi
|
||||
TestFile1 exists and contains data.
|
||||
```
|
||||
|
||||
现在加入 `elif` 语句来辨别是文件不存在还是文件为空:
|
||||
|
||||
```
|
||||
[student@studentvm1 testdir]$ File="TestFile1" ; touch $File ; if [ -s $File ] ; then echo "$File exists and contains data." ; elif [ -e $File ] ; then echo "$File exists and is empty." ; else echo "$File does not exist." ; fi
|
||||
TestFile1 exists and is empty.
|
||||
[student@studentvm1 testdir]$ File="TestFile1" ; echo "This is $File" > $File ; if [ -s $File ] ; then echo "$File exists and contains data." ; elif [ -e $File ] ; then echo "$File exists and is empty." ; else echo "$File does not exist." ; fi
|
||||
TestFile1 exists and contains data.
|
||||
[student@studentvm1 testdir]$
|
||||
```
|
||||
|
||||
现在你有一个可以测试这三种情况的 Bash CLI 程序,但是可能的情况是无限的。
|
||||
|
||||
如果你能像保存在文件中的脚本那样组织程序语句,那么即使对于更复杂的命令组合也会很容易看出它们的逻辑结构。图表 2 就是一个示例。 `if-elif-else` 结构中每一部分的程序语句的缩进让逻辑更变得清晰。
|
||||
|
||||
|
||||
```
|
||||
File="TestFile1"
|
||||
echo "This is $File" > $File
|
||||
if [ -s $File ]
|
||||
then
|
||||
echo "$File exists and contains data."
|
||||
elif [ -e $File ]
|
||||
then
|
||||
echo "$File exists and is empty."
|
||||
else
|
||||
echo "$File does not exist."
|
||||
fi
|
||||
```
|
||||
|
||||
*图表 2: 像在脚本里一样重写书写命令行程序*
|
||||
|
||||
对于大多数 CLI 程序来说,让这些复杂的命令变得有逻辑需要写很长的代码。虽然 CLI 可能是用 Linux 或 Bash 内置的命令,但是当 CLI 程序很长或很复杂时,创建一个保存在文件中的脚本将更有效,保存到文件中后,可以随时运行。
|
||||
|
||||
#### 字符串比较操作符
|
||||
|
||||
字符串比较操作符使我们可以对字符串中的字符按字母顺序进行比较。图表 3 列出了仅有的几个字符串比较操作符。
|
||||
|
||||
操作符 | 描述
|
||||
---|---
|
||||
`-z string` | 如果字符串的长度为 0 ,返回真值
|
||||
`-n string` |如果字符串的长度不为 0 ,返回真值
|
||||
`string1 == string2` 或 `string1 = string2` | 如果两个字符串相等,返回真值。处于遵从 POSIX 一致性,在测试命令中应使用一个等号 `=`。与命令 `[[` 一起使用时,会进行如上描述的模式匹配(混合命令)。
|
||||
`string1 != string2` | 两个字符串不相等,返回真值
|
||||
`string1 < string2` | 如果对 `string1` 和 `string2` 按字母顺序进行排序,`string1` 排在 `string2` 前面(即基于地区设定的对所有字母和特殊字符的排列顺序)
|
||||
`string1 > string2` | 如果对 `string1` 和 `string2` 按字母顺序进行排序,`string1` 排在 `string2` 后面
|
||||
|
||||
*图表 3: Bash 字符串逻辑操作符*
|
||||
|
||||
首先,检查字符串长度。比较表达式中 `$MyVar` 两边的双引号不能省略(你仍应该在目录 `~/testdir` 下 )。
|
||||
|
||||
```
|
||||
[student@studentvm1 testdir]$ MyVar="" ; if [ -z "" ] ; then echo "MyVar is zero length." ; else echo "MyVar contains data" ; fi
|
||||
MyVar is zero length.
|
||||
[student@studentvm1 testdir]$ MyVar="Random text" ; if [ -z "" ] ; then echo "MyVar is zero length." ; else echo "MyVar contains data" ; fi
|
||||
MyVar is zero length.
|
||||
```
|
||||
|
||||
你也可以这样做:
|
||||
|
||||
```
|
||||
[student@studentvm1 testdir]$ MyVar="Random text" ; if [ -n "$MyVar" ] ; then echo "MyVar contains data." ; else echo "MyVar is zero length" ; fi
|
||||
MyVar contains data.
|
||||
[student@studentvm1 testdir]$ MyVar="" ; if [ -n "$MyVar" ] ; then echo "MyVar contains data." ; else echo "MyVar is zero length" ; fi
|
||||
MyVar is zero length
|
||||
```
|
||||
|
||||
有时候你需要知道一个字符串确切的长度。这虽然不是比较,但是也与比较相关。不幸的是,计算字符串的长度没有简单的方法。有很多种方法可以计算,但是我认为使用 `expr`(求值表达式)命令是相对最简单的一种。阅读 `expr` 的手册页可以了解更多相关知识。注意表达式中你检测的字符串或变量两边的引号不要省略。
|
||||
|
||||
```
|
||||
[student@studentvm1 testdir]$ MyVar="" ; expr length "$MyVar"
|
||||
0
|
||||
[student@studentvm1 testdir]$ MyVar="How long is this?" ; expr length "$MyVar"
|
||||
17
|
||||
[student@studentvm1 testdir]$ expr length "We can also find the length of a literal string as well as a variable."
|
||||
70
|
||||
```
|
||||
|
||||
关于比较操作符,在我们的脚本中使用了大量的检测两个字符串是否相等(例如,两个字符串是否实际上是同一个字符串)的操作。我使用的是非 POSIX 版本的比较表达式:
|
||||
|
||||
```
|
||||
[student@studentvm1 testdir]$ Var1="Hello World" ; Var2="Hello World" ; if [ "$Var1" == "$Var2" ] ; then echo "Var1 matches Var2" ; else echo "Var1 and Var2 do not match." ; fi
|
||||
Var1 matches Var2
|
||||
[student@studentvm1 testdir]$ Var1="Hello World" ; Var2="Hello world" ; if [ "$Var1" == "$Var2" ] ; then echo "Var1 matches Var2" ; else echo "Var1 and Var2 do not match." ; fi
|
||||
Var1 and Var2 do not match.
|
||||
```
|
||||
|
||||
在你自己的脚本中去试一下这些操作符。
|
||||
|
||||
#### 数字比较操作符
|
||||
|
||||
数字操作符用于两个数字参数之间的比较。像其他类操作符一样,大部分都很容易理解。
|
||||
|
||||
操作符 | 描述
|
||||
---|---
|
||||
`arg1 -eq arg2` | 如果 `arg1` 等于 `arg2`,返回真值
|
||||
`arg1 -ne arg2` | 如果 `arg1` 不等于 `arg2`,返回真值
|
||||
`arg1 -lt arg2` | 如果 `arg1` 小于 `arg2`,返回真值
|
||||
`arg1 -le arg2` | 如果 `arg1` 小于或等于 `arg2`,返回真值
|
||||
`arg1 -gt arg2` | 如果 `arg1` 大于 `arg2`,返回真值
|
||||
`arg1 -ge arg2` | 如果 `arg1` 大于或等于 `arg2`,返回真值
|
||||
|
||||
*图表 4: Bash 数字比较逻辑操作符*
|
||||
|
||||
来看几个简单的例子。第一个示例设置变量 `$X` 的值为 1,然后检测 `$X` 是否等于 1。第二个示例中,`$X` 被设置为 0,所以比较表达式返回结果不为真值。
|
||||
|
||||
```
|
||||
[student@studentvm1 testdir]$ X=1 ; if [ $X -eq 1 ] ; then echo "X equals 1" ; else echo "X does not equal 1" ; fi
|
||||
X equals 1
|
||||
[student@studentvm1 testdir]$ X=0 ; if [ $X -eq 1 ] ; then echo "X equals 1" ; else echo "X does not equal 1" ; fi
|
||||
X does not equal 1
|
||||
[student@studentvm1 testdir]$
|
||||
```
|
||||
|
||||
自己来多尝试一下其他的。
|
||||
|
||||
#### 杂项操作符
|
||||
|
||||
这些杂项操作符展示一个 shell 选项是否被设置,或一个 shell 变量是否有值,但是它不显示变量的值,只显示它是否有值。
|
||||
|
||||
操作符 | 描述
|
||||
---|---
|
||||
`-o optname` | 如果一个 shell 选项 `optname` 是启用的(查看内建在 Bash 手册页中的 set `-o` 选项描述下面的选项列表),则返回真值
|
||||
`-v varname` | 如果 shell 变量 `varname` 被设置了值(被赋予了值),则返回真值
|
||||
`-R varname` | 如果一个 shell 变量 `varname` 被设置了值且是一个名字引用,则返回真值
|
||||
|
||||
*图表 5: 杂项 Bash 逻辑操作符*
|
||||
|
||||
自己来使用这些操作符实践下。
|
||||
|
||||
### 扩展
|
||||
|
||||
Bash 支持非常有用的几种类型的扩展和命令替换。根据 Bash 手册页,Bash 有七种扩展格式。本文只介绍其中五种:`~` 扩展、算术扩展、路径名称扩展、大括号扩展和命令替换。
|
||||
|
||||
#### 大括号扩展
|
||||
|
||||
大括号扩展是生成任意字符串的一种方法。(下面的例子是用特定模式的字符创建大量的文件。)大括号扩展可以用于产生任意字符串的列表,并把它们插入一个用静态字符串包围的特定位置或静态字符串的两端。这可能不太好想象,所以还是来实践一下。
|
||||
|
||||
首先,看一下大括号扩展的作用:
|
||||
|
||||
```
|
||||
[student@studentvm1 testdir]$ echo {string1,string2,string3}
|
||||
string1 string2 string3
|
||||
```
|
||||
|
||||
看起来不是很有用,对吧?但是用其他方式使用它,再来看看:
|
||||
|
||||
```
|
||||
[student@studentvm1 testdir]$ echo "Hello "{David,Jen,Rikki,Jason}.
|
||||
Hello David. Hello Jen. Hello Rikki. Hello Jason.
|
||||
```
|
||||
|
||||
这看起来貌似有点用了 — 我们可以少打很多字。现在试一下这个:
|
||||
|
||||
```
|
||||
[student@studentvm1 testdir]$ echo b{ed,olt,ar}s
|
||||
beds bolts bars
|
||||
```
|
||||
|
||||
我可以继续举例,但是你应该已经理解了它的用处。
|
||||
|
||||
#### ~ 扩展
|
||||
|
||||
资料显示,使用最多的扩展是波浪字符(`~`)扩展。当你在命令中使用它(如 `cd ~/Documents`)时,Bash shell 把这个快捷方式展开成用户的完整的家目录。
|
||||
|
||||
使用这个 Bash 程序观察 `~` 扩展的作用:
|
||||
|
||||
```
|
||||
[student@studentvm1 testdir]$ echo ~
|
||||
/home/student
|
||||
[student@studentvm1 testdir]$ echo ~/Documents
|
||||
/home/student/Documents
|
||||
[student@studentvm1 testdir]$ Var1=~/Documents ; echo $Var1 ; cd $Var1
|
||||
/home/student/Documents
|
||||
[student@studentvm1 Documents]$
|
||||
```
|
||||
|
||||
#### 路径名称扩展
|
||||
|
||||
路径名称扩展是展开文件通配模式为匹配该模式的完整路径名称的另一种说法,匹配字符使用 `?` 和 `*`。文件通配指的是在大量操作中匹配文件名、路径和其他字符串时用特定的模式字符产生极大的灵活性。这些特定的模式字符允许匹配字符串中的一个、多个或特定字符。
|
||||
|
||||
* `?` — 匹配字符串中特定位置的一个任意字符
|
||||
* `*` — 匹配字符串中特定位置的 0 个或多个任意字符
|
||||
|
||||
这个扩展用于匹配路径名称。为了弄清它的用法,请确保 `testdir` 是当前工作目录(`PWD`),先执行基本的列出清单命令 `ls`(我家目录下的内容跟你的不一样)。
|
||||
|
||||
```
|
||||
[student@studentvm1 testdir]$ ls
|
||||
chapter6 cpuHog.dos dmesg1.txt Documents Music softlink1 testdir6 Videos
|
||||
chapter7 cpuHog.Linux dmesg2.txt Downloads Pictures Templates testdir
|
||||
testdir cpuHog.mac dmesg3.txt file005 Public testdir tmp
|
||||
cpuHog Desktop dmesg.txt link3 random.txt testdir1 umask.test
|
||||
[student@studentvm1 testdir]$
|
||||
```
|
||||
|
||||
现在列出以 `Do`、`testdir/Documents` 和 `testdir/Downloads` 开头的目录:
|
||||
|
||||
```
|
||||
Documents:
|
||||
Directory01 file07 file15 test02 test10 test20 testfile13 TextFiles
|
||||
Directory02 file08 file16 test03 test11 testfile01 testfile14
|
||||
file01 file09 file17 test04 test12 testfile04 testfile15
|
||||
file02 file10 file18 test05 test13 testfile05 testfile16
|
||||
file03 file11 file19 test06 test14 testfile09 testfile17
|
||||
file04 file12 file20 test07 test15 testfile10 testfile18
|
||||
file05 file13 Student1.txt test08 test16 testfile11 testfile19
|
||||
file06 file14 test01 test09 test18 testfile12 testfile20
|
||||
|
||||
Downloads:
|
||||
[student@studentvm1 testdir]$
|
||||
```
|
||||
|
||||
然而,并没有得到你期望的结果。它列出了以 `Do` 开头的目录下的内容。使用 `-d` 选项,仅列出目录而不列出它们的内容。
|
||||
|
||||
```
|
||||
[student@studentvm1 testdir]$ ls -d Do*
|
||||
Documents Downloads
|
||||
[student@studentvm1 testdir]$
|
||||
```
|
||||
|
||||
在两个例子中,Bash shell 都把 `Do*` 模式展开成了匹配该模式的目录名称。但是如果有文件也匹配这个模式,会发生什么?
|
||||
|
||||
```
|
||||
[student@studentvm1 testdir]$ touch Downtown ; ls -d Do*
|
||||
Documents Downloads Downtown
|
||||
[student@studentvm1 testdir]$
|
||||
```
|
||||
|
||||
因此所有匹配这个模式的文件也被展开成了完整名字。
|
||||
|
||||
#### 命令替换
|
||||
|
||||
命令替换是让一个命令的标准输出数据流被当做参数传给另一个命令的扩展形式,例如,在一个循环中作为一系列被处理的项目。Bash 手册页显示:“命令替换可以让你用一个命令的输出替换为命令的名字。”这可能不太好理解。
|
||||
|
||||
命令替换有两种格式:\`command\` 和 `$(command)`。在更早的格式中使用反引号(\`),在命令中使用反斜杠(`\`)来保持它转义之前的文本含义。然而,当用在新版本的括号格式中时,反斜杠被当做一个特殊字符处理。也请注意带括号的格式打开个关闭命令语句都是用一个括号。
|
||||
|
||||
我经常在命令行程序和脚本中使用这种能力,一个命令的结果能被用作另一个命令的参数。
|
||||
|
||||
来看一个非常简单的示例,这个示例使用了这个扩展的两种格式(再一次提醒,确保 `testdir` 是当前工作目录):
|
||||
|
||||
```
|
||||
[student@studentvm1 testdir]$ echo "Todays date is `date`"
|
||||
Todays date is Sun Apr 7 14:42:46 EDT 2019
|
||||
[student@studentvm1 testdir]$ echo "Todays date is $(date)"
|
||||
Todays date is Sun Apr 7 14:42:59 EDT 2019
|
||||
[student@studentvm1 testdir]$
|
||||
```
|
||||
|
||||
`-seq` 工具用于一个数字序列:
|
||||
|
||||
```
|
||||
[student@studentvm1 testdir]$ seq 5
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
5
|
||||
[student@studentvm1 testdir]$ echo `seq 5`
|
||||
1 2 3 4 5
|
||||
[student@studentvm1 testdir]$
|
||||
```
|
||||
|
||||
现在你可以做一些更有用处的操作,比如创建大量用于测试的空文件。
|
||||
|
||||
```
|
||||
[student@studentvm1 testdir]$ for I in $(seq -w 5000) ; do touch file-$I ; done
|
||||
```
|
||||
|
||||
`seq` 工具加上 `-w` 选项后,在生成的数字前面会用 0 补全,这样所有的结果都等宽,例如,忽略数字的值,它们的位数一样。这样在对它们按数字顺序进行排列时很容易。
|
||||
|
||||
`seq -w 5000` 语句生成了 1 到 5000 的数字序列。通过把命令替换用于 `for` 语句,`for` 语句就可以使用该数字序列来生成文件名的数字部分。
|
||||
|
||||
#### 算术扩展
|
||||
|
||||
Bash 可以进行整型的数学计算,但是比较繁琐(你一会儿将看到)。数字扩展的语法是 `$((arithmetic-expression))` ,分别用两个括号来打开和关闭表达式。算术扩展在 shell 程序或脚本中类似命令替换;表达式结算后的结果替换了表达式,用于 shell 后续的计算。
|
||||
|
||||
我们再用一个简单的用法来开始:
|
||||
|
||||
```
|
||||
[student@studentvm1 testdir]$ echo $((1+1))
|
||||
2
|
||||
[student@studentvm1 testdir]$ Var1=5 ; Var2=7 ; Var3=$((Var1*Var2)) ; echo "Var 3 = $Var3"
|
||||
Var 3 = 35
|
||||
```
|
||||
|
||||
下面的除法结果是 0,因为表达式的结果是一个小于 1 的整型数字:
|
||||
|
||||
```
|
||||
[student@studentvm1 testdir]$ Var1=5 ; Var2=7 ; Var3=$((Var1/Var2)) ; echo "Var 3 = $Var3"
|
||||
Var 3 = 0
|
||||
```
|
||||
|
||||
这是一个我经常在脚本或 CLI 程序中使用的一个简单的计算,用来查看在 Linux 主机中使用了多少虚拟内存。 `free` 不提供我需要的数据:
|
||||
|
||||
```
|
||||
[student@studentvm1 testdir]$ RAM=`free | grep ^Mem | awk '{print $2}'` ; Swap=`free | grep ^Swap | awk '{print $2}'` ; echo "RAM = $RAM and Swap = $Swap" ; echo "Total Virtual memory is $((RAM+Swap))" ;
|
||||
RAM = 4037080 and Swap = 6291452
|
||||
Total Virtual memory is 10328532
|
||||
```
|
||||
|
||||
我使用 \` 字符来划定用作命令替换的界限。
|
||||
|
||||
我用 Bash 算术扩展的场景主要是用脚本检查系统资源用量后基于返回的结果选择一个程序运行的路径。
|
||||
|
||||
### 总结
|
||||
|
||||
本文是 Bash 编程语言系列的第二篇,探讨了 Bash 中文件、字符串、数字和各种提供流程控制逻辑的逻辑操作符还有不同种类的 shell 扩展。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/19/10/programming-bash-logical-operators-shell-expansions
|
||||
|
||||
作者:[David Both][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[lxbwolf](https://github.com/lxbwolf)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/dboth
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/OSDC_women_computing_5.png?itok=YHpNs_ss (Women in computing and open source v5)
|
||||
[2]: http://www.both.org/?page_id=1183
|
||||
[3]: https://linux.cn/article-11552-1.html
|
@ -1,164 +0,0 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (HankChow)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (3 easy steps to update your apps to Python 3)
|
||||
[#]: via: (https://opensource.com/article/19/12/update-apps-python-3)
|
||||
[#]: author: (Seth Kenlon https://opensource.com/users/seth)
|
||||
|
||||
3 easy steps to update your apps to Python 3
|
||||
======
|
||||
Python 2 has reached its end of life, so it's past time to convert your
|
||||
Python 2 project to Python 3.
|
||||
![Hands on a keyboard with a Python book ][1]
|
||||
|
||||
The 2.x series of Python is [officially over][2], but converting code to Python 3 is easier than you think. Over the weekend, I spent an evening converting the frontend code of a 3D renderer (and its corresponding [PySide][3] version) to Python 3, and it was surprisingly simple in retrospect, although it seemed relatively hopeless during the refactoring process. The conversion process can seem a little like a labyrinth, with every change you make revealing a dozen more changes you need to make.
|
||||
|
||||
You may or may not _want_ to do the conversion, but—whether it's because you procrastinated too long or you rely on a module that won't be maintained unless you convert—sometimes you just don't have a choice. And if you're looking for an easy task to start your contribution to open source, converting a Python 2 app to Python 3 is a great way to make an easy but meaningful impression.
|
||||
|
||||
Whatever your reason for refactoring Python 2 code into Python 3, it's an important job. Here are three steps to approach the task with clarity.
|
||||
|
||||
### 1\. Run 2to3
|
||||
|
||||
For the past several years, Python has shipped with a script called [**2to3**][4], which does the bulk of the conversion from Python 2 to Python 3 for you. Automatically. And you already have it installed (whether you realize it or not).
|
||||
|
||||
Here's a short snippet of code written in Python 2.6:
|
||||
|
||||
|
||||
```
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
mystring = u'abcdé'
|
||||
print ord(mystring[-1])
|
||||
```
|
||||
|
||||
Run the **2to3** script:
|
||||
|
||||
|
||||
```
|
||||
$ 2to3 example.py
|
||||
RefactoringTool: Refactored example.py
|
||||
\--- example.py (original)
|
||||
+++ example.py (refactored)
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
-mystring = u'abcdé'
|
||||
-print ord(mystring[-1])
|
||||
+mystring = 'abcdé'
|
||||
+print(ord(mystring[-1]))
|
||||
RefactoringTool: Files that need to be modified:
|
||||
RefactoringTool: example.py
|
||||
```
|
||||
|
||||
By default, **2to3** prints only the changes required to bring old Python code up to Python 3 standards. The output is a usable patch you can use to change your file, but it's easier to just let Python do that for you, using the **\--write** (or **-w**) option:
|
||||
|
||||
|
||||
```
|
||||
$ 2to3 -w example.py
|
||||
[...]
|
||||
RefactoringTool: Files that were modified:
|
||||
RefactoringTool: example.py
|
||||
```
|
||||
|
||||
The **2to3** script doesn't work on just a single file. You can run it on an entire directory of Python files, with or without the **\--write** option, to process all ***.py** files in the directory and its subdirectories.
|
||||
|
||||
### 2\. Use Pylint or Pyflakes
|
||||
|
||||
It's not uncommon to discover code quirks that ran without issue in Python 2 but don't work so well in Python 3. Because these quirks can't be fixed by converting syntax, they get past **2to3** unchanged, but they fail once you try to run the code.
|
||||
|
||||
To detect such issues, you can use an application like [Pylint][5] or a tool like [Pyflakes][6] (or the [flake8][7] wrapper). I prefer Pyflakes because, unlike Pylint, it ignores deviations in the _style_ of your code. While the "prettiness" of Python is often praised as one of its strong points, when porting someone else's code from 2 to 3, treating style and function as two separate bugs is a matter of prioritization.
|
||||
|
||||
Here's example output from Pyflakes:
|
||||
|
||||
|
||||
```
|
||||
$ pyflakes example/maths
|
||||
example/maths/enum.py:19: undefined name 'cmp'
|
||||
example/maths/enum.py:105: local variable 'e' is assigned to but never used
|
||||
example/maths/enum.py:109: undefined name 'basestring'
|
||||
example/maths/enum.py:208: undefined name 'EnumValueCompareError'
|
||||
example/maths/enum.py:208: local variable 'e' is assigned to but never used
|
||||
```
|
||||
|
||||
This output (compared to 143 lines from Pylint, most of which were complaints about indentation) clearly displays the problems in the code that you should repair.
|
||||
|
||||
The most interesting error here is the first one, on line 19. It's a little misleading because you might think that **cmp** is a variable that was never defined, but **cmp** is really a function from Python 2 that doesn't exist in Python 3. It's wrapped in a **try** statement, so the issue could easily go unnoticed until it becomes obvious that the **try** result is not getting produced.
|
||||
|
||||
|
||||
```
|
||||
try:
|
||||
result = cmp(self.index, other.index)
|
||||
except:
|
||||
result = 42
|
||||
|
||||
return result
|
||||
```
|
||||
|
||||
There are countless examples of functions that no longer exist or that have changed between when an application was maintained as a Python 2 codebase and when you decide to port it. PySide(2) bindings have changed, Python functions have disappeared or been transformed (**imp** to **importlib**, for example), and so on. Fix them one by one as you encounter them. Even though it's up to you to reimplement or replace those missing functions, by now, most of these issues are known and [well-documented][8]. The real challenge is more about catching the errors than fixing them, so use Pyflakes or a similar tool.
|
||||
|
||||
### 3\. Repair broken Python 2 code
|
||||
|
||||
The **2to3** script gets your code Python 3 compliant, but it only knows about differences between Python 2 and 3. It generally can't make adjustments to account for changes in libraries that worked one way back in 2010 but have had major revisions since then. You must update that code manually.
|
||||
|
||||
For instance, this code apparently worked back in the days of Python 2.6:
|
||||
|
||||
|
||||
```
|
||||
class CLOCK_SPEED:
|
||||
TICKS_PER_SECOND = 16
|
||||
TICK_RATES = [int(i * TICKS_PER_SECOND)
|
||||
for i in (0.5, 1, 2, 3, 4, 6, 8, 11, 20)]
|
||||
|
||||
class FPS:
|
||||
STATS_UPDATE_FREQUENCY = CLOCK_SPEED.TICKS_PER_SECOND
|
||||
```
|
||||
|
||||
Automated tools like **2to3** and **Pyflakes** don't detect the problem, but Python 3 doesn't see **GAME_SPEED.TICKS_PER_SECOND** as a valid statement because the function being called was never explicitly declared. Adjusting the code is a simple exercise in object-oriented programming:
|
||||
|
||||
|
||||
```
|
||||
class CLOCK_SPEED:
|
||||
def TICKS_PER_SECOND():
|
||||
TICKS_PER_SECOND = 16
|
||||
TICK_RATES = [int(i * TICKS_PER_SECOND)
|
||||
for i in (0.5, 1, 2, 3, 4, 6, 8, 11, 20)]
|
||||
return TICKS_PER_SECOND
|
||||
|
||||
class FPS:
|
||||
STATS_UPDATE_FREQUENCY = CLOCK_SPEED.TICKS_PER_SECOND()
|
||||
```
|
||||
|
||||
You may be inclined to make it cleaner still by replacing the **TICKS_PER_SECOND** function with a constructor (an **__init__** function to set default values), but that would change the required call from **CLOCK_SPEED.TICKS_PER_SECOND()** to just **CLOCK_SPEED()**, which may or may not have ramifications elsewhere in the codebase. If you know the code well, then you can use your better judgment about how
|
||||
|
||||
much alteration is _required_ and how much would just be pleasant, but generally, I prefer to assume every change I make inevitably demands at least three changes to every other file in the project, so I try to work within its existing structure.
|
||||
|
||||
### Don't stop believing
|
||||
|
||||
If you're porting a very large project, it sometimes starts to feel like there's no end in sight. It can seem like forever before you see a useful error message that's _not_ about a Python 2 quirk that slipped past the scripts and linters, and once you get to that point, you'll start to suspect it would be easier to just start from scratch. The bright side is that you (presumably) know that the codebase you're porting works (or worked) in Python 2, and once you make your adjustments, it will work again in Python 3; it's just a matter of conversion.
|
||||
|
||||
Once you've done the legwork, you'll have a Python 3 module or application, and regular maintenance (and those style changes to make Pylint happy) can begin anew!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/19/12/update-apps-python-3
|
||||
|
||||
作者:[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/python-programming-code-keyboard.png?itok=fxiSpmnd (Hands on a keyboard with a Python book )
|
||||
[2]: https://opensource.com/article/19/11/end-of-life-python-2
|
||||
[3]: https://pypi.org/project/PySide/
|
||||
[4]: https://docs.python.org/3.1/library/2to3.html
|
||||
[5]: https://opensource.com/article/19/10/python-pylint-introduction
|
||||
[6]: https://pypi.org/project/pyflakes/
|
||||
[7]: https://opensource.com/article/19/5/python-flake8
|
||||
[8]: https://docs.python.org/3.0/whatsnew/3.0.html
|
@ -1,196 +0,0 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (laingke)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (What's in an open source name?)
|
||||
[#]: via: (https://opensource.com/article/19/10/open-source-name-origins)
|
||||
[#]: author: (Joshua Allen Holm https://opensource.com/users/holmja)
|
||||
|
||||
开源名称中有什么?
|
||||
======
|
||||
有没有想过您喜欢的开源项目或编程语言的名称来自何处?了解从 A 到 Z 的流行技术术语背后的起源故事。
|
||||
![A person writing.][1]
|
||||
|
||||
GNOME、Java、Jupyter、Python。如果你的朋友或家人曾留意过你的工作对话,他们可能会认为您从事文艺复兴时期的民间文学艺术、咖啡烘焙、天文学或动物学工作。这些开源技术的名称从何而来?我们要求作者社区提供意见,并汇总了一些我们最喜欢的技术名称起源故事。
|
||||
|
||||
### Ansible
|
||||
|
||||
“Ansible”这个名称直接来自科幻小说。厄休拉·勒古恩(Ursula Le Guin)的《鲁康农的世界》(_Rocannon's World_)一书中能进行即时(比光速更快)通信的设备允许被称为 ansibles(显然来自“ answerable”一词)。Ansibles 成为科幻小说的主要内容,包括在奥森·斯科特·卡德(Orson Scott Card)的《安德的游戏》(_Ender's Game_)(后来成为受欢迎的电影)中,该设备控制了许多远程太空飞船。对于控制分布式机器的软件来说,这似乎是一个很好的模型,因此 Michael DeHaan(Ansible 的创建者和创始人)借用了这个名称。
|
||||
|
||||
### Apache
|
||||
|
||||
[Apache][2] 是最初于 1995 年发布的开源 Web 服务器。它的名称与著名的美国原住民部落无关;相反,它是指对原始软件代码重复的补丁。因此称之为,“<ruby>一个修补<rt>A-patchy</rt></ruby>服务器”。
|
||||
|
||||
### awk
|
||||
|
||||
“awk(1) 代表着 Aho, Weinberger, Kernighan(作者)”—— Michael Greenberg
|
||||
|
||||
### Bash
|
||||
|
||||
“最初的 Unix shell,即 Bourne shell,是以其创建者的名字命名的。在开发 Bash 时,csh(发音为‘seashell’)实际上更受交互登录用户的欢迎。Bash 项目旨在赋予 Bourne shell 新的生命,使其更适合于交互式使用,因此它被命名为‘Bourne again shell’,是‘重生’的双关语。’”——Ken Gaillot
|
||||
|
||||
### C
|
||||
|
||||
在早期,AT&T 的 Ken Thompson 和 Dennis Ritchie 发现可以使用更高级的编程语言(而不是低级的、可移植性更低的汇编编程)来编写操作系统和工具是很有趣的。早期有一个叫做 BCPL(Basic Combined programming Language,基本组合编程语言)的编程系统,汤普森创建了一个名为 B 的简化版 BCPL,但 B 的灵活性和速度都不高。然后,里奇把 B 的思想扩展成一种叫做 C 的编译语言。”——Jim Hall
|
||||
|
||||
### dd
|
||||
|
||||
“我想你发表这样一篇文章不能不提到 dd。我的外号叫 Didi。正确发音,它听起来像‘dd’。我第一次学的是 Unix,然后是 Linux,那是在 1993 年,当时我还是个学生。然后我去了军队,来到了我的部队中少数几个使用 Unix(Ultrix)的部门之一(其它部门主要是 VMS),那里的一个人说:‘这么说,你是一个黑客,对吗?你以为你了解 Unix 吗?好的,那么 dd 这个名字的原因是什么呢?’我不知道,试着猜:‘数据复印机?’所以他说,‘我要告诉你 dd 的故事。dd 是 _convert 和 copy_ 的缩写(任何人仍然可以在今天从参考页中看到),但由于 cc 这个缩写已经被 C 的编译器占用,它被命名为 dd。’只有几年后,我听闻了关于 JCL 的数据定义和非统一、半开玩笑的 Unix dd 命令语法的纪实中的一部分都是基于这个说法的。”——Yedidyah Bar David
|
||||
|
||||
### Emacs
|
||||
|
||||
经典的<ruby>反 vi<rt>anti-vi</rt></ruby> 编辑器,其名称的真正词源并不明显,因为它源自“Editing MACroS”。但是,它作为一个伟大的宗教亵渎和崇拜的对象,吸引了许多恶作剧般的缩写,例如“<ruby>避开 Meta Alt Control Shift 键<rt>Escape Meta Alt Control Shift</rt></ruby>”(以调侃其对键盘的大量依赖),“<ruby>8MB 并经常交换<rt>Eight Megabytes And Constantly Swapping</rt></ruby>”(从那时起就有很多内存了),“<ruby>最终分配了所有的计算机存储<rt>Eventually malloc()s All Computer Storage</rt></ruby>”和 “<ruby>EMACS 使一台计算机慢<rt>EMACS Makes A Computer Slow</rt></ruby>”——改编术语文件/黑客的字典
|
||||
|
||||
### Enarx
|
||||
|
||||
[Enarx][3] 是机密计算领域的一个新项目。该项目的设计原则之一是它应该是“可替代的”。因此最初的名字是“psilocybin”(著名的魔术蘑菇)。一般情况下,经理级别的人可能会对这个名称有所抵触,因此考虑使用新名称。该项目的两位创始人 Mike Bursell 和 Nathaniel McCallum 都是老一辈的极客,因此他们考虑了许多不同的想法,包括 тайна(Tayna——俄语中代表秘密或神秘——虽然公认的俄语并不是一门古老的语言,但你就不要在乎这些细节了),crypticon(希腊语的意思是完全庶生的),cryptidion(希腊中表示小密室),arconus(拉丁语中表示秘密的褒义形容词),arcanum(拉丁语中表示秘密的中性形容词)和 ærn(盎格鲁撒克逊人表示地方,秘密的地方,壁橱,住所,房子,或小屋的词汇)。最后,由于各种原因,包括域名和 GitHub 项目名称的可用性,他们选择了 enarx,这是两个拉丁词根的组合:en-(表示内部)和 -arx(表示城堡,要塞或堡垒)。
|
||||
|
||||
### GIMP
|
||||
|
||||
没有 [GIMP][4] 我们会怎么样?GNU 图像处理项目多年来一直是开源的主要内容。[维基百科][5]指出,“1995 年,[Spencer Kimball][6] 和 [Peter Mattis][7] 开始开发 GIMP,作为加州大学伯克利分校的一个为期一个学期的实验计算设施项目。”
|
||||
|
||||
### GNOME
|
||||
|
||||
你有没有想过为什么 GNOME 被称为 GNOME?根据[维基百科][8],GNOME 最初是一个表示“GNU 网络对象模型环境”的缩写词。现在,该名称不再表示项目,并已被删除,但该名称仍然保留。[GNOME 3][9] 是 Fedora、红帽企业版、Ubuntu、Debian、SUSE Linux 企业版等发行版的默认桌面环境。
|
||||
|
||||
### Java
|
||||
|
||||
您能想象这种编程语言还有其它名称吗?Java 最初被称为 Oak,但是遗憾的是,Sun Microsystems 的法律团队因其现有商标而否决了该名称。所以开发团队又重新给它命名。[据说][10]该语言的工作组在 1995 年 1 月举行了一次大规模的头脑风暴。许多其它名称也被扔掉了,包括 Silk、DNA、WebDancer 等。该团队不希望新名称与过度使用的术语“web”或“net.”有任何关系。取而代之的是,他们在寻找更有活力、更有趣、更容易记住的东西。Java 满足了这些要求,并且奇迹般地,团队同意通过了!
|
||||
|
||||
### Jupyter
|
||||
|
||||
现在许多数据科学家和学生在工作中使用 [Jupyter][11] 笔记本。“Jupyter”这个名字是三种开源计算机语言的融合,这三种语言在笔记本中都有使用,在数据科学中也很突出:[Julia][12]、[Python][13] 和 [R][14]。
|
||||
|
||||
### Kubernetes
|
||||
|
||||
Kubernetes 源自希腊语中的舵手。Kubernetes 项目创始人 Craig McLuckie 在 [2015 Hacker News][15] 回应中证实了这种词源。为了坚持航海主题,他解释说,这项技术驱动集装箱,就像舵手或飞行员驱动集装箱船一样。因此,选择了 Kubernetes 这个名字。我们中的许多人仍然在尝试正确的发音(koo-bur-NET-eez),因此 K8s 是可以接受的替代发音。有趣的是,它与英语单词“ governor”具有相同的词源,也与蒸汽机上的机械负反馈装置相同。
|
||||
|
||||
### KDE
|
||||
|
||||
那 K desktop 呢? KDE 最初代表“ Kool 桌面环境”。 它由 [Matthias Ettrich][16] 于 1996 年创立。根据[维基百科][17]上的说法,该名称是 Unix 上 [Common Desktop Environment][18](CDE)一词的调侃。
|
||||
|
||||
### Linux
|
||||
|
||||
[Linux][19] 因其发明者 Linus Torvalds 的名字命名的。Linus 最初想将他的作品命名为“Freax”,因为他认为以他自己的名字命名太自负了。根据[维基百科][19]的说法,“赫尔辛基科技大学 Torvalds 的同事 Ari Lemmke 当时是 FTP 服务器的志愿管理员之一,他并不认为‘Freax’是个好名字。 因此,他在没有咨询 Torvalds 的情况下,将服务器上的这个项目命名为‘Linux’。”
|
||||
|
||||
以下是一些最受欢迎的Linux发行版。
|
||||
|
||||
#### CentOS
|
||||
|
||||
[CentOS][20] 是<ruby>社区企业操作系统<rt>Community Enterprise Operating System</rt></ruby>的缩写。它包含 Red Hat Enterprise Linux 的上游软件包。
|
||||
|
||||
#### Debian
|
||||
|
||||
[Debian][21] Linux 创建于 1993 年 9 月,是其创始人 Ian Murdock 和他当时的女友 Debra Lynn 的混成词。
|
||||
|
||||
#### RHEL
|
||||
|
||||
[Red Hat Linux][22] 的名字来自它的创始人马克·尤因(Marc Ewing),他戴着一顶祖父送给他的康奈尔大学红色软呢帽。红帽公司成立于 1993 年 3 月 26 日。[Fedora Linux][23] 作为一个志愿者项目而启动,旨在为红帽发行版提供额外的软件,它的名字来自红帽的“Shadowman”标识。
|
||||
|
||||
#### Ubuntu
|
||||
|
||||
[Ubuntu][24] 旨在广泛分享开源软件,它以非洲哲学“人的本质”命名,可以翻译为“对他人的人道主义”或“我之所以是我,是因为我们都是这样的人”。
|
||||
|
||||
### Moodle
|
||||
|
||||
开源学习平台 [Moodle][25] 是“<ruby>模块化面向对象动态学习环境<rt>modular object-oriented dynamic learning environment</rt></ruby>”的首字母缩写。Moodle 仍然是电子学习的领先平台。全球有近 10.4 万个注册的 Moodle 网站。
|
||||
|
||||
另外两个流行的开源内容管理系统是 Drupal 和 Joomla。Drupal 的名字来自荷兰语,意思是“放弃”。根据维基百科,Joomla 是斯瓦希里语单词“jumla”的[英式拼写][26],在阿拉伯语、乌尔都语和其他语言中是“一起”的意思。
|
||||
|
||||
### Mozilla
|
||||
|
||||
[Mozilla][27] 是一个成立于 1998 年的开源软件社区。根据其网站,“Mozilla 项目创建于 1998 年,发布了 Netscape 浏览器套件源代码。它旨在利用互联网上成千上万的程序员的创造力,并推动浏览器市场上前所未有的创新水平。” 这个名字是 [Mosaic] [28] 和 Godzilla 的混成词。
|
||||
|
||||
### Nginx
|
||||
|
||||
“许多技术人员都试图装酷,并将它念成‘n’‘g’‘n’‘x’。实际上,很少的一部分人只做了一些基本的研究工作,就可以很快发现名称实际上应该被说成是“ EngineX”,指的是功能强大的 web 服务器,例如引擎。”——Jean Sebastien Tougne
|
||||
|
||||
### Perl
|
||||
|
||||
Perl 的创始人 Larry Wall 最初将他的项目命名为“Pearl”。根据维基百科,Wall 想给这种语言起一个有积极含义的简短名字。在 Perl 正式发布之前,Wall 发现了现有的 [PEARL][29] 编程语言,并更改了名称的拼写。
|
||||
|
||||
### Piet and Mondrian
|
||||
|
||||
“有两种编程语言以艺术家 Piet Mondrian 命名。一种叫做‘Piet’,另一种叫做‘Mondrian’。[David Morgan-Mar [写道][30]]:“Piet 是一种编程语言,其中的程序看起来像抽象绘画。该语言以几何抽象艺术的开创者 Piet Mondrian 的名字命名。我曾想将这种语言命名为 Mondrian,但是有人告诉我这会让它看起来像一种很普通的脚本语言。哦,好吧,我想我们不能都是深奥的语言作家。”——Yuval Lifshitz
|
||||
|
||||
### Python
|
||||
|
||||
Python编程语言的独特名称来自其创建者 Guido Van Rossum,他是喜剧团体 Monty Python 的粉丝。
|
||||
|
||||
### Raspberry Pi
|
||||
|
||||
Raspberry Pi 以其微小但强大的功能和对钱包友好的价格标签而闻名,在开源社区中是最受欢迎的。但是它可爱(和好吃)的名字是从哪里来的呢?在 70 年代和 80 年代,以水果命名的计算机是一种流行的趋势。苹果,橘子,杏……有人饿了吗?根据创始人 Eben Upton 的 [2012 采访] [31],“Raspberry Pi”这个名称是对这种趋势的致敬。树莓也很小,但味道却很浓。名称中的“Pi”暗示着这样的事实:最初,计算机只能运行 Python。
|
||||
|
||||
### Samba
|
||||
|
||||
[Server Message Block][32] 用于在 Linux 上共享 Windows 文件。
|
||||
|
||||
### ScummVM
|
||||
|
||||
[ScummVM][33](《疯狂大楼》虚拟机的脚本创建实用程序)是一个程序,可以在现代计算机上运行一些经典的计算机冒险游戏。最初,它旨在玩用 SCUMM 构建的 LucasArts 冒险游戏,该游戏最初用于开发《疯狂大楼》,后来又被用来开发 LucasArts 的其它大多数冒险游戏。目前,ScummVM 支持大量游戏引擎,包括 Sierra Online 的 AGI 和 SCI,但仍保留名称 ScummVM。一个相关的项目 [ResidualVM][34] 之所以得名,是因为它涵盖了 ScummVM 未涵盖的“剩余” LucasArts 冒险游戏。 ResidualVM 涵盖的 LucasArts 游戏是使用 GrimE(Grim Engine)开发的,该引擎最初用于开发 Grim Fandango,因此 ResidualVM 的名称是双关语。
|
||||
|
||||
### SQL
|
||||
|
||||
“你可能知道 [SQL] 代表结构化查询语言,但你知道为什么它经常被读作‘sequel’吗?”它是作为‘QUEL’(查询语言)的后续(即续集)而创建的。”——Ken Gaillot
|
||||
|
||||
### XFCE
|
||||
|
||||
[XFCE][35] 是由 [Olivier Fourdan][36] 创建的一个流行的桌面。它在 1996 年作为 CDE 的替代品出现,最初是 <ruby>XForms 公共环境<rt>XForms Common Environment</rt></ruby>的缩写。
|
||||
|
||||
### Zsh
|
||||
|
||||
Zsh 是一个交互式登录 shell。1990 年,普林斯顿大学的学生 Paul Falstad 写了 shell 的第一个版本。他在看到当时在普林斯顿大学担任助教的 Zhong Sha(zsh)的登录 ID 后,给它起了个名字,他觉得这个名字听起来像 [shell 的好名字][37]。
|
||||
|
||||
还有更多的项目和名称还没有包括在这个列表中。请一定要在评论中分享你的收藏。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/19/10/open-source-name-origins
|
||||
|
||||
作者:[Joshua Allen Holm][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[laingke](https://github.com/laingke)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/holmja
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/rh_003784_02_os.comcareers_resume_rh1x.png?itok=S3HGxi6E (A person writing.)
|
||||
[2]: https://httpd.apache.org/
|
||||
[3]: https://enarx.io
|
||||
[4]: https://www.gimp.org/
|
||||
[5]: https://en.wikipedia.org/wiki/GIMP
|
||||
[6]: https://en.wikipedia.org/wiki/Spencer_Kimball_(computer_programmer)
|
||||
[7]: https://en.wikipedia.org/wiki/Peter_Mattis
|
||||
[8]: https://en.wikipedia.org/wiki/GNOME
|
||||
[9]: https://www.gnome.org/gnome-3/
|
||||
[10]: https://www.javaworld.com/article/2077265/so-why-did-they-decide-to-call-it-java-.html
|
||||
[11]: https://jupyter.org/
|
||||
[12]: https://julialang.org/
|
||||
[13]: https://www.python.org/
|
||||
[14]: https://www.r-project.org/
|
||||
[15]: https://news.ycombinator.com/item?id=9653797
|
||||
[16]: https://en.wikipedia.org/wiki/Matthias_Ettrich
|
||||
[17]: https://en.wikipedia.org/wiki/KDE
|
||||
[18]: https://sourceforge.net/projects/cdesktopenv/
|
||||
[19]: https://en.wikipedia.org/wiki/Linux
|
||||
[20]: https://www.centos.org/
|
||||
[21]: https://www.debian.org/
|
||||
[22]: https://www.redhat.com/en/technologies/linux-platforms/enterprise-linux
|
||||
[23]: https://getfedora.org/
|
||||
[24]: https://ubuntu.com/about
|
||||
[25]: https://moodle.org/
|
||||
[26]: https://en.wikipedia.org/wiki/Joomla#Historical_background
|
||||
[27]: https://www.mozilla.org/en-US/
|
||||
[28]: https://en.wikipedia.org/wiki/Mosaic_(web_browser)
|
||||
[29]: https://en.wikipedia.org/wiki/PEARL_(programming_language)
|
||||
[30]: http://www.dangermouse.net/esoteric/piet.html
|
||||
[31]: https://www.techspot.com/article/531-eben-upton-interview/
|
||||
[32]: https://www.samba.org/
|
||||
[33]: https://www.scummvm.org/
|
||||
[34]: https://www.residualvm.org/
|
||||
[35]: https://www.xfce.org/
|
||||
[36]: https://en.wikipedia.org/wiki/Olivier_Fourdan
|
||||
[37]: http://www.zsh.org/mla/users/2005/msg00951.html
|
@ -1,495 +0,0 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (lxbwolf)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (How to program with Bash: Logical operators and shell expansions)
|
||||
[#]: via: (https://opensource.com/article/19/10/programming-bash-logical-operators-shell-expansions)
|
||||
[#]: author: (David Both https://opensource.com/users/dboth)
|
||||
|
||||
Bash 编程教程:逻辑操作符和 shell 扩展
|
||||
======
|
||||
|
||||
学习逻辑操作符和 shell 扩展,本文是Bash 编程系列(三篇文章)的第二篇。
|
||||
![Women in computing and open source v5][1]
|
||||
|
||||
Bash 是一种强大的编程语言,完美契合命令行和 shell 脚本。本系列(三篇文章,基于我的 [Linux 自学课程三卷][2])讲解如何在 CLI 使用 Bash 编程。
|
||||
|
||||
[第一篇文章][3] 讲解了 Bash 的一些简单命令行操作,包括如何使用变量和控制操作符。第二篇文章探讨文件、字符串、数字等类型和各种各样在执行流中提供控制逻辑的的逻辑运算符,还有 Bash 中的各类 shell 扩展。本系列第三篇也是最后一篇文章,将会探索能重复执行操作的 **for** 、**while** 和 **until** 循环。
|
||||
|
||||
逻辑操作符是程序中判断的根本要素,也是执行不同的语句组合的依据。有时这也被称为流控制。
|
||||
|
||||
### 逻辑操作符
|
||||
|
||||
Bash 中有大量的用于不同条件表达式的逻辑操作符。最基本的是 **if** 控制结构,它判断一个条件,如果条件为真,就执行一些程序语句。操作符共有三类:文件,数字和非数字操作符。如果条件为真,所有的操作符返回 true(0),如果条件为假,返回 false(1)。
|
||||
|
||||
这些比较操作符的函数语法是,一个操作符加一个或两个参数放在中括号内,后面跟一系列程序语句,如果条件为真,程序语句执行,可能会有另一个程序语句 list,该 list 在条件为假时执行:
|
||||
|
||||
|
||||
```
|
||||
if [ arg1 operator arg2 ] ; then list
|
||||
or
|
||||
if [ arg1 operator arg2 ] ; then list ; else list ; fi
|
||||
```
|
||||
|
||||
像例子中那样,在比较表达式中,空格不能省略。中括号的每部分,**[** 和 **]**,是跟 **test** 命令一样的传统的 Bash 符号:
|
||||
|
||||
|
||||
```
|
||||
`if test arg1 operator arg2 ; then list`
|
||||
```
|
||||
|
||||
还有一个更新的语法能提供一点点便利,一些系统管理员比较喜欢用。这种格式对于不同版本的 Bash 和一些 shell 如 ksh(the Korn shell)兼容性稍差。格式如下:
|
||||
|
||||
|
||||
```
|
||||
`if [[ arg1 operator arg2 ]] ; then list`
|
||||
```
|
||||
|
||||
#### 文件操作符
|
||||
|
||||
文件操作符是 Bash 中一系列强大的逻辑操作符。图表 1 列出了 20 多种不同的 Bash 处理文件的操作符。在我的脚本中使用频率很高。
|
||||
|
||||
Operator | Description
|
||||
---|---
|
||||
-a filename | 如果文件存在,返回 true;文件可以为空也可以有内容,但是只要它存在,就返回 true
|
||||
-b filename | 如果文件存在且是一个块设备如**/dev/sda** or **/dev/sda1**,则返回 true
|
||||
-c filename | 如果文件存在且是一个字符设备如**/dev/TTY1**,则返回 true
|
||||
-d filename | 如果文件存在且是一个目录,返回 true
|
||||
-e filename | 如果文件存在,返回 true;与上面的 **-a** 相同
|
||||
-f filename | 如果文件存在且是一个一般文件,不是目录、设备文件或链接等的其他的文件,则返回 true
|
||||
-g filename | 如果文件存在且 **SETGID** 标记被设置在其上,返回 true
|
||||
-h filename | 如果文件存在且是一个符号链接,则返回 true
|
||||
-k filename | 如果文件存在且粘贴位已设置,则返回 true
|
||||
-p filename | 如果文件存在且是一个命名的管道(FIFO),返回 true
|
||||
-r filename | 如果文件存在且有可读权限,如它的可读位被设置,返回 true
|
||||
-s filename | 如果文件存在且大小大于 0,返回 true;如果一个文件存在但大小为 0,则返回 false
|
||||
-t fd | 如果文件描述符 **fd** 被打开且被关联到一个终端设备上,返回 true
|
||||
-u filename | 如果文件存在且它的 **set-user-id** 位被设置,返回 true
|
||||
-w filename | 如果文件存在且有可写权限,返回 true
|
||||
-x filename | 如果文件存在且有可执行权限,返回 true
|
||||
-G filename | 如果文件存在且文件的 group ID 与当前用户相同,返回 true
|
||||
-L filename | 如果文件存在且是一个符号链接,返回 true
|
||||
-N filename | 如果文件存在且从文件上一次被读取到现在为止, 文件被修改过,返回 true
|
||||
-O filename | 如果文件存在且你是文件的拥有者,返回 true
|
||||
-S filename | True if the file exists and is a socket
|
||||
file1 -ef file2 | 如果文件`file1`和 文件`file2`是相同文件的硬链接,返回 true
|
||||
file1 -nt file2 | 如果文件 file1 比 file2 新(根据修改日期),或 file1 存在而 file2 不存在
|
||||
file1 -ot file2 | 如果文件 file1 比 file2 旧(根据修改日期),或 file1 不存在而 file2 存在
|
||||
|
||||
_**Fig.1:Bash 文件操作符**_
|
||||
|
||||
以测试一个文件存在与否来举例:
|
||||
|
||||
|
||||
```
|
||||
[student@studentvm1 testdir]$ File="TestFile1" ; if [ -e $File ] ; then echo "The file $File exists." ; else echo "The file $File does not exist." ; fi
|
||||
The file TestFile1 does not exist.
|
||||
[student@studentvm1 testdir]$
|
||||
```
|
||||
|
||||
创建一个用来测试的文件,命名为 **TestFile1**。目前它不需要包含任何数据:
|
||||
|
||||
|
||||
```
|
||||
`[student@studentvm1 testdir]$ touch TestFile1`
|
||||
```
|
||||
|
||||
在这个简短的 CLI 程序中,修改 **$File** 变量的值相比于在多个地方修改表示文件名的字符串的值要容易:
|
||||
|
||||
|
||||
```
|
||||
[student@studentvm1 testdir]$ File="TestFile1" ; if [ -e $File ] ; then echo "The file $File exists." ; else echo "The file $File does not exist." ; fi
|
||||
The file TestFile1 exists.
|
||||
[student@studentvm1 testdir]$
|
||||
```
|
||||
|
||||
现在,运行一个测试来判断一个文件是否存在且长度不为 0(表示它包含数据)。假设你想判断三种情况:
|
||||
|
||||
1. 文件不存在;
|
||||
|
||||
2. 文件存在且为空;
|
||||
|
||||
3. 文件存在且包含数据。
|
||||
|
||||
因此,你需要一组更负责的测试代码 — 为了测试所有的情况在 **if-elif-else** 结构中使用 **elif** 语句:
|
||||
|
||||
|
||||
```
|
||||
[student@studentvm1 testdir]$ File="TestFile1" ; if [ -s $File ] ; then echo "$File exists and contains data." ; fi
|
||||
[student@studentvm1 testdir]$
|
||||
```
|
||||
|
||||
在本案例中,文件存在但不包含任何数据。向文件添加一些数据再运行一次:
|
||||
|
||||
|
||||
```
|
||||
[student@studentvm1 testdir]$ File="TestFile1" ; echo "This is file $File" > $File ; if [ -s $File ] ; then echo "$File exists and contains data." ; fi
|
||||
TestFile1 exists and contains data.
|
||||
[student@studentvm1 testdir]$
|
||||
```
|
||||
|
||||
这组语句能返回正常的结果,但是仅仅是在我们已知三种可能的情况下测试某种确切的条件。添加一段 **else** 语句,这样你就可以更精确地测试。把文件删掉,你就可以完整地测试这段新代码:
|
||||
|
||||
|
||||
```
|
||||
[student@studentvm1 testdir]$ File="TestFile1" ; rm $File ; if [ -s $File ] ; then echo "$File exists and contains data." ; else echo "$File does not exist or is empty." ; fi
|
||||
TestFile1 does not exist or is empty.
|
||||
```
|
||||
|
||||
现在创建一个空文件用来测试:
|
||||
|
||||
|
||||
```
|
||||
[student@studentvm1 testdir]$ File="TestFile1" ; touch $File ; if [ -s $File ] ; then echo "$File exists and contains data." ; else echo "$File does not exist or is empty." ; fi
|
||||
TestFile1 does not exist or is empty.
|
||||
```
|
||||
|
||||
向文件添加一些内容,然后再测试一次:
|
||||
|
||||
|
||||
```
|
||||
[student@studentvm1 testdir]$ File="TestFile1" ; echo "This is file $File" > $File ; if [ -s $File ] ; then echo "$File exists and contains data." ; else echo "$File does not exist or is empty." ; fi
|
||||
TestFile1 exists and contains data.
|
||||
```
|
||||
|
||||
现在加入 **elif** 语句来辨别是文件不存在还是文件为空:
|
||||
|
||||
|
||||
```
|
||||
[student@studentvm1 testdir]$ File="TestFile1" ; touch $File ; if [ -s $File ] ; then echo "$File exists and contains data." ; elif [ -e $File ] ; then echo "$File exists and is empty." ; else echo "$File does not exist." ; fi
|
||||
TestFile1 exists and is empty.
|
||||
[student@studentvm1 testdir]$ File="TestFile1" ; echo "This is $File" > $File ; if [ -s $File ] ; then echo "$File exists and contains data." ; elif [ -e $File ] ; then echo "$File exists and is empty." ; else echo "$File does not exist." ; fi
|
||||
TestFile1 exists and contains data.
|
||||
[student@studentvm1 testdir]$
|
||||
```
|
||||
|
||||
现在你有一个可以测试这三种情况的 Bash CLI 程序,但是可能的情况是无限的。
|
||||
|
||||
如果你能像保存在文件中的脚本那样书写程序语句,那么对于即使更复杂的命令组合也会很容易看出它们的逻辑结构。图表 2 就是一个示例。 **if-elif-else** 结构中每一部分的程序语句的缩进让逻辑更变得清晰。
|
||||
|
||||
|
||||
```
|
||||
File="TestFile1"
|
||||
echo "This is $File" > $File
|
||||
if [ -s $File ]
|
||||
then
|
||||
echo "$File exists and contains data."
|
||||
elif [ -e $File ]
|
||||
then
|
||||
echo "$File exists and is empty."
|
||||
else
|
||||
echo "$File does not exist."
|
||||
fi
|
||||
```
|
||||
|
||||
_**Fig. 2: 像在脚本里一样重写书写命令行程序**_
|
||||
|
||||
对于大多数 CLI 程序来说,让这些复杂的命令变得有逻辑需要写很长的代码。虽然 CLI 可能是用 Linux 或 Bash 内置的命令,但是当 CLI 程序很长或很复杂时,创建一个脚本保存在一个文件中将更有效,保存到文件中后,可以随时运行。
|
||||
|
||||
#### 字符串比较操作符
|
||||
|
||||
字符串比较操作符使我们可以对字符串中的字符按字母顺序进行比较。图表 3 列出了仅有的几个字符串比较操作符。
|
||||
|
||||
Operator | Description
|
||||
---|---
|
||||
-z string | True if the length of string is zero
|
||||
-n string | True if the length of string is non-zero
|
||||
string1 == string2<br/>or<br/>string1 = string2 | 如果两个字符串相等,返回 true。为了保持 POSIX 一致性,一个等号 **=** 应与 test 命令一起用。命令 **[[** 支持模式匹配,跟前面描述的一样(复杂命令)。
|
||||
string1 != string2 | 两个字符串不相等,返回 true
|
||||
string1 < string2 | 如果对 string1 和 string2 按字母顺序进行排序,string1 排在 string2 前面(即基于地区设定的对所有字母和特殊字符的排列顺序)
|
||||
string1 > string2 | 如果对 string1 和 string2 按字母顺序进行排序,string1 排在 string2 后面
|
||||
_**Fig. 3: Bash 字符串逻辑操作符**_
|
||||
|
||||
首先,检查字符串长度。比较表达式中 **$MyVar** 两边的双引号不能省略(你仍应该在目录 **~/testdir** 下 )。
|
||||
|
||||
|
||||
```
|
||||
[student@studentvm1 testdir]$ MyVar="" ; if [ -z "$MyVar" ] ; then echo "MyVar is zero length." ; else echo "MyVar contains data" ; fi
|
||||
MyVar is zero length.
|
||||
[student@studentvm1 testdir]$ MyVar="Random text" ; if [ -z "$MyVar" ] ; then echo "MyVar is zero length." ; else echo "MyVar contains data" ; fi
|
||||
MyVar is zero length.
|
||||
```
|
||||
|
||||
你也可以这样做:
|
||||
|
||||
|
||||
```
|
||||
[student@studentvm1 testdir]$ MyVar="Random text" ; if [ -n "$MyVar" ] ; then echo "MyVar contains data." ; else echo "MyVar is zero length" ; fi
|
||||
MyVar contains data.
|
||||
[student@studentvm1 testdir]$ MyVar="" ; if [ -n "$MyVar" ] ; then echo "MyVar contains data." ; else echo "MyVar is zero length" ; fi
|
||||
MyVar is zero length
|
||||
```
|
||||
|
||||
有时候你需要知道一个字符串确切的长度。这虽然不是比较,但是也与比较相关。不幸的是,计算字符串的长度没有简单的方法。有很多种方法可以计算,但是我认为使用 **expr**(evaluate expression,求值表达式)是相对最简单的一种。阅读 **expr** 的 man 主页可以了解更多相关知识。注意表达式中你检测的字符串或变量两边的引号不要省略。
|
||||
|
||||
|
||||
```
|
||||
[student@studentvm1 testdir]$ MyVar="" ; expr length "$MyVar"
|
||||
0
|
||||
[student@studentvm1 testdir]$ MyVar="How long is this?" ; expr length "$MyVar"
|
||||
17
|
||||
[student@studentvm1 testdir]$ expr length "We can also find the length of a literal string as well as a variable."
|
||||
70
|
||||
```
|
||||
|
||||
关于比较操作符,在我们的脚本中使用了大量的检测两个字符串是否相等(例如,两个字符串是否实际上是同一个字符串)的操作。我使用的是非 POSIX 版本的比较表达式:
|
||||
|
||||
|
||||
```
|
||||
[student@studentvm1 testdir]$ Var1="Hello World" ; Var2="Hello World" ; if [ "$Var1" == "$Var2" ] ; then echo "Var1 matches Var2" ; else echo "Var1 and Var2 do not match." ; fi
|
||||
Var1 matches Var2
|
||||
[student@studentvm1 testdir]$ Var1="Hello World" ; Var2="Hello world" ; if [ "$Var1" == "$Var2" ] ; then echo "Var1 matches Var2" ; else echo "Var1 and Var2 do not match." ; fi
|
||||
Var1 and Var2 do not match.
|
||||
```
|
||||
|
||||
在你自己的脚本中去试一下这些操作符。
|
||||
|
||||
#### 数字比较操作符
|
||||
|
||||
数字操作符用于两个数字参数之间的比较。像其他类操作符一样,大部分都很容易理解。
|
||||
|
||||
Operator | Description
|
||||
---|---
|
||||
arg1 -eq arg2 | True if arg1 equals arg2
|
||||
arg1 -ne arg2 | 如果 arg1 不等于 arg2,返回 true
|
||||
arg1 -lt arg2 | 如果 arg1 小于 arg2,返回 true
|
||||
arg1 -le arg2 | 如果 arg1 小于或等于 arg2,返回 true
|
||||
arg1 -gt arg2 | 如果 arg1 大于 arg2,返回 true
|
||||
arg1 -ge arg2 | 如果 arg1 大于或等于 arg2,返回 true
|
||||
|
||||
_**Fig. 4: Bash 数字比较逻辑操作符**_
|
||||
|
||||
来看几个简单的例子。第一个示例设置变量 **$X** 的值为 1,然后检测 **$X** 是否等于 1.第二个示例中, **$X** 被设置为 0,所以比较表达式返回结果不为 true。
|
||||
|
||||
|
||||
```
|
||||
[student@studentvm1 testdir]$ X=1 ; if [ $X -eq 1 ] ; then echo "X equals 1" ; else echo "X does not equal 1" ; fi
|
||||
X equals 1
|
||||
[student@studentvm1 testdir]$ X=0 ; if [ $X -eq 1 ] ; then echo "X equals 1" ; else echo "X does not equal 1" ; fi
|
||||
X does not equal 1
|
||||
[student@studentvm1 testdir]$
|
||||
```
|
||||
|
||||
自己来多尝试一下其他的。
|
||||
|
||||
#### 混杂操作符
|
||||
|
||||
这些混杂操作符展示一个 shell 选项是否被设置或一个 shell 变量是否有值,但是它不显示变量的值,只显示它是否有值。
|
||||
|
||||
Operator | Description
|
||||
---|---
|
||||
-o optname | 如果一个选项 `optname` 开启了(查看 Bash 内建的 Bash man 页面中 **-o** 选项描述下面的选项列表),则返回 true
|
||||
-v varname | 如果 shell 变量 varname 被设置了值(被赋予了值),则返回 true
|
||||
-R varname | 如果一个 shell 变量 varname 被设置了值且是一个名字引用,则返回 true
|
||||
|
||||
_**Fig. 5: 混杂 Bash 逻辑操作符**_
|
||||
|
||||
自己来使用这些操作符实践下。
|
||||
|
||||
### 扩展
|
||||
|
||||
Bash 支持一些类型扩展和一些非常有用的命令替换。根据 Bash man 页面,Bash 有多种扩展格式。本文只介绍其中 5 种:`~` 扩展,算术扩展,路径名称扩展,大括号扩展和命令替换。
|
||||
|
||||
#### 大括号扩展
|
||||
|
||||
大括号扩展是生成任意字符串的一种方法。(下面的例子是用特定模式的字符创建大量的文件。)大括号扩展可以用于生产任意字符串的列表,并把它们插入一个静态字符串的中间特定位置或静态字符串的两端。这可能很难想象,所以还是来实践一下。
|
||||
|
||||
首先,看一下大括号扩展的作用:
|
||||
|
||||
|
||||
```
|
||||
[student@studentvm1 testdir]$ echo {string1,string2,string3}
|
||||
string1 string2 string3
|
||||
```
|
||||
|
||||
看起来不是很有用,对吧?但是用其他方式使用它,再来看看:
|
||||
|
||||
|
||||
```
|
||||
[student@studentvm1 testdir]$ echo "Hello "{David,Jen,Rikki,Jason}.
|
||||
Hello David. Hello Jen. Hello Rikki. Hello Jason.
|
||||
```
|
||||
|
||||
这看起来貌似有点用了 — 我们可以少打很多字。现在试一下这个:
|
||||
|
||||
|
||||
```
|
||||
[student@studentvm1 testdir]$ echo b{ed,olt,ar}s
|
||||
beds bolts bars
|
||||
```
|
||||
|
||||
我可以继续举例,但是你应该已经理解了它的用处。
|
||||
|
||||
#### ~ 扩展
|
||||
|
||||
资料显示,使用最多的扩展是波浪字符(~)扩展。当你在命令中使用它(如 **cd ~/Documents**)时,Bash shell 把这个快捷方式展开式完整的 home 目录。
|
||||
|
||||
使用 Bash 程序观察 ~ 扩展的作用:
|
||||
|
||||
|
||||
```
|
||||
[student@studentvm1 testdir]$ echo ~
|
||||
/home/student
|
||||
[student@studentvm1 testdir]$ echo ~/Documents
|
||||
/home/student/Documents
|
||||
[student@studentvm1 testdir]$ Var1=~/Documents ; echo $Var1 ; cd $Var1
|
||||
/home/student/Documents
|
||||
[student@studentvm1 Documents]$
|
||||
```
|
||||
|
||||
#### 路径名称扩展
|
||||
|
||||
路径名称扩展是展开文件代换模式到匹配到的完成路径名称的另一种说法,匹配字符使用 **?** 和 **\*** 。文件代换指的是在大量操作中匹配文件名、路径和其他字符串时用特定的模式字符产生极大的灵活性。这些特定的模式字符允许匹配字符串中的一个、多个或特定字符。
|
||||
|
||||
* **?** — 匹配字符串中特定位置的一个任意字符
|
||||
* ***** — 匹配字符串中特定位置的 0 个或多个任意字符
|
||||
|
||||
这个扩展用于匹配路径名称。为了弄清它的用法,请确保 **testdir** 是当前工作目录(PWD),先执行基本的列出清单命令 `ls`(我 home 目录下的内容跟你的不一样)。
|
||||
|
||||
|
||||
```
|
||||
[student@studentvm1 testdir]$ ls
|
||||
chapter6 cpuHog.dos dmesg1.txt Documents Music softlink1 testdir6 Videos
|
||||
chapter7 cpuHog.Linux dmesg2.txt Downloads Pictures Templates testdir
|
||||
testdir cpuHog.mac dmesg3.txt file005 Public testdir tmp
|
||||
cpuHog Desktop dmesg.txt link3 random.txt testdir1 umask.test
|
||||
[student@studentvm1 testdir]$
|
||||
```
|
||||
|
||||
现在列出以 **Do**, **testdir/Documents**, 和 **testdir/Downloads** 开头的目录:
|
||||
|
||||
|
||||
```
|
||||
Documents:
|
||||
Directory01 file07 file15 test02 test10 test20 testfile13 TextFiles
|
||||
Directory02 file08 file16 test03 test11 testfile01 testfile14
|
||||
file01 file09 file17 test04 test12 testfile04 testfile15
|
||||
file02 file10 file18 test05 test13 testfile05 testfile16
|
||||
file03 file11 file19 test06 test14 testfile09 testfile17
|
||||
file04 file12 file20 test07 test15 testfile10 testfile18
|
||||
file05 file13 Student1.txt test08 test16 testfile11 testfile19
|
||||
file06 file14 test01 test09 test18 testfile12 testfile20
|
||||
|
||||
Downloads:
|
||||
[student@studentvm1 testdir]$
|
||||
```
|
||||
|
||||
然而,并没有得到你期望的结果。它列出了以 **Do** 开头的目录下的内容。使用 **-d** 选项,仅列出目录而不列出它们的内容。
|
||||
|
||||
|
||||
```
|
||||
[student@studentvm1 testdir]$ ls -d Do*
|
||||
Documents Downloads
|
||||
[student@studentvm1 testdir]$
|
||||
```
|
||||
|
||||
在两个例子中,Bash shell 都把 **Do*** 模式展开成了匹配该模式的目录名称。但是如果有文件也匹配这个模式,会发生什么?
|
||||
|
||||
|
||||
```
|
||||
[student@studentvm1 testdir]$ touch Downtown ; ls -d Do*
|
||||
Documents Downloads Downtown
|
||||
[student@studentvm1 testdir]$
|
||||
```
|
||||
|
||||
因此所有匹配这个模式的文件也被展开成了完成名字。
|
||||
|
||||
#### 命令替换
|
||||
|
||||
命令替换让一个命令的 STDOUT 数据流被当做参数传给另一个命令,例如,在一个循环中作为一系列被处理的项目。Bash man 页面显示:”命令替换用命令的输出替换了命令的名字。“ 可能不太好理解。
|
||||
|
||||
命令替换有两种格式:**`command`** 和 **$(command)**。在更早的格式中使用反引号(**\`**),在命令中使用反斜杠(`\`)来保持它转义之前的文本含义。然而,当用在新版本的括号格式中时,反斜杠被当做一个特殊字符处理。也请注意带括号的格式打开个关闭命令语句都是用一个括号。
|
||||
|
||||
我经常在命令行程序和脚本中出现一个命令的结果可以被作为参数传给另一个命令时使用命令替换。
|
||||
|
||||
来看一个非常简单的示例,这个示例使用了这个扩展的两种格式(再一次提醒,确保 **testdir** 是当前工作目录):
|
||||
|
||||
|
||||
```
|
||||
[student@studentvm1 testdir]$ echo "Todays date is `date`"
|
||||
Todays date is Sun Apr 7 14:42:46 EDT 2019
|
||||
[student@studentvm1 testdir]$ echo "Todays date is $(date)"
|
||||
Todays date is Sun Apr 7 14:42:59 EDT 2019
|
||||
[student@studentvm1 testdir]$
|
||||
```
|
||||
|
||||
**-seq** 工具加上 **-w** 选项后,在生成的数字前面会用 0 补全,这样所有的结果都等宽,例如,忽略数字的值,它们的位数一样。这样在对它们按数字顺序进行排列时很容易。
|
||||
|
||||
**-seq** 工具用于一个数字序列:
|
||||
|
||||
|
||||
```
|
||||
[student@studentvm1 testdir]$ seq 5
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
5
|
||||
[student@studentvm1 testdir]$ echo `seq 5`
|
||||
1 2 3 4 5
|
||||
[student@studentvm1 testdir]$
|
||||
```
|
||||
|
||||
现在你可以做一些更有用处的操作,比如创建大量用于测试的空文件。
|
||||
|
||||
|
||||
```
|
||||
`[student@studentvm1 testdir]$ for I in $(seq -w 5000) ; do touch file-$I ; done`
|
||||
```
|
||||
|
||||
**seq -w 5000** 语句生成了1 到 5000 的数字序列。通过把命令替换用于 **for** 语句,**for** 语句就可以使用数字序列来生成文件名的数字部分。
|
||||
|
||||
#### 算术扩展
|
||||
|
||||
Bash 可以进行整型的数学计算,但是比较繁琐(你一会儿将看到)。数字扩展的语法是 **$((算术表达式))** ,分别用两个括号来打开和关闭表达式。算术扩展在 shell 程序或脚本中类似命令替换;表达式结算后的结果替换了表达式,用于 shell 后续的计算。
|
||||
|
||||
我们再用一个简单的用法来开始:
|
||||
|
||||
|
||||
```
|
||||
[student@studentvm1 testdir]$ echo $((1+1))
|
||||
2
|
||||
[student@studentvm1 testdir]$ Var1=5 ; Var2=7 ; Var3=$((Var1*Var2)) ; echo "Var 3 = $Var3"
|
||||
Var 3 = 35
|
||||
```
|
||||
|
||||
下面的除法结果是 0,因为表达式的结果是一个小于 1 的整型数字:
|
||||
|
||||
|
||||
```
|
||||
[student@studentvm1 testdir]$ Var1=5 ; Var2=7 ; Var3=$((Var1/Var2)) ; echo "Var 3 = $Var3"
|
||||
Var 3 = 0
|
||||
```
|
||||
|
||||
这是一个我经常在脚本或 CLI 程序中使用的一个简单的计算,用来查看在 Linux 主机中使用了多少虚拟内存。 **free** 不提供我需要的数据:
|
||||
|
||||
|
||||
```
|
||||
[student@studentvm1 testdir]$ RAM=`free | grep ^Mem | awk '{print $2}'` ; Swap=`free | grep ^Swap | awk '{print $2}'` ; echo "RAM = $RAM and Swap = $Swap" ; echo "Total Virtual memory is $((RAM+Swap))" ;
|
||||
RAM = 4037080 and Swap = 6291452
|
||||
Total Virtual memory is 10328532
|
||||
```
|
||||
|
||||
我使用 **\`** 字符来划定用作命令替换的界限。我用 Bash 算术扩展的场景主要是用脚本检查系统资源用量后基于返回的结果选择一个程序运行的路径。
|
||||
|
||||
### 总结
|
||||
|
||||
本文是 Bash 编程语言系列的第二篇,探讨了 Bash 文件,字符串,数字和各种提供流程控制逻辑的逻辑操作符还有不同种类的 shell 扩展。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/19/10/programming-bash-logical-operators-shell-expansions
|
||||
|
||||
作者:[David Both][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/dboth
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/OSDC_women_computing_5.png?itok=YHpNs_ss (Women in computing and open source v5)
|
||||
[2]: http://www.both.org/?page_id=1183
|
||||
[3]: https://opensource.com/article/19/10/programming-bash-part-1
|
@ -1,6 +1,6 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (lxbwolf)
|
||||
[#]: reviewer: ( )
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (How to program with Bash: Loops)
|
||||
@ -324,7 +324,7 @@ via: https://opensource.com/article/19/10/programming-bash-loops
|
||||
作者:[David Both][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[lxbwolf](https://github.com/lxbwolf)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
@ -0,0 +1,163 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (HankChow)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (3 easy steps to update your apps to Python 3)
|
||||
[#]: via: (https://opensource.com/article/19/12/update-apps-python-3)
|
||||
[#]: author: (Seth Kenlon https://opensource.com/users/seth)
|
||||
|
||||
将你的应用迁移到 Python 3 的三个步骤
|
||||
======
|
||||
Python 2 气数将尽,是时候将你的项目从 Python 2 迁移到 Python 3 了。
|
||||
|
||||
![Hands on a keyboard with a Python book ][1]
|
||||
|
||||
Python 2.x 很快就要[失去官方支持][2]了,尽管如此,从 Python 2 迁移到 Python 3 却并没有想象中那么难。我在上周用了一个晚上的时间将一个 3D 渲染器及其对应的 [PySide][3] 迁移到 Python 3,回想起来,尽管在迁移过程中无可避免地会遇到一些牵一发而动全身的修改,但整个过程相比起痛苦的重构来说简直是出奇地简单。
|
||||
|
||||
每个人都别无选择地有各种必须迁移的原因:或许是觉得已经拖延太久了,或许是依赖了某个在 Python 2 下不再维护的模块。但如果你仅仅是想通过做一些事情来对开源做贡献,那么把一个 Python 2 应用迁移到 Python 3 就是一个简单而又有意义的做法。
|
||||
|
||||
无论你从 Python 2 迁移到 Python 3 的原因是什么,这都是一项重要的任务。按照以下三个步骤,可以让你把任务完成得更加清晰。
|
||||
|
||||
### 1\. 使用 2to3
|
||||
|
||||
从几年前开始,Python 在你或许还不知道的情况下就已经自带了一个名叫 [2to3][4] 的脚本,它可以帮助你实现大部分代码从 Python 2 到 Python 3 的自动转换。
|
||||
|
||||
下面是一段使用 Python 2.6 编写的代码:
|
||||
|
||||
|
||||
```
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
mystring = u'abcdé'
|
||||
print ord(mystring[-1])
|
||||
```
|
||||
|
||||
对其执行 2to3 脚本:
|
||||
|
||||
|
||||
```
|
||||
$ 2to3 example.py
|
||||
RefactoringTool: Refactored example.py
|
||||
\--- example.py (original)
|
||||
+++ example.py (refactored)
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
-mystring = u'abcdé'
|
||||
-print ord(mystring[-1])
|
||||
+mystring = 'abcdé'
|
||||
+print(ord(mystring[-1]))
|
||||
RefactoringTool: Files that need to be modified:
|
||||
RefactoringTool: example.py
|
||||
```
|
||||
|
||||
在默认情况下,2to3 只会对迁移到 Python 3 时必须作出修改的代码进行标示,在输出结果中显示的 Python 3 代码是直接可用的,但你可以在 2to3 加上 `-w` 或者 `--write` 参数,这样它就可以直接按照给出的方案修改你的 Python 2 代码文件了。
|
||||
|
||||
|
||||
```
|
||||
$ 2to3 -w example.py
|
||||
[...]
|
||||
RefactoringTool: Files that were modified:
|
||||
RefactoringTool: example.py
|
||||
```
|
||||
|
||||
2to3 脚本不仅仅对单个文件有效,你还可以把它用于一个目录下的所有 Python 文件,同时它也会递归地对所有子目录下的 Python 文件都生效。
|
||||
|
||||
### 2\. 使用 Pylint 或 Pyflakes
|
||||
|
||||
有一些不良的代码习惯在 Python 2 下运行是没有异常的,在 Python 3 下运行则会或多或少报出错误,并且这些代码无法通过语法转换来修复,所以 2to3 对它们没有效果,但一旦使用 Python 3 来运行就会产生报错。
|
||||
|
||||
对于这种情况,你需要使用 [Pylint][5]、[Pyflakes][6](或封装好的 [flake8][7])这类工具。其中我更喜欢 Pyflakes,它会忽略代码风格上的差异,在这一点上它和 Pylint 不同。尽管代码优美是 Python 的一大特点,但在代码迁移的层面上,“让代码功能保持一致”无疑比“让代码风格保持一致”重要得多/
|
||||
|
||||
以下是 Pyflakes 的输出样例:
|
||||
|
||||
|
||||
```
|
||||
$ pyflakes example/maths
|
||||
example/maths/enum.py:19: undefined name 'cmp'
|
||||
example/maths/enum.py:105: local variable 'e' is assigned to but never used
|
||||
example/maths/enum.py:109: undefined name 'basestring'
|
||||
example/maths/enum.py:208: undefined name 'EnumValueCompareError'
|
||||
example/maths/enum.py:208: local variable 'e' is assigned to but never used
|
||||
```
|
||||
|
||||
上面这些由 Pyflakes 输出的内容清晰地给出了代码中需要修改的问题。相比之下,Pylint 会输出多达 143 行的内容,而且多数是诸如代码缩进这样无关紧要的问题。
|
||||
|
||||
值得注意的是第 19 行这个容易产生误导的错误。从输出来看你可能会以为 `cmp` 是一个在使用前未定义的变量,实际上 `cmp` 是 Python 2 的一个内置函数,而它在 Python 3 中被移除了。而且这段代码被放在了 `try` 语句块中,除非认真检查这段代码的输出值,否则这个问题很容易被忽略掉。
|
||||
|
||||
|
||||
```
|
||||
try:
|
||||
result = cmp(self.index, other.index)
|
||||
except:
|
||||
result = 42
|
||||
|
||||
return result
|
||||
```
|
||||
|
||||
在代码迁移过程中,你会发现很多原本在 Python 2 中能正常运行的函数都发生了变化,甚至直接在 Python 3 中被移除了。例如 PySide 的绑定方式发生了变化、`importlib` 取代了 `imp` 等等。这样的问题只能见到一个解决一个,而涉及到的功能需要重构还是直接放弃,则需要你自己权衡。但目前来说,大多数问题都是已知的,并且有[完善的文档记录][8]。所以难的不是修复问题,而是找到问题,从这个角度来说,使用 Pyflake 是很有必要的。
|
||||
|
||||
### 3\. 修复被破坏的 Python 2 代码
|
||||
|
||||
尽管 2to3 脚本能够帮助你把代码修改成兼容 Python 3 的形式,但对于一个完整的代码库,它就显得有点无能为力了,因为一些老旧的代码在 Python 3 中可能需要不同的结构来表示。在这样的情况下,只能人工进行修改。
|
||||
|
||||
例如以下代码在 Python 2.6 中可以正常运行:
|
||||
|
||||
|
||||
```
|
||||
class CLOCK_SPEED:
|
||||
TICKS_PER_SECOND = 16
|
||||
TICK_RATES = [int(i * TICKS_PER_SECOND)
|
||||
for i in (0.5, 1, 2, 3, 4, 6, 8, 11, 20)]
|
||||
|
||||
class FPS:
|
||||
STATS_UPDATE_FREQUENCY = CLOCK_SPEED.TICKS_PER_SECOND
|
||||
```
|
||||
|
||||
类似 2to3 和 Pyflakes 这些自动化工具并不能发现其中的问题,但如果上述代码使用 Python 3 来运行,解释器会认为 `CLOCK_SPEED.TICKS_PER_SECOND` 是未被明确定义的。因此就需要把代码改成面向对象的结构:
|
||||
|
||||
|
||||
```
|
||||
class CLOCK_SPEED:
|
||||
def TICKS_PER_SECOND():
|
||||
TICKS_PER_SECOND = 16
|
||||
TICK_RATES = [int(i * TICKS_PER_SECOND)
|
||||
for i in (0.5, 1, 2, 3, 4, 6, 8, 11, 20)]
|
||||
return TICKS_PER_SECOND
|
||||
|
||||
class FPS:
|
||||
STATS_UPDATE_FREQUENCY = CLOCK_SPEED.TICKS_PER_SECOND()
|
||||
```
|
||||
|
||||
你也许会认为如果把 `TICKS_PER_SECOND()` 改写为一个构造函数能让代码看起来更加简洁,但这样就需要把这个方法的调用形式从 `CLOCK_SPEED.TICKS_PER_SECOND()` 改为 `CLOCK_SPEED()` 了,这样的改动或多或少会对整个库造成一些未知的影响。如果你对整个代码库的结构烂熟于心,那么你确实可以随心所欲地作出这样的修改。但我通常认为,只要我做出了修改,都可能会影响到其它代码中的至少三处地方,因此我更倾向于不使代码的结构发生改变。
|
||||
|
||||
### 坚持信念
|
||||
|
||||
如果你正在尝试将一个大项目从 Python 2 迁移到 Python 3,也许你会觉得这是一个漫长的过程。你可能会费尽心思也找不到一条有用的报错信息,这种情况下甚至会有将代码推倒重建的冲动。但从另一个角度想,代码原本在 Python 2 中就可以运行,要让它能在 Python 3 中继续运行,你需要做的只是对它稍加转换而已。
|
||||
|
||||
但只要你完成了迁移,你就得到了这个模块或者整个应用程序的 Python 3 版本,外加 Python 官方的长期支持。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/19/12/update-apps-python-3
|
||||
|
||||
作者:[Seth Kenlon][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[HankChow](https://github.com/HankChow)
|
||||
校对:[校对者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/python-programming-code-keyboard.png?itok=fxiSpmnd "Hands on a keyboard with a Python book "
|
||||
[2]: https://opensource.com/article/19/11/end-of-life-python-2
|
||||
[3]: https://pypi.org/project/PySide/
|
||||
[4]: https://docs.python.org/3.1/library/2to3.html
|
||||
[5]: https://opensource.com/article/19/10/python-pylint-introduction
|
||||
[6]: https://pypi.org/project/pyflakes/
|
||||
[7]: https://opensource.com/article/19/5/python-flake8
|
||||
[8]: https://docs.python.org/3.0/whatsnew/3.0.html
|
||||
|
Loading…
Reference in New Issue
Block a user