mirror of
https://github.com/LCTT/TranslateProject.git
synced 2026-08-26 04:13:30 +08:00
@@ -1,122 +1,116 @@
|
||||
程序员的学习之路
|
||||
============================================================
|
||||
|
||||
*2016 年 10 月,当我从微软离职时,我已经在微软工作了近 21 年,在工业界也快 35 年了。我花了一些时间反思我这些年来学到的东西,这些文字是那篇帖子稍加修改后得到。请见谅,文章有一点长。*
|
||||
*2016 年 10 月,当我从微软离职时,我已经在微软工作了近 21 年,在业界也快 35 年了。我花了一些时间反思我这些年来学到的东西,这些文字是那篇帖子稍加修改后得到。请见谅,文章有一点长。*
|
||||
|
||||
要成为一名专业的程序员,你需要知道的事情多得令人吃惊:语言的细节,API,算法,数据结构,系统和工具。这些东西一直在随着时间变化——新的语言和编程环境不断出现,似乎总有热门的新工具或新语言是“每个人”都在使用的。紧跟潮流,保持专业,这很重要。木匠需要知道如何为工作选择合适的锤子和钉子,并且要有能力笔直精准地钉入钉子。
|
||||
要成为一名专业的程序员,你需要知道的事情多得令人吃惊:语言的细节、API、算法、数据结构、系统和工具。这些东西一直在随着时间变化——新的语言和编程环境不断出现,似乎总有一些“每个人”都在使用的热门的新工具或新语言。紧跟潮流,保持专业,这很重要。木匠需要知道如何为工作选择合适的锤子和钉子,并且要有能力笔直精准地钉入钉子。
|
||||
|
||||
与此同时,我也发现有一些理论和方法有着广泛的应用场景,它们能使用几十年。底层设备的性能和容量在这几十年来增长了几个数量级,但系统设计的思考方式还是互相有关联的,这些思考方式比具体的实现更根本。理解这些重复出现的主题对分析与设计我们所负责的系统大有帮助。
|
||||
|
||||
谦卑和自我
|
||||
### 谦卑和自我
|
||||
|
||||
这不仅仅局限于编程,但在编程这个持续发展的领域,一个人需要在谦卑和自我中保持平衡。总有新的东西需要学习,并且总有人能帮助你学习——如果你愿意学习的话。一个人即需要保持谦卑,认识到自己不懂并承认它,也要保持自我,相信自己能掌握一个新的领域,并且能运用你已经掌握的知识。我见过的最大的挑战就是一些人在某个领域深入专研了很长时间,“忘记”了自己擅长学习新的东西。最好的学习来自放手去做,建造一些东西,即便只是一个原型或者 hack。我知道的最好的程序员对技术有广泛的认识,但同时他们对某个技术深入研究,成为了专家。而深入的学习来自努力解决真正困难的问题。
|
||||
这不仅仅局限于编程,但在编程这个持续发展的领域,一个人需要在谦卑和自我中保持平衡。总有新的东西需要学习,并且总有人能帮助你学习——如果你愿意学习的话。一个人即需要保持谦卑,认识到自己不懂并承认它,也要保持自我,相信自己能掌握一个新的领域,并且能运用你已经掌握的知识。我见过的最大的挑战就是一些人在某个领域深入专研了很长时间,“忘记”了自己擅长学习新的东西。最好的学习来自放手去做,建造一些东西,即便只是一个原型或者 hack。我知道的最好的程序员对技术有广泛的认识,但同时他们对某个技术深入研究,成为了专家。而深入的学习来自努力解决真正困难的问题。
|
||||
|
||||
端到端观点
|
||||
### 端到端观点
|
||||
|
||||
1981 年,Jerry Saltzer, Dave Reed 和 Dave Clark 在做因特网和分布式系统的早期工作,他们提出了端到端观点,并作出了[经典的阐述][4]。网络上的文章有许多误传,所以更应该阅读论文本身。论文的作者很谦虚,没有声称这是他们自己的创造——从他们的角度看,这只是一个常见的工程策略,不只在通讯领域中,在其他领域中也有运用。他们只是将其写下来并收集了一些例子。下面是文章的一个小片段:
|
||||
1981 年,Jerry Saltzer、 Dave Reed 和 Dave Clark 在做因特网和分布式系统的早期工作,他们提出了<ruby>端到端<rt>end to end</rt></ruby>观点,并作出了[经典的阐述][4]。网络上的文章有许多误传,所以更应该阅读论文本身。论文的作者很谦虚,没有声称这是他们自己的创造——从他们的角度看,这只是一个常见的工程策略,不只在通讯领域中,在其他领域中也有运用。他们只是将其写下来并收集了一些例子。下面是文章的一个小片段:
|
||||
|
||||
> 当我们设计系统的一个功能时,仅依靠端点的知识和端点的参与,就能正确地完整地实现这个功能。在一些情况下,系统的内部模块局部实现这个功能,可能会对性能有重要的提升。
|
||||
|
||||
论文称这是一个“观点”,虽然在维基百科和其他地方它已经被上升成“原则”。实际上,还是把它看作一个观点比较好,正如作者们所说,系统设计者面临的最难的问题之一就是如何在系统组件之间划分责任,这会引发不断的讨论:怎样在划分功能时权衡利弊,怎样隔离复杂性,怎样设计一个灵活的高性能系统来满足不断变化的需求。没有简单的原则可以直接遵循。
|
||||
该论文称这是一个“观点”,虽然在维基百科和其他地方它已经被上升成“原则”。实际上,还是把它看作一个观点比较好,正如作者们所说,系统设计者面临的最难的问题之一就是如何在系统组件之间划分责任,这会引发不断的讨论:怎样在划分功能时权衡利弊,怎样隔离复杂性,怎样设计一个灵活的高性能系统来满足不断变化的需求。没有简单的原则可以直接遵循。
|
||||
|
||||
互联网上的大部分讨论集中在通信系统上,但端到端观点的适用范围其实更广泛。分布式系统中的“最终一致性”就是一个例子。一个满足“最终一致性”的系统,可以让系统中的元素暂时进入不一致的状态,从而简化系统,优化性能,因为有一个更大的端到端过程来解决不一致的状态。我喜欢横向拓展的订购系统的例子(例如亚马逊),它不要求每个请求都通过中央库存的控制点。缺少中央控制点可能允许两个终端出售相同的最后一本书,所以系统需要用某种方法来解决这个问题,如通知客户该书会延期交货。不论怎样设计,想购买的最后一本书在订单完成前都有可能被仓库中的叉车运出厍(译者注:比如被其他人下单购买)。一旦你意识到你需要一个端到端的解决方案,并实现了这个方案,那系统内部的设计就可以被优化,并利用这个解决方案。
|
||||
互联网上的大部分讨论集中在通信系统上,但端到端观点的适用范围其实更广泛。分布式系统中的“<ruby>最终一致性<rt>eventual consistency</rt></ruby>”就是一个例子。一个满足“最终一致性”的系统,可以让系统中的元素暂时进入不一致的状态,从而简化系统,优化性能,因为有一个更大的端到端过程来解决不一致的状态。我喜欢横向拓展的订购系统的例子(例如亚马逊),它不要求每个请求都通过中央库存的控制点。缺少中央控制点可能允许两个终端出售相同的最后一本书,所以系统需要用某种方法来解决这个问题,如通知客户该书会延期交货。不论怎样设计,想购买的最后一本书在订单完成前都有可能被仓库中的叉车运出厍(LCTT 译注:比如被其他人下单购买)。一旦你意识到你需要一个端到端的解决方案,并实现了这个方案,那系统内部的设计就可以被优化以利用这个解决方案。
|
||||
|
||||
事实上,这种设计上的灵活性可以优化系统的性能,或者提供其他的系统功能,从而使得端到端的方法变得如此强大。端到端的思考往往允许内部进行灵活的操作,使整个系统更加健壮,并且能适应每个组件特性的变化。这些都让端到端的方法变得健壮,并能适应变化。
|
||||
|
||||
端到端方法意味着,添加会牺牲整体性能灵活性的抽象层和功能时要非常小心(也可能是其他的灵活性,但性能,特别是延迟,往往是特殊的)。如果你展示出底层的原始性能(performance, 也可能指操作),端到端的方法可以根据这个性能(操作)来优化,实现特定的需求。如果你破坏了底层性能(操作),即使你实现了重要的有附加价值的功能,你也牺牲了设计灵活性。
|
||||
端到端方法意味着,添加会牺牲整体性能灵活性的抽象层和功能时要非常小心(也可能是其他的灵活性,但性能,特别是延迟,往往是特殊的)。如果你展示出底层的原始性能(LCTT 译注:performance,也可能指操作,下同),端到端的方法可以根据这个性能(操作)来优化,实现特定的需求。如果你破坏了底层性能(操作),即使你实现了重要的有附加价值的功能,你也牺牲了设计灵活性。
|
||||
|
||||
如果系统足够庞大而且足够复杂,需要把整个开发团队分配给系统内部的组件,那么端到端观点可以和团队组织相结合。这些团队自然要扩展这些组件的功能,他们通常从牺牲设计上的灵活性开始,尝试在组件上实现端到端的功能。
|
||||
|
||||
应用端到端方法面临的挑战之一是确定端点在哪里。 俗话说,“大跳蚤上有小跳蚤,小跳蚤上有更少的跳蚤……等等”。
|
||||
|
||||
关注复杂性
|
||||
### 关注复杂性
|
||||
|
||||
编程是一门精确的艺术,每一行代码都要确保程序的正确执行。但这是带有误导的。编程的复杂性不在于各个部分的整合,也不在于各个部分之间如何相互交互。最健壮的程序将复杂性隔离开,让最重要的部分变的简单直接,通过简单的方式与其他部分交互。虽然隐藏复杂性和信息隐藏、数据抽象等其他设计方法一样,但我仍然觉得,如果你真的要定位出系统的复杂所在,并将其隔离开,那你需要对设计特别敏锐。
|
||||
编程是一门精确的艺术,每一行代码都要确保程序的正确执行。但这是带有误导的。编程的复杂性不在于各个部分的整合,也不在于各个部分之间如何相互交互。最健壮的程序会将复杂性隔离开,让最重要的部分变的简单直接,通过简单的方式与其他部分交互。虽然隐藏复杂性和信息隐藏、数据抽象等其他设计方法一样,但我仍然觉得,如果你真的要定位出系统的复杂所在,并将其隔离开,那你需要对设计特别敏锐。
|
||||
|
||||
在我的[文章][5]中反复提到的例子是早期的终端编辑器 VI 和 Emacs 中使用的屏幕重绘算法。早期的视频终端实现了控制序列,来控制绘制字符核心操作,也实现了附加的显示功能,来优化重新绘制屏幕,如向上向下滚动当前行,或者插入新行,或在当前行中移动字符。这些命令都具有不同的开销,并且这些开销在不同制造商的设备中也是不同的。(参见[TERMCAP][6]以获取代码链接和更完整的历史记录。)像文本编辑器这样的全屏应用程序希望尽快更新屏幕,因此需要优化使用这些控制序列来转换屏幕从一个状态到另一个状态。
|
||||
在我的[文章][5]中反复提到的例子是早期的终端编辑器 VI 和 Emacs 中使用的屏幕重绘算法。早期的视频终端实现了控制序列,来控制绘制字符核心操作,也实现了附加的显示功能,来优化重新绘制屏幕,如向上向下滚动当前行,或者插入新行,或在当前行中移动字符。这些命令都具有不同的开销,并且这些开销在不同制造商的设备中也是不同的。(参见[TERMCAP][6] 以获取代码和更完整的历史记录的链接。)像文本编辑器这样的全屏应用程序希望尽快更新屏幕,因此需要优化使用这些控制序列来从一个状态到另一个状态屏幕转换。
|
||||
|
||||
这些程序在设计上隐藏了底层的复杂性。系统中修改文本缓冲区的部分(功能上大多数创新都在这里)完全忽略了这些改变如何被转换成屏幕更新命令。这是可以接受的,因为针对*任何*内容的改变计算最佳命令所消耗的性能代价,远不及被终端本身实际执行这些更新命令的性能代价。在确定如何隐藏复杂性,以及隐藏哪些复杂性时,性能分析扮演着重要的角色,这一点在系统设计中非常常见。屏幕的更新与底层文本缓冲区的更改是异步的,并且可以独立于缓冲区的实际历史变化顺序。缓冲区*怎样*改变的并不重要,重要的是改变了*什么*。异步耦合,在组件交互时消除组件对历史路径依赖的组合,以及用自然的交互方式以有效地将组件组合在一起是隐藏耦合复杂度的常见特征。
|
||||
这些程序在设计上隐藏了底层的复杂性。系统中修改文本缓冲区的部分(功能上大多数创新都在这里)完全忽略了这些改变如何被转换成屏幕更新命令。这是可以接受的,因为针对*任何*内容的改变计算最佳命令所消耗的性能代价,远不及被终端本身实际执行这些更新命令的性能代价。在确定如何隐藏复杂性,以及隐藏哪些复杂性时,性能分析扮演着重要的角色,这一点在系统设计中非常常见。屏幕的更新与底层文本缓冲区的更改是异步的,并且可以独立于缓冲区的实际历史变化顺序。缓冲区是*怎样*改变的并不重要,重要的是改变了*什么*。异步耦合,在组件交互时消除组件对历史路径依赖的组合,以及用自然的交互方式以有效地将组件组合在一起是隐藏耦合复杂度的常见特征。
|
||||
|
||||
隐藏复杂性的成功不是由隐藏复杂性的组件决定的,而是由使用该模块的使用者决定的。这就是为什么组件的提供者至少要为组件的某些端到端过程负责。他们需要清晰的知道系统的其他部分如何与组件相互作用,复杂性是如何泄漏出来的(以及是否泄漏出来)。这常常表现为“这个组件很难使用”这样的反馈——这通常意味着它不能有效地隐藏内部复杂性,或者没有选择一个隐藏复杂性的功能边界。
|
||||
|
||||
分层与组件化
|
||||
### 分层与组件化
|
||||
|
||||
系统设计人员的一个基本工作是确定如何将系统分解成组件和层;决定自己要开发什么,以及从别的地方获取什么。开源项目在决定自己开发组件还是购买服务时,大多会选择自己开发,但组件之间交互的过程是一样的。在大规模工程中,理解这些决策将如何随着时间的推移而发挥作用是非常重要的。从根本上说,变化是程序员所做的一切的基础,所以这些设计决定不仅在当下被评估,还要随着产品的不断发展而在未来几年得到评估。
|
||||
系统设计人员的一个基本工作是确定如何将系统分解成组件和层;决定自己要开发什么,以及从别的地方获取什么。开源项目在决定自己开发组件还是购买服务时,大多会选择自己开发,但组件之间交互的过程是一样的。在大规模工程中,理解这些决策将如何随着时间的推移而发挥作用是非常重要的。从根本上说,变化是程序员所做的一切的基础,所以这些设计决定不仅要在当下评估,还要随着产品的不断发展而在未来几年得到评估。
|
||||
|
||||
以下是关于系统分解的一些事情,它们最终会占用大量的时间,因此往往需要更长的时间来学习和欣赏。
|
||||
|
||||
* 层泄漏。层(或抽象)[基本上是泄漏的][1]。这些泄漏会立即产生后果,也会随着时间的推移而产生两方面的后果。其中一方面就是该抽象层的特性渗透到了系统的其他部分,渗透的程度比你意识到得更深入。这些渗透可能是关于具体的性能特征的假设,以及抽象层的文档中没有明确的指出的行为发生的顺序。这意味着假如内部组件的行为发生变化,你的系统会比想象中更加脆弱。第二方面是你比表面上看起来更依赖组件内部的行为,所以如果你考虑改变这个抽象层,后果和挑战可能超出你的想象。
|
||||
* **层泄漏。**层(或抽象)[基本上是泄漏的][1]。这些泄漏会立即产生后果,也会随着时间的推移而产生两方面的后果。其中一方面就是该抽象层的特性渗透到了系统的其他部分,渗透的程度比你意识到得更深入。这些渗透可能是关于具体的性能特征的假设,以及抽象层的文档中没有明确的指出的行为发生的顺序。这意味着假如内部组件的行为发生变化,你的系统会比想象中更加脆弱。第二方面是你比表面上看起来更依赖组件内部的行为,所以如果你考虑改变这个抽象层,后果和挑战可能超出你的想象。
|
||||
* **层具有太多功能。**您所采用的组件具有比实际需要更多的功能,这几乎是一个真理。在某些情况下,你决定采用这个组件是因为你想在将来使用那些尚未用到的功能。有时,你采用组件是想“上快车”,利用组件完成正在进行的工作。在功能强大的抽象层上开发会带来一些后果。
|
||||
1. 组件往往会根据你并不需要的功能作出取舍。
|
||||
2. 为了实现那些你并不没有用到的功能,组件引入了复杂性和约束,这些约束将阻碍该组件的未来的演变。
|
||||
3. 层泄漏的范围更大。一些泄漏是由于真正的“抽象泄漏”,另一些是由于明显的,逐渐增加的对组件全部功能的依赖(但这些依赖通常都没有处理好)。Office 软件太大了,我们发现,对于我们建立的任何抽象层,我们最终都在系统的某个部分完全运用了它的功能。虽然这看起来是积极的(我们完全地利用了这个组件),但并不是所用的使用都有同样的价值。所以,我们最终要付出巨大的代价才能从一个抽象层往另一个抽象层迁移,这种“长尾”没什么价值,并且对使用场景认识不足。
|
||||
4. 附加的功能会增加复杂性,并增加功能滥用的可能。如果将验证 XML 的 API 指定为 XML 树的一部分,那这个 API 可以选择动态下载 XML 的模式定义。这在我们的基本文件解析代码中被错误地执行,导致 w3c.org 服务器上的大量性能下降以及(无意)分布式拒绝服务攻击。(这些被通俗地称为“地雷”API)。
|
||||
* **抽象层被更换。**需求在进化,系统在进化,组件被放弃。您最终需要更换该抽象层或组件。不管是对外部组件的依赖还是对内部组件的依赖都是如此。这意味着上述问题将变得重要起来。
|
||||
* **自己构建还是购买的决定将会改变。**这是上面几方面的必然结果。这并不意味着自己构建还是购买的决定在当时是错误的。一开始时往往没有合适的组件,一段时间之后才有合适的组件出现。或者,也可能你使用了一个组件,但最终发现它不符合您不断变化的要求,而且你的要求非常窄、很好理解,或者对你的价值体系来说是非常重要的,以至于拥有自己的模块是有意义的。这意味着你像关心自己构造的模块一样,关心购买的模块,关心它们是怎样泄漏并深入你的系统中的。
|
||||
* **抽象层会变臃肿。**一旦你定义了一个抽象层,它就开始增加功能。层是对使用模式优化的自然分界点。臃肿的层的困难在于,它往往会降低您利用底层的不断创新的能力。从某种意义上说,这就是操作系统公司憎恨构建在其核心功能之上的臃肿的层的原因——采用创新的速度放缓了。避免这种情况的一种比较规矩的方法是禁止在适配器层中进行任何额外的状态存储。微软基础类在 Win32 上采用这个一般方法。在短期内,将功能集成到现有层(最终会导致上述所有问题)而不是重构和重新推导是不可避免的。理解这一点的系统设计人员寻找分解和简化组件的方法,而不是在其中增加越来越多的功能。
|
||||
|
||||
* 层具有太多功能了。您所采用的组件具有比实际需要更多的功能,这几乎是一个真理。在某些情况下,你决定采用这个组件是因为你想在将来使用那些尚未用到的功能。有时,你采用组件是想“上快车”,利用组件完成正在进行的工作。在功能强大的抽象层上开发会带来一些后果。1) 组件往往会根据你并不需要的功能作出取舍。 2) 为了实现那些你并不没有用到的功能,组件引入了复杂性和约束,这些约束将阻碍该组件的未来的演变。3) 层泄漏的范围更大。一些泄漏是由于真正的“抽象泄漏”,另一些是由于明显的,逐渐增加的对组件全部功能的依赖(但这些依赖通常都没有处理好)。Office 太大了,我们发现,对于我们建立的任何抽象层,我们最终都在系统的某个部分完全运用了它的功能。虽然这看起来是积极的(我们完全地利用了这个组件),但并不是所用的使用都有同样的价值。所以,我们最终要付出巨大的代价才能从一个抽象层往另一个抽象层迁移,这种“长尾巴”没什么价值,并且对使用场景认识不足。4) 附加的功能会增加复杂性,并增加功能滥用的可能。如果将验证 XML 的 API 指定为 XML 树的一部分,那这个 API 可以选择动态下载 XML 的模式定义。这在我们的基本文件解析代码中被错误地执行,导致 w3c.org 服务器上的大量性能下降以及(无意)分布式拒绝服务攻击。(这些被通俗地称为“地雷”API)。
|
||||
### 爱因斯坦宇宙
|
||||
|
||||
* 抽象层被更换。需求发展,系统发展,组件被放弃。您最终需要更换该抽象层或组件。不管是对外部组件的依赖还是对内部组件的依赖都是如此。这意味着上述问题将变得重要起来。
|
||||
|
||||
* 自己构建还是购买的决定将会改变。这是上面几方面的必然结果。这并不意味着自己构建还是购买的决定在当时是错误的。一开始时往往没有合适的组件,一段时间之后才有合适的组件出现。或者,也可能你使用了一个组件,但最终发现它不符合您不断变化的要求,而且你的要求非常窄,能被理解,或着对你的价值体系来说是非常重要的,以至于拥有自己的模块是有意义的。这意味着你像关心自己构造的模块一样,关心购买的模块,关心它们是怎样泄漏并深入你的系统中的。
|
||||
|
||||
* 抽象层会变臃肿。一旦你定义了一个抽象层,它就开始增加功能。层是对使用模式优化的自然分界点。臃肿的层的困难在于,它往往会降低您利用底层的不断创新的能力。从某种意义上说,这就是操作系统公司憎恨构建在其核心功能之上的臃肿的层的原因——采用创新的速度放缓了。避免这种情况的一种比较规矩的方法是禁止在适配器层中进行任何额外的状态存储。微软基础类在 Win32 上采用这个一般方法。在短期内,将功能集成到现有层(最终会导致上述所有问题)而不是重构和重新推导是不可避免的。理解这一点的系统设计人员寻找分解和简化组件的方法,而不是在其中增加越来越多的功能。
|
||||
|
||||
爱因斯坦宇宙
|
||||
|
||||
几十年来,我一直在设计异步分布式系统,但是在微软内部的一次演讲中,SQL 架构师 Pat Helland 的一句话震惊了我。 “我们生活在爱因斯坦的宇宙中,没有同时性。”在构建分布式系统时(基本上我们构建的都是分布式系统),你无法隐藏系统的分布式特性。这是物理的。我一直感到远程过程调用在根本上错误的,这是一个原因,尤其是那些“透明的”远程过程调用,它们就是想隐藏分布式的交互本质。你需要拥抱系统的分布式特性,因为这些意义几乎总是需要通过系统设计和用户体验来完成。
|
||||
几十年来,我一直在设计异步分布式系统,但是在微软内部的一次演讲中,SQL 架构师 Pat Helland 的一句话震惊了我。 “我们生活在爱因斯坦的宇宙中,没有同时性这种东西。”在构建分布式系统时(基本上我们构建的都是分布式系统),你无法隐藏系统的分布式特性。这是物理的。我一直感到远程过程调用在根本上错误的,这是一个原因,尤其是那些“透明的”远程过程调用,它们就是想隐藏分布式的交互本质。你需要拥抱系统的分布式特性,因为这些意义几乎总是需要通过系统设计和用户体验来完成。
|
||||
|
||||
拥抱分布式系统的本质则要遵循以下几个方面:
|
||||
|
||||
* 一开始就要思考设计对用户体验的影响,而不是试图在处理错误,取消请求和报告状态上打补丁。
|
||||
|
||||
* 使用异步技术来耦合组件。同步耦合是*不可能*的。如果某些行为看起来是同步的,是因为某些内部层尝试隐藏异步,这样做会遮蔽(但绝对不隐藏)系统运行时的基本行为特征。
|
||||
|
||||
* 认识到并且明确设计了交互状态机,这些状态表示长期的可靠的内部系统状态(而不是由深度调用堆栈中的变量值编码的临时,短暂和不可发现的状态)。
|
||||
|
||||
* 认识到失败是在所难免的。要保证能检测出分布式系统中的失败,唯一的办法就是直接看你的等待时间是否“太长”。这自然意味着[取消的等级最高][2]。系统的某一层(可能直接通向用户)需要决定等待时间是否过长,并取消操作。取消只是为了重建局部状态,回收局部的资源——没有办法在系统内广泛使用取消机制。有时用一种低成本,不可靠的方法广泛使用取消机制对优化性能可能有用。
|
||||
|
||||
* 认识到取消不是回滚,因为它只是回收本地资源和状态。如果回滚是必要的,它必须实现成一个端到端的功能。
|
||||
|
||||
* 承认永远不会真正知道分布式组件的状态。只要你发现一个状态,它可能就已经改变了。当你发送一个操作时,请求可能在传输过程中丢失,也可能被处理了但是返回的响应丢失了,或者请求需要一定的时间来处理,这样远程状态最终会在未来的某个任意的时间转换。这需要像幂等操作这样的方法,并且要能够稳健有效地重新发现远程状态,而不是期望可靠地跟踪分布式组件的状态。“[最终一致性][3]”的概念简洁地捕捉了这其中大多数想法。
|
||||
|
||||
我喜欢说你应该“陶醉在异步”。与其试图隐藏异步,不如接受异步,为异步而设计。当你看到像幂等性或不变性这样的技术时,你就认识到它们是拥抱宇宙本质的方法,而不仅仅是工具箱中的一个设计工具。
|
||||
|
||||
性能
|
||||
### 性能
|
||||
|
||||
我确信 Don Knuth 会对人们怎样误解他的名言“过早的优化是一切罪恶的根源”而感到震惊。事实上,性能,及性能持续超过60年的指数增长(或超过10年,取决于您是否愿意将晶体管,真空管和机电继电器的发展算入其中),为所有行业内的惊人创新和影响经济的“软件吃遍世界”的变化打下了基础。
|
||||
我确信 Don Knuth 会对人们怎样误解他的名言“过早的优化是一切罪恶的根源”而感到震惊。事实上,性能,及性能的持续超过 60 年的指数增长(或超过 10 年,取决于您是否愿意将晶体管,真空管和机电继电器的发展算入其中),为所有行业内的惊人创新和影响经济的“软件吃掉全世界”的变化打下了基础。
|
||||
|
||||
要认识到这种指数变化的一个关键是,虽然系统的所有组件正在经历指数变化,但这些指数是不同的。硬盘容量的增长速度与内存容量的增长速度不同,与 CPU 的增长速度不同,与内存 CPU 之间的延迟的性能改善速度也不用。即使性能发展的趋势是由相同的基础技术驱动的,增长的指数也会有分歧。[延迟的改进从根本上改善了带宽][7]。指数变化在近距离或者短期内看起来是线性的,但随着时间的推移可能是压倒性的。系统不同组件的性能的增长不同,会出现压倒性的变化,并迫使对设计决策定期进行重新评估。
|
||||
要认识到这种指数变化的一个关键是,虽然系统的所有组件正在经历指数级变化,但这些指数是不同的。硬盘容量的增长速度与内存容量的增长速度不同,与 CPU 的增长速度不同,与内存 CPU 之间的延迟的性能改善速度也不用。即使性能发展的趋势是由相同的基础技术驱动的,增长的指数也会有分歧。[延迟的改进从根本上改善了带宽][7]。指数变化在近距离或者短期内看起来是线性的,但随着时间的推移可能是压倒性的。系统不同组件的性能的增长不同,会出现压倒性的变化,并迫使对设计决策定期进行重新评估。
|
||||
|
||||
这样做的结果是,几年后,一度有意义的设计决定就不再有意义了。或者在某些情况下,二十年前有意义的方法又开始变成一个好的决定。现代内存映射的特点看起来更像是早期分时的进程切换,而不像分页那样。 (这样做有时会让我这样的老人说“这就是我们在 1975 年时用的方法”——忽略了这种方法在 40 年都没有意义,但现在又重新成为好的方法,因为两个组件之间的关系——可能是闪存和 NAND 而不是磁盘和核心内存——已经变得像以前一样了)。
|
||||
这样做的结果是,几年后,一度有意义的设计决策就不再有意义了。或者在某些情况下,二十年前有意义的方法又开始变成一个好的决策。现代内存映射的特点看起来更像是早期分时的进程切换,而不像分页那样。 (这样做有时会让我这样的老人说“这就是我们在 1975 年时用的方法”——忽略了这种方法在 40 年都没有意义,但现在又重新成为好的方法,因为两个组件之间的关系——可能是闪存和 NAND 而不是磁盘和核心内存——已经变得像以前一样了)。
|
||||
|
||||
当这些指数超越人自身的限制时,重要的转变就发生了。你能从 2 的 16 次方个字符(一个人可以在几个小时打这么多字)过渡到 2 的 3 次方个字符(远超出了一个人打字的范围)。你可以捕捉比人眼能感知的分辨率更高的数字图像。或者你可以将整个音乐专辑存在小巧的磁盘上,放在口袋里。或者你可以将数字化视频录制存储在硬盘上。再通过实时流式传输的能力,可以在一个地方集中存储一次,不需要在数千个本地硬盘上重复记录。
|
||||
当这些指数超越人自身的限制时,重要的转变就发生了。你能从 2 的 16 次方个字符(一个人可以在几个小时打这么多字)过渡到 2 的 32 次方个字符(远超出了一个人打字的范围)。你可以捕捉比人眼能感知的分辨率更高的数字图像。或者你可以将整个音乐专辑存在小巧的磁盘上,放在口袋里。或者你可以将数字化视频录制存储在硬盘上。再通过实时流式传输的能力,可以在一个地方集中存储一次,不需要在数千个本地硬盘上重复记录。
|
||||
|
||||
但有的东西仍然是根本的限制条件,那就是空间的三维和光速。我们又回到了爱因斯坦的宇宙。内存的分级结构将始终存在——它是物理定律的基础。稳定的存储和 IO,内存,计算和通信也都将一直存在。这些模块的相对容量,延迟和带宽将会改变,但是系统始终要考虑这些元素如何组合在一起,以及它们之间的平衡和折衷。Jim Gary 是这方面的大师。
|
||||
但有的东西仍然是根本的限制条件,那就是空间的三维和光速。我们又回到了爱因斯坦的宇宙。内存的分级结构将始终存在——它是物理定律的基础。稳定的存储和 IO、内存、计算和通信也都将一直存在。这些模块的相对容量,延迟和带宽将会改变,但是系统始终要考虑这些元素如何组合在一起,以及它们之间的平衡和折衷。Jim Gary 是这方面的大师。
|
||||
|
||||
空间和光速的根本限制造成的另一个后果是,性能分析主要是关于三件事:局部化 (locality),局部化,局部化。无论是将数据打包在磁盘上,管理处理器缓存的层次结构,还是将数据合并到通信数据包中,数据如何打包在一起,如何在一段时间内从局部获取数据,数据如何在组件之间传输数据是性能的基础。把重点放在减少管理数据的代码上,增加空间和时间上的局部性,是消除噪声的好办法。
|
||||
空间和光速的根本限制造成的另一个后果是,性能分析主要是关于三件事:<ruby>局部化<rt>locality</rt></ruby>、<ruby>局部化<rt>locality</rt></ruby>、<ruby>局部化<rt>locality</rt></ruby>。无论是将数据打包在磁盘上,管理处理器缓存的层次结构,还是将数据合并到通信数据包中,数据如何打包在一起,如何在一段时间内从局部获取数据,数据如何在组件之间传输数据是性能的基础。把重点放在减少管理数据的代码上,增加空间和时间上的局部性,是消除噪声的好办法。
|
||||
|
||||
Jon Devaan 曾经说过:“设计数据,而不是设计代码”。这也通常意味着当查看系统结构时,我不太关心代码如何交互——我想看看数据如何交互和流动。如果有人试图通过描述代码结构来解释一个系统,而不理解数据流的速率和数量,他们就不了解这个系统。
|
||||
|
||||
内存的层级结构也意味着我缓存将会一直存在——即使某些系统层正在试图隐藏它。缓存是根本的,但也是危险的。缓存试图利用代码的运行时行为,来改变系统中不同组件之间的交互模式。它们需要对运行时行为进行建模,即使模型填充缓存并使缓存失效,并测试缓存命中。如果模型由于行为改变而变差或变得不佳,缓存将无法按预期运行。一个简单的指导方针是,缓存必须被检测——由于应用程序行为的改变,事物不断变化的性质和组件之间性能的平衡,缓存的行为将随着时间的推移而退化。每一个老程序员都有缓存变糟的经历。
|
||||
内存的层级结构也意味着缓存将会一直存在——即使某些系统层正在试图隐藏它。缓存是根本的,但也是危险的。缓存试图利用代码的运行时行为,来改变系统中不同组件之间的交互模式。它们需要对运行时行为进行建模,即使模型填充缓存并使缓存失效,并测试缓存命中。如果模型由于行为改变而变差或变得不佳,缓存将无法按预期运行。一个简单的指导方针是,缓存必须被检测——由于应用程序行为的改变,事物不断变化的性质和组件之间性能的平衡,缓存的行为将随着时间的推移而退化。每一个老程序员都有缓存变糟的经历。
|
||||
|
||||
我很幸运,我的早期职业生涯是在互联网的发源地之一 BBN 度过的。 我们很自然地将将异步组件之间的通信视为系统连接的自然方式。流量控制和队列理论是通信系统的基础,更是任何异步系统运行的方式。流量控制本质上是资源管理(管理通道的容量),但资源管理是更根本的关注点。流量控制本质上也应该由端到端的应用负责,所以用端到端的方式思考异步系统是自然的。[缓冲区膨胀][8]的故事在这种情况下值得研究,因为它展示了当对端到端行为的动态性以及技术“改进”(路由器中更大的缓冲区)缺乏理解时,在整个网络基础设施中导致的长久的问题。
|
||||
|
||||
我发现“光速”的概念在分析任何系统时都非常有用。光速分析并不是从当前的性能开始分析,而是问“这个设计理论上能达到的最佳性能是多少?”真正传递的信息是什么,以什么样的速度变化?组件之间的底层延迟和带宽是多少?光速分析迫使设计师深入思考他们的方法能否达到性能目标,或者否需要重新考虑设计的基本方法。它也迫使人们更深入地了解性能在哪里损耗,以及损耗是由固有的,还是由于一些不当行为产生的。从构建的角度来看,它迫使系统设计人员了解其构建的模块的真实性能特征,而不是关注其他功能特性。
|
||||
我发现“<ruby>光速<rt>light speed</rt></ruby>”的概念在分析任何系统时都非常有用。光速分析并不是从当前的性能开始分析,而是问“这个设计理论上能达到的最佳性能是多少?”真正传递的信息是什么,以什么样的速度变化?组件之间的底层延迟和带宽是多少?光速分析迫使设计师深入思考他们的方法能否达到性能目标,或者否需要重新考虑设计的基本方法。它也迫使人们更深入地了解性能在哪里损耗,以及损耗是由固有的,还是由于一些不当行为产生的。从构建的角度来看,它迫使系统设计人员了解其构建的模块的真实性能特征,而不是关注其他功能特性。
|
||||
|
||||
我的职业生涯大多花费在构建图形应用程序上。用户坐在系统的一端,定义关键的常量和约束。人类的视觉和神经系统没有经历过指数性的变化。它们固有地受到限制,这意味着系统设计者可以利用(必须利用)这些限制,例如,通过虚拟化(限制底层数据模型需要映射到视图数据结构中的数量),或者通过将屏幕更新的速率限制到人类视觉系统的感知限制。
|
||||
|
||||
复杂性的本质
|
||||
### 复杂性的本质
|
||||
|
||||
我的整个职业生涯都在与复杂性做斗争。为什么系统和应用变得复杂呢?为什么在一个应用领域内进行开发并没有随着时间变得简单,而基础设施却没有变得更复杂,反而变得更强大了?事实上,管理复杂性的一个关键方法就是“走开”然后重新开始。通常新的工具或语言迫使我们从头开始,这意味着开发人员将工具的优点与从新开始的优点结合起来。从新开始是重要的。这并不是说新工具,新平台,或新语言可能不好,但我保证它们不能解决复杂性增长的问题。控制复杂性的最简单的方法就是用更少的程序员,建立一个更小的系统。
|
||||
|
||||
当然,很多情况下“走开”并不是一个选择——Office 建立在有巨大的价值的复杂的资源上。通过 OneNote, Office 从 Word 的复杂性上“走开”,从而在另一个维度上进行创新。Sway 是另一个例子, Office 决定从限制中跳出来,利用关键的环境变化,抓住机会从底层上采取全新的设计方案。我们有 Word,Excel,PowerPoint 这些应用,它们的数据结构非常有价值,我们并不能完全放弃这些数据结构,它们成为了开发中持续的显著的限制条件。
|
||||
当然,很多情况下“走开”并不是一个选择——Office 软件建立在有巨大的价值的复杂的资源上。通过 OneNote, Office 从 Word 的复杂性上“走开”,从而在另一个维度上进行创新。Sway 是另一个例子, Office 决定从限制中跳出来,利用关键的环境变化,抓住机会从底层上采取全新的设计方案。我们有 Word、Excel、PowerPoint 这些应用,它们的数据结构非常有价值,我们并不能完全放弃这些数据结构,它们成为了开发中持续的显著的限制条件。
|
||||
|
||||
我受到 Fred Brook 讨论软件开发中的意外和本质的文章[《没有银子弹》][9]的影响,他希望用两个趋势来尽可能地推动程序员的生产力:一是在选择自己开发还是购买时,更多地关注购买——这预示了开源社区和云架构的改变;二是从单纯的构建方法转型到更“有机”或者“生态”的增量开发方法。现代的读者可以认为是向敏捷开发和持续开发的转型。但那篇文章可是写于 1986 年!
|
||||
我受到 Fred Brook 讨论软件开发中的意外和本质的文章[《没有银弹》][9]的影响,他希望用两个趋势来尽可能地推动程序员的生产力:一是在选择自己开发还是购买时,更多地关注购买——这预示了开源社区和云架构的改变;二是从单纯的构建方法转型到更“有机”或者“生态”的增量开发方法。现代的读者可以认为是向敏捷开发和持续开发的转型。但那篇文章可是写于 1986 年!
|
||||
|
||||
我很欣赏 Stuart Kauffman 的在复杂性的基本性上的研究工作。Kauffman 从一个简单的布尔网络模型(“[NK 模型][10]”)开始建立起来,然后探索这个基本的数学结构在相互作用的分子,基因网络,生态系统,经济系统,计算机系统(以有限的方式)等系统中的应用,来理解紧急有序行为的数学基础及其与混沌行为的关系。在一个高度连接的系统中,你固有地有一个相互冲突的约束系统,使得它(在数学上)很难向前发展(这被看作是在崎岖景观上的优化问题)。控制这种复杂性的基本方法是将系统分成独立元素并限制元素之间的相互连接(实质上减少 NK 模型中的“N”和“K”)。当然对那些使用复杂隐藏,信息隐藏和数据抽象,并且使用松散异步耦合来限制组件之间的交互的技术的系统设计者来说,这是很自然的。
|
||||
|
||||
|
||||
我们一直面临的一个挑战是,我们想到的许多拓展系统的方法,都跨越了所有的方面。实时共同编辑是 Office 应用程序最近的一个非常具体的(也是最复杂的)例子。
|
||||
|
||||
我们的数据模型的复杂性往往等同于“能力”。设计用户体验的固有挑战是我们需要将有限的一组手势,映射到底层数据模型状态空间的转换。增加状态空间的维度不可避免地在用户手势中产生模糊性。这是“[纯数学][11]”,这意味着确保系统保持“易于使用”的最基本的方式常常是约束底层的数据模型。
|
||||
|
||||
管理
|
||||
### 管理
|
||||
|
||||
我从高中开始着手一些领导角色(学生会主席!),对承担更多的责任感到理所当然。同时,我一直为自己在每个管理阶段都坚持担任全职程序员而感到自豪。但 Office 的开发副总裁最终还是让我从事管理,离开了日常的编程工作。当我在去年离开那份工作时,我很享受重返编程——这是一个出奇地充满创造力的充实的活动(当修完“最后”的 bug 时,也许也会有一点令人沮丧)。
|
||||
我从高中开始担任一些领导角色(学生会主席!),对承担更多的责任感到理所当然。同时,我一直为自己在每个管理阶段都坚持担任全职程序员而感到自豪。但 Office 软件的开发副总裁最终还是让我从事管理,离开了日常的编程工作。当我在去年离开那份工作时,我很享受重返编程——这是一个出奇地充满创造力的充实的活动(当修完“最后”的 bug 时,也许也会有一点令人沮丧)。
|
||||
|
||||
尽管在我加入微软前已经做了十多年的“主管”,但是到了 1996 年我加入微软才真正了解到管理。微软强调“工程领导是技术领导”。这与我的观点一致,帮助我接受并承担更大的管理责任。
|
||||
|
||||
@@ -124,21 +118,19 @@ Jon Devaan 曾经说过:“设计数据,而不是设计代码”。这也通
|
||||
|
||||
我过去说我的工作是设计反馈回路。独立工程师,经理,行政人员,每一个项目的参与者都能通过分析记录的项目数据,推进项目,产出结果,了解自己在整个项目中扮演的角色。最终,透明化最终成为增强能力的一个很好的工具——管理者可以将更多的局部控制权给予那些最接近问题的人,因为他们对所取得的进展有信心。这样的话,合作自然就会出现。
|
||||
|
||||
Key to this is that the goal has actually been properly framed (including key resource constraints like ship schedule). Decision-making that needs to constantly flow up and down the management chain usually reflects poor framing of goals and constraints by management.
|
||||
|
||||
关键需要确定目标框架(包括关键资源的约束,如发布的时间表)。如果决策需要在管理链上下不断流动,那说明管理层对目标和约束的框架不好。
|
||||
|
||||
当我在 Beyond Software 工作时,我真正理解了一个项目拥有一个唯一领导的重要性。原来的项目经理离职了(后来从 FrontPage 雇佣了我)。我们四个主管在是否接任这个岗位上都有所犹豫,这不仅仅由于我们都不知道要在这家公司坚持多久。我们都技术高超,并且相处融洽,所以我们决定以同级的身份一起来领导这个项目。然而这槽糕透了。有一个显而易见的问题,我们没有相应的战略用来在原有的组织之间分配资源——这应当是管理者的首要职责之一!当你知道你是唯一的负责人时,你会有很深的责任感,但在这个例子中,这种责任感缺失了。我们没有真正的领导来负责统一目标和界定约束。
|
||||
当我在 Beyond Software 工作时,我真正理解了一个项目拥有一个唯一领导的重要性。原来的项目经理离职了(后来从 FrontPage 团队雇佣了我)。我们四个主管在是否接任这个岗位上都有所犹豫,这不仅仅由于我们都不知道要在这家公司坚持多久。我们都技术高超,并且相处融洽,所以我们决定以同级的身份一起来领导这个项目。然而这槽糕透了。有一个显而易见的问题,我们没有相应的战略用来在原有的组织之间分配资源——这应当是管理者的首要职责之一!当你知道你是唯一的负责人时,你会有很深的责任感,但在这个例子中,这种责任感缺失了。我们没有真正的领导来负责统一目标和界定约束。
|
||||
|
||||
我有清晰地记得,我第一次充分认识到*倾听*对一个领导者的重要性。那时我刚刚担任了 Word,OneNote,Publisher 和 Text Services 团队的开发经理。关于我们如何组织文本服务团队,我们有一个很大的争议,我走到了每个关键参与者身边,听他们想说的话,然后整合起来,写下了我所听到的一切。当我向其中一位主要参与者展示我写下的东西时,他的反应是“哇,你真的听了我想说的话”!作为一名管理人员,我所经历的所有最大的问题(例如,跨平台和转型持续工程)涉及到仔细倾听所有的参与者。倾听是一个积极的过程,它包括:尝试以别人的角度去理解,然后写出我学到的东西,并对其进行测试,以验证我的理解。当一个关键的艰难决定需要发生的时候,在最终决定前,每个人都知道他们的想法都已经被听到并理解(不论他们是否同意最后的决定)。
|
||||
我有清晰地记得,我第一次充分认识到*倾听*对一个领导者的重要性。那时我刚刚担任了 Word、OneNote、Publisher 和 Text Services 团队的开发经理。关于我们如何组织文本服务团队,我们有一个很大的争议,我走到了每个关键参与者身边,听他们想说的话,然后整合起来,写下了我所听到的一切。当我向其中一位主要参与者展示我写下的东西时,他的反应是“哇,你真的听了我想说的话”!作为一名管理人员,我所经历的所有最大的问题(例如,跨平台和转型持续工程)涉及到仔细倾听所有的参与者。倾听是一个积极的过程,它包括:尝试以别人的角度去理解,然后写出我学到的东西,并对其进行测试,以验证我的理解。当一个关键的艰难决定需要发生的时候,在最终决定前,每个人都知道他们的想法都已经被听到并理解(不论他们是否同意最后的决定)。
|
||||
|
||||
在 FrontPage 担任开发经理的工作,让我理解了在只有部分信息的情况下做决定的“操作困境”。你等待的时间越长,你就会有更多的信息做出决定。但是等待的时间越长,实际执行的灵活性就越低。在某个时候,你仅需要做出决定。
|
||||
在 FrontPage 团队担任开发经理的工作,让我理解了在只有部分信息的情况下做决定的“操作困境”。你等待的时间越长,你就会有更多的信息做出决定。但是等待的时间越长,实际执行的灵活性就越低。在某个时候,你仅需要做出决定。
|
||||
|
||||
设计一个组织涉及类似的两难情形。您希望增加资源领域,以便可以在更大的一组资源上应用一致的优先级划分框架。但资源领域越大,越难获得作出决定所需要的所有信息。组织设计就是要平衡这两个因素。软件复杂化,因为软件的特点可以在任意维度切入设计。Office 已经使用[共享团队][12]来解决这两个问题(优先次序和资源),让跨领域的团队能与需要产品的团队分享工作(增加资源)。
|
||||
设计一个组织涉及类似的两难情形。您希望增加资源领域,以便可以在更大的一组资源上应用一致的优先级划分框架。但资源领域越大,越难获得作出决定所需要的所有信息。组织设计就是要平衡这两个因素。软件复杂化,因为软件的特点可以在任意维度切入设计。Office 软件部门已经使用[共享团队][12]来解决这两个问题(优先次序和资源),让跨领域的团队能与需要产品的团队分享工作(增加资源)。
|
||||
|
||||
随着管理阶梯的提升,你会懂一个小秘密:你和你的新同事不会因为你现在承担更多的责任,就突然变得更聪明。这强调了整个组织比顶层领导者更聪明。赋予每个级别在一致框架下拥有自己的决定是实现这一目标的关键方法。听取并使自己对组织负责,阐明和解释决策背后的原因是另一个关键策略。令人惊讶的是,害怕做出一个愚蠢的决定可能是一个有用的激励因素,以确保你清楚地阐明你的推理,并确保你听取所有的信息。
|
||||
|
||||
结语
|
||||
### 结语
|
||||
|
||||
我离开大学寻找第一份工作时,面试官在最后一轮面试时问我对做“系统”和做“应用”哪一个更感兴趣。我当时并没有真正理解这个问题。在软件技术栈的每一个层面都会有趣的难题,我很高兴深入研究这些问题。保持学习。
|
||||
|
||||
@@ -146,9 +138,9 @@ Key to this is that the goal has actually been properly framed (including key re
|
||||
|
||||
via: https://hackernoon.com/education-of-a-programmer-aaecf2d35312
|
||||
|
||||
作者:[ Terry Crowley][a]
|
||||
作者:[Terry Crowley][a]
|
||||
译者:[explosic4](https://github.com/explosic4)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
@@ -1,46 +1,54 @@
|
||||
HeRM’s - 一个命令行食谱管理器
|
||||
HeRM's :一个命令行食谱管理器
|
||||
======
|
||||
|
||||

|
||||
|
||||
烹饪让爱变得可见,不是吗?确实!烹饪也许是你的热情或爱好或职业,我相信你会维护一份烹饪日记。保持写烹饪日记是改善烹饪习惯的一种方法。有很多方法可以记录食谱。你可以维护一份小日记/笔记或将配方的笔记存储在智能手机中,或将它们保存在计算机中文档中。这有很多选择。今天,我介绍 **HeRM 's**,一个基于 Haskell 的命令行食谱管理器,能为你的美食食谱做笔记。使用 Herm's,你可以添加、查看、编辑和删除食物配方,甚至可以制作购物清单。这些全部来自你的终端!它是免费的,并使用 Haskell 语言编写的开源程序。源代码在 GitHub 中免费提供,因此你可以 fork 它,添加更多功能或改进它。
|
||||
烹饪让爱变得可见,不是吗?确实!烹饪也许是你的热情或爱好或职业,我相信你会维护一份烹饪日记。保持写烹饪日记是改善烹饪习惯的一种方法。有很多方法可以记录食谱。你可以维护一份小日记/笔记或将配方的笔记存储在智能手机中,或将它们保存在计算机中文档中。这有很多选择。今天,我介绍 **HeRM's**,这是一个基于 Haskell 的命令行食谱管理器,能为你的美食食谱做笔记。使用 Herm's,你可以添加、查看、编辑和删除食物配方,甚至可以制作购物清单。这些全部来自你的终端!它是免费的,是使用 Haskell 语言编写的开源程序。源代码在 GitHub 中免费提供,因此你可以复刻它,添加更多功能或改进它。
|
||||
|
||||
### HeRM's - 一个命令食谱管理器
|
||||
|
||||
#### **安装 HeRM 's**
|
||||
#### 安装 HeRM's
|
||||
|
||||
由于它是使用 Haskell 编写的,因此我们需要首先安装 Cabal。 Cabal 是一个用于下载和编译用 Haskell 语言编写的软件的命令行程序。Cabal 存在于大多数 Linux 发行版的核心软件库中,因此你可以使用发行版的默认软件包管理器来安装它。
|
||||
|
||||
例如,你可以使用以下命令在 Arch Linux 及其变体(如 Antergos、Manjaro Linux)中安装 cabal:
|
||||
|
||||
```
|
||||
sudo pacman -S cabal-install
|
||||
```
|
||||
|
||||
在 Debian、Ubuntu 上:
|
||||
|
||||
```
|
||||
sudo apt-get install cabal-install
|
||||
```
|
||||
|
||||
安装 Cabal 后,确保你已经添加了 PATH。为此,请编辑你的 **~/.bashrc** :
|
||||
安装 Cabal 后,确保你已经添加了 `PATH`。为此,请编辑你的 `~/.bashrc`:
|
||||
|
||||
```
|
||||
vi ~/.bashrc
|
||||
```
|
||||
|
||||
添加下面这行:
|
||||
|
||||
```
|
||||
PATH=$PATH:~/.cabal/bin
|
||||
```
|
||||
|
||||
按 **:wq** 保存并退出文件。然后,运行以下命令更新所做的更改。
|
||||
按 `:wq` 保存并退出文件。然后,运行以下命令更新所做的更改。
|
||||
|
||||
```
|
||||
source ~/.bashrc
|
||||
```
|
||||
|
||||
安装 cabal 后,运行以下命令安装 herms:
|
||||
安装 cabal 后,运行以下命令安装 `herms`:
|
||||
|
||||
```
|
||||
cabal install herms
|
||||
```
|
||||
|
||||
喝一杯咖啡!这将需要一段时间。几分钟后,你会看到一个输出,如下所示。
|
||||
|
||||
```
|
||||
[...]
|
||||
Linking dist/build/herms/herms ...
|
||||
@@ -50,71 +58,77 @@ Installed herms-1.8.1.2
|
||||
|
||||
恭喜! Herms 已经安装完成。
|
||||
|
||||
#### **添加食谱**
|
||||
#### 添加食谱
|
||||
|
||||
让我们添加一个食谱,例如 **Dosa**。对于那些想知道的,Dosa 是一种受欢迎的南印度食物,配以 **sambar** 和**酸辣酱**。这是一种健康的,可以说是最美味的食物。它不含添加的糖或饱和脂肪。制作一个也很容易。有几种不同的 Dosas,在我们家中最常见的是 Plain Dosa。
|
||||
让我们添加一个食谱,例如 Dosa。对于那些想知道的,Dosa 是一种受欢迎的南印度食物,配以 sambar(LCTT 译注:扁豆和酸豆炖菜,像咖喱汤) 和**酸辣酱**。这是一种健康的,可以说是最美味的食物。它不含添加的糖或饱和脂肪。制作一个也很容易。有几种不同的 Dosas,在我们家中最常见的是 Plain Dosa。
|
||||
|
||||
要添加食谱,请输入:
|
||||
|
||||
```
|
||||
herms add
|
||||
```
|
||||
|
||||
你会看到一个如下所示的屏幕。开始输入食谱的详细信息。
|
||||
|
||||
[![][1]][2]
|
||||
![][2]
|
||||
|
||||
要变换字段,请使用以下键盘快捷键:
|
||||
|
||||
* **Tab / Shift+Tab** - 下一个/前一个字段
|
||||
* **Ctrl + <箭头键>** - 导航字段
|
||||
* **[Meta 或者 Alt] + <h-j-k-l>** - 导航字段
|
||||
* **Esc** - 保存或取消。
|
||||
* `Tab` / `Shift+Tab` - 下一个/前一个字段
|
||||
* `Ctrl + <箭头键>` - 导航字段
|
||||
* `[Meta 或者 Alt] + <h-j-k-l>` - 导航字段
|
||||
* `Esc` - 保存或取消。
|
||||
|
||||
|
||||
|
||||
添加完配方的详细信息后,按下 ESC 键并点击 Y 保存。同样,你可以根据需要添加尽可能多的食谱。
|
||||
添加完配方的详细信息后,按下 `ESC` 键并点击 `Y` 保存。同样,你可以根据需要添加尽可能多的食谱。
|
||||
|
||||
要列出添加的食谱,输入:
|
||||
|
||||
```
|
||||
herms list
|
||||
```
|
||||
|
||||
[![][1]][3]
|
||||
![][3]
|
||||
|
||||
要查看上面列出的任何食谱的详细信息,请使用下面的相应编号。
|
||||
|
||||
```
|
||||
herms view 1
|
||||
```
|
||||
|
||||
[![][1]][4]
|
||||
![][4]
|
||||
|
||||
要编辑任何食谱,使用:
|
||||
|
||||
```
|
||||
herms edit 1
|
||||
```
|
||||
|
||||
完成更改后,按下 ESC 键。系统会询问你是否要保存。你只需选择适当的选项。
|
||||
完成更改后,按下 `ESC` 键。系统会询问你是否要保存。你只需选择适当的选项。
|
||||
|
||||
[![][1]][5]
|
||||
![][5]
|
||||
|
||||
要删除食谱,命令是:
|
||||
|
||||
```
|
||||
herms remove 1
|
||||
```
|
||||
|
||||
要为指定食谱生成购物清单,运行:
|
||||
|
||||
```
|
||||
herms shopping 1
|
||||
```
|
||||
|
||||
[![][1]][6]
|
||||
![][6]
|
||||
|
||||
要获得帮助,运行:
|
||||
|
||||
```
|
||||
herms -h
|
||||
```
|
||||
|
||||
当你下次听到你的同事、朋友或其他地方谈到好的食谱时,只需打开 Herms,并快速记下,并将它们分享给你的配偶。她会很高兴!
|
||||
当你下次听到你的同事、朋友或其他地方谈到好的食谱时,只需打开 Herm's,并快速记下,并将它们分享给你的配偶。她会很高兴!
|
||||
|
||||
今天就是这些。还有更好的东西。敬请关注!
|
||||
|
||||
@@ -126,16 +140,16 @@ herms -h
|
||||
|
||||
via: https://www.ostechnix.com/herms-commandline-food-recipes-manager/
|
||||
|
||||
作者:[][a]
|
||||
作者:[SK][a]
|
||||
译者:[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/) 荣誉推出
|
||||
|
||||
[a]:https://www.ostechnix.com
|
||||
[1]:data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7
|
||||
[2]:http://www.ostechnix.com/wp-content/uploads/2017/12/Make-Dosa-1.png ()
|
||||
[3]:http://www.ostechnix.com/wp-content/uploads/2017/12/herms-1-1.png ()
|
||||
[4]:http://www.ostechnix.com/wp-content/uploads/2017/12/herms-2.png ()
|
||||
[5]:http://www.ostechnix.com/wp-content/uploads/2017/12/herms-3.png ()
|
||||
[6]:http://www.ostechnix.com/wp-content/uploads/2017/12/herms-4.png ()
|
||||
[2]:http://www.ostechnix.com/wp-content/uploads/2017/12/Make-Dosa-1.png
|
||||
[3]:http://www.ostechnix.com/wp-content/uploads/2017/12/herms-1-1.png
|
||||
[4]:http://www.ostechnix.com/wp-content/uploads/2017/12/herms-2.png
|
||||
[5]:http://www.ostechnix.com/wp-content/uploads/2017/12/herms-3.png
|
||||
[6]:http://www.ostechnix.com/wp-content/uploads/2017/12/herms-4.png
|
||||
134
published/20180405 Getting started with Vagrant.md
Normal file
134
published/20180405 Getting started with Vagrant.md
Normal file
@@ -0,0 +1,134 @@
|
||||
开始 Vagrant 之旅
|
||||
=====
|
||||
|
||||
> 用管理虚拟机和容器的工具 Vagrant 清理你的开发环境和依赖。
|
||||
|
||||

|
||||
|
||||
如果你和我一样,你可能在某一个地方有一个“沙盒”,你可以在那里进行你正在做的任何项目。随着时间的推移,沙盒会变得杂乱无章,充斥着各种想法、工具链元素、你不使用的代码模块,以及其他你不需要的东西。当你完成某件事情时,这会使你的部署变得复杂,因为你可能不确定项目的实际依赖关系 —— 随着时间推移你在沙盒中已经有了一些工具,但是你忘了必须安装它。你需要一个干净的环境,将所有的依赖关系放在一个地方,以便以后更方便。
|
||||
|
||||
或者你可能工作在 DevOps 中,你所服务的开发人员用模糊的依赖关系来编写代码,这使得测试变得更加困难。你需要一种方法来获得一个干净的盒子,将代码放入其中,并通过它运行代码,而且你希望这些环境是一次性的和可重复的。
|
||||
|
||||
那么选择 [Vagrant][1] 吧。由 HashiCorp 在 [MIT 许可证][2]下创建,Vagrant 可充当 VirtualBox、Microsoft Hyper-V 或 Docker 容器的包装器和前端,并且可以通过[许多其他供应商][3]的插件进行扩展。你可以配置 Vagrant 以提供可重复的、干净的环境,并且已安装需要的基础架构。配置脚本是可移植的,因此,如果你的仓库和 Vagrant 配置脚本位于基于云存储上,那么你只需要很少的限制就可以启动并在多台机器机器上工作。让我们来看一看。
|
||||
|
||||
### 安装
|
||||
|
||||
对于本次安装,我的环境是 Linux Mint 桌面,版本是 18.3 Cinnamon 64 位,在其他大多数 Debian 派生系统上安装非常类似。在大多数发行版中,对于基于 RPM 的系统也有类似的安装程序。Vagrant 的[安装页面][4]为 Debian、 Windows、 CentOS、 MacOS 和 Arch Linux 都提供下载,但是我在我的软件包管理器中找到了它,所以我在那进行了安装。
|
||||
|
||||
最简单的安装使用了 VirtualBox 作为虚拟化提供者,所以我需要安装它:
|
||||
|
||||
```
|
||||
sudo apt-get install virtualbox vagrant
|
||||
```
|
||||
|
||||
安装程序将会获取依赖项 —— 主要是 Ruby 的一些东西,安装它们。
|
||||
|
||||
### 建立一个项目
|
||||
|
||||
在设置你的项目之前,你需要了解一些你想要运行它的环境。你可以在 [Vagrant Boxes 仓库][5]中找到为许多虚拟化供应商提供的大量预配置的<ruby>系统<rt>box</rt></ruby>。许多会预先配置一些你可能需要的核心基础设置,比如 PHP、 MySQL 和 Apache,但是对于本次测试,我将安装一个 Debian 8 64 位 “Jessie” 裸机沙盒并手动安装一些东西,这样你就可以看到具体过程了。
|
||||
|
||||
```
|
||||
mkdir ~/myproject
|
||||
cd ~/myproject
|
||||
vagrant init debian/contrib-jessie64
|
||||
vagrant up
|
||||
```
|
||||
|
||||
最后一条命令将根据需要从仓库中获取或更新 VirtualBox 镜像,然后运行启动器,你的系统上会出现一个运行的系统!下次启动这个项目时,除非镜像已经在仓库中更新,否则不会花费太长时间。
|
||||
|
||||
要访问该沙盒,只需要输入 `vagrant ssh`,你将进入虚拟机的全功能 SSH 会话中,你将会是 `vagrant` 用户,但也是 `sudo` 组的成员,所以你可以切换到 root,并在这里做你想做的任何事情。
|
||||
|
||||
你会在沙盒中看到一个名为 `/vagrant` 目录,对这个目录小心点,因为它与你主机上的 `~/myproject` 文件夹保持同步。在虚拟机 `/vagrant` 下建立一个文件它会立即复制到主机上,反之亦然。注意,有些沙盒并没有安装 VirtualBox 的附加功能,所以拷贝只能在启动时才起作用。有一些用于手动同步的命令行工具,这可能是测试环境中非常有用的特性。我倾向于坚持使用那些有附加功能的沙盒,所以这个目录可以正常工作,不必考虑它。
|
||||
|
||||
这个方案的好处很快显现出来了: 如果你在主机上有一个代码编辑工具链,并处于某种原因不希望它出现在虚拟机上,那么这不是问题 —— 在主机上进行编辑,虚拟机会立刻更改。快速更改虚拟机,它也将其同步到主机上的“官方”副本
|
||||
。
|
||||
|
||||
让我们关闭这个系统,这样我们就可以在这个系统里提供一些我们需要的东西:
|
||||
|
||||
```
|
||||
vagrant halt
|
||||
```
|
||||
|
||||
### 在虚拟机上安装额外的软件
|
||||
|
||||
对于这个例子,我将使用 [Apache][6]、 [PostgreSQL][7] 和 Perl 的 [Dancer][8] web 框架进行项目开发。我将修改Vagrant 配置脚本,以便我需要的东西已经安装。 为了使之稍后更容易保持更新,我将在项目根目录下创建一个脚本`~/myproject/Vagrantfile`:
|
||||
|
||||
```
|
||||
$provision_script = <<SCRIPT
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
apt-get update
|
||||
apt-get -y install \
|
||||
apache2 \
|
||||
postgresql-client-9.4 \
|
||||
postgresql-9.4 \
|
||||
libdbd-pg-perl \
|
||||
libapache2-mod-fastcgi \
|
||||
libdata-validate-email-perl \
|
||||
libexception-class-perl \
|
||||
libexception-class-trycatch-perl \
|
||||
libtemplate-perl \
|
||||
libtemplate-plugin-json-escape-perl \
|
||||
libdbix-class-perl \
|
||||
libyaml-tiny-perl \
|
||||
libcrypt-saltedhash-perl \
|
||||
libdancer2-perl \
|
||||
libtemplate-plugin-gravatar-perl \
|
||||
libtext-csv-perl \
|
||||
libstring-tokenizer-perl \
|
||||
cpanminus
|
||||
cpanm -f -n \
|
||||
Dancer2::Session::Cookie \
|
||||
Dancer2::Plugin::DBIC \
|
||||
Dancer2::Plugin::Auth::Extensible::Provider::DBIC \
|
||||
Dancer2::Plugin::Locale \
|
||||
Dancer2::Plugin::Growler
|
||||
sudo a2enmod rewrite fastcgi
|
||||
sudo apache2ctl restart
|
||||
SCRIPT
|
||||
```
|
||||
|
||||
在 Vagrantfile 结尾附近,你会发现一行 `config.vm.provision` 变量,正如你在示例中看到的那样,你可以在此处以内联方式进行操作,只需通过取消注释以下行:
|
||||
|
||||
```
|
||||
# config.vm.provision "shell", inline: <<-SHELL
|
||||
# sudo apt-get update
|
||||
# sudo apt-get install -y apache2
|
||||
# SHELL
|
||||
```
|
||||
|
||||
相反,将那四行替换为使用你在文件顶部定义为变量的配置脚本:
|
||||
|
||||
```
|
||||
config.vm.provision "shell", inline: $provision_script
|
||||
```
|
||||
|
||||
你可能还希望将转发的端口设置为从主机访问虚拟机上的 Apache。寻找包含 `forwarded_port` 的行并取消注释它。如果你愿意,也可以将端口从 8080 更改为其他内容。我通常使用端口 5000,并在我的浏览器浏览 http://localhost:5000 就可以访问我虚拟机上的 Apache 服务器。
|
||||
|
||||
这里有一个设置提示:如果你的仓库位于云存储上,为了在多台机器上使用 Vagrant,你可能希望将不同机器上的 `VAGRANT_HOME` 环境变量设置为不同的东西。以 VirtualBox 的工作方式,你需要分别为这些系统存储状态信息,确保你的版本控制系统忽略了用于此的目录 —— 我将 `.vagrant.d*` 添加到仓库的 `.gitignore` 文件中。不过,我确实让 Vagrantfile 成为仓库的一部分!
|
||||
|
||||
### 好了!
|
||||
|
||||
我输入 `vagrant up`,我准备开始写代码了。一旦你做了一两次,你可能会想到你可以循环利用很多的 Vagrantfile 模板文件(就像我刚刚那样),这就是 Vagrant 的优势之一。你可以更快地完成实际的编码工作,并将很少的时间花在基础设施上!
|
||||
|
||||
你可以使用 Vagrant 做更多事情。配置工具存在于许多工具链中,因此,无论你需要复制什么环境,它都是快速而简单的。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/18/4/getting-started-vagrant
|
||||
|
||||
作者:[Ruth Holloway][a]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[MjSeven](https://github.com/MjSeven)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://opensource.com/users/druthb
|
||||
[1]:https://vagrantup.com
|
||||
[2]:https://opensource.org/licenses/MIT
|
||||
[3]:https://github.com/hashicorp/vagrant/wiki/Available-Vagrant-Plugins#providers
|
||||
[4]:https://www.vagrantup.com/downloads.html
|
||||
[5]:https://app.vagrantup.com/boxes/search
|
||||
[6]:https://httpd.apache.org/
|
||||
[7]:https://postgresql.org
|
||||
[8]:https://perldancer.org
|
||||
@@ -1,3 +1,6 @@
|
||||
Translating by MjSeven
|
||||
|
||||
|
||||
How to Install and Optimize Apache on Ubuntu
|
||||
======
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
translated by hopefully2333
|
||||
|
||||
Using machine learning to color cartoons
|
||||
======
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
KevinSJ Translating
|
||||
A Beginners Guide To Cron Jobs
|
||||
======
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
translating---geeekpi
|
||||
|
||||
Analyzing Ansible runs using ARA
|
||||
======
|
||||
|
||||
|
||||
@@ -1,126 +1,118 @@
|
||||
Translating KevinSJ -- 05142018
|
||||
How To Display Images In The Terminal
|
||||
如何在终端中显示图片
|
||||
======
|
||||
|
||||

|
||||
There are plenty of GUI picture viewers available for Linux. But I haven’t heard or used any applications which displays pictures in the Terminal itself. Luckily, I have just found a CLI image viewer named **FIM** that can be used to display images images in Terminal. The FIM utility draw my attention, because it is very lightweight compared to most GUI picture viewer applications. Without further ado, lets us go ahead and see what it is capable of.
|
||||
Linux 上用许多 GUI 图片浏览器。但我尚未听说或使用过任何在终端中显示图片的应用程序。幸运的是,我刚刚发现了一个可用于在终端中显示图像的名叫 ** FIM ** 的图像查看器。FIM 引起了我的注意,是因为与大多数 GUI 图片浏览器相比,它非常轻巧。毫不迟疑,让我们来看看它能做什么。
|
||||
|
||||
### Display Images In the Terminal Using FIM
|
||||
###使用FIM在终端中显示图像
|
||||
|
||||
**FIM** stands for **F** bi **IM** proved. For those who don’t know, **Fbi** is a linux **f** rame **b** uffer **i** mageviewer. It uses the system’s framebuffer to display images directly from the command line. By default, it displays bmp, gif, jpeg, PhotoCD, png, ppm, tiff, and xwd from the Terminal itself. For other formats, it will try to use ImageMagick’s convert.
|
||||
**FIM** stands for **F**bi **IM**proved. 对于那些不知道的人,**Fbi**是指 linux 中的 **f**rame **b**uffer **i**mageviewer。它使用系统的帧缓冲器直接从命令行显示图像。默认情况下,它能用终端显示bmp,gif,jpeg,PhotoCD,png,ppm,tiff 和 xwd。对于其他格式,它会尝试使用 ImageMagick 的转换。
|
||||
|
||||
FIM is based on Fbi and it is a highly customizable and scriptable image viewer targeted at the users who are comfortable with software like the Vim text editor or the Mutt mail user agent. It displays the images in full screen and the images can be controlled (such as resize, flip, zoom) using keyboard shortcuts. Unlike fbi, the FIM utility is universal: it can open many file formats and it can display pictures in the following video modes:
|
||||
FIM 基于 Fbi,它是一款高度可高度定制及脚本化的图像浏览器,非常适合使用 Vim 文本编辑器或 Mutt 等软件的用户。它会以全屏显示图像,并可通过键盘快捷键控制(如调整大小,翻转,缩放)。与fbi不同的是,FIM 是通用的:它可以打开许多文件格式,并且可以在以下视频模式下显示图片:
|
||||
|
||||
* Graphically, with the Linux framebuffer device.
|
||||
* Graphically, under X/Xorg, using the SDL library.
|
||||
* Graphically, under X/Xorg, using the Imlib2 library.
|
||||
* Rendered as ASCII Art in any textual console, using the AAlib library.
|
||||
*使用 Linux framebuffer 设备,以图形方式呈现
|
||||
*在 X / Xorg 下,使用 SDL 库。以图形方式呈现
|
||||
*在 X / Xorg 下,使用 Imlib2 库。以图形方式呈现。
|
||||
*在任何文本控制台中使用 AAlib 库呈现为 ASCII 字符画 。
|
||||
|
||||
|
||||
|
||||
FIM is completely free and open source.
|
||||
FIM是完全免费且开源的。
|
||||
|
||||
### Install FIM
|
||||
###安装FIM
|
||||
|
||||
基于 DEB 的系统,如 Ubuntu,Linux Mint, 可从默认的仓库中获取 FIM 图像查看器。因此,你可以使用如下命令安装fbi:
|
||||
|
||||
The FIM image viewer is available in the default repositories of DEB-based systems such as Ubuntu, Linux Mint. So, you can install fbi using command:
|
||||
```
|
||||
$ sudo apt-get install fim
|
||||
|
||||
```
|
||||
|
||||
If it is not available in the default repositories of your Linux distribution, you can download, compile and install from source as shown below.
|
||||
如果它在你使用的 Linux 发行版的仓库中不包含 FIM,则可以下载源代码进行编译和安装,如下所示。
|
||||
```
|
||||
wget http://download.savannah.nongnu.org/releases/fbi-improved/fim-0.6-trunk.tar.gz
|
||||
wget http://download.savannah.nongnu.org/releases/fbi-improved/fim-0.6-trunk.tar.gz.sig
|
||||
gpg --search 'dezperado autistici org'
|
||||
# import the key from a trusted keyserver by following on screen instructions
|
||||
#按照屏幕上的说明,从密钥服务器导入密钥
|
||||
gpg --verify fim-0.6-trunk.tar.gz.sig
|
||||
|
||||
tar xzf fim-0.6-trunk.tar.gz
|
||||
cd fim-0.6-trunk
|
||||
./configure --help=short
|
||||
# read the ./configure --help=short output: you can give options to ./configure
|
||||
#阅读./configure --help = short的输出:你可以在 ./configure 中添加选项
|
||||
./configure
|
||||
make
|
||||
su -c "make install"
|
||||
|
||||
su -c“make install”
|
||||
```
|
||||
|
||||
### FIM Usage
|
||||
### FIM用法
|
||||
|
||||
Once installed, you can display an image with “auto zoom” option using command:
|
||||
安装完成后,您可以使用以下命令以“自动缩放”显示的图像:
|
||||
```
|
||||
$ fim -a dog.jpg
|
||||
|
||||
```
|
||||
|
||||
Here is the sample output from my Ubuntu box.
|
||||
这里是我的 Ubuntu 主机的示例输出。
|
||||
|
||||
![][1]
|
||||
|
||||
As you can see in the above screenshot, FIM didn’t use any external GUI picture viewers. Instead, it uses our system’s framebuffer to display the image.
|
||||
正如你在上面的屏幕截图中看到的,FIM 没有使用任何外部 GUI 图片浏览器。相反,它使用我们系统的帧缓冲器来显示图像。
|
||||
|
||||
If you have multiple .jpg files in the current directory, you could use wildcard to open all of them as shown below.
|
||||
如果当前目录中有多个.jpg文件,可以使用通配符打开所有文件,如下所示。
|
||||
```
|
||||
$ fim -a *.jpg
|
||||
|
||||
$ fim -a * .jpg
|
||||
```
|
||||
|
||||
To open all images in a directory, for example **Pictures** , run:
|
||||
要打开目录中的所有图像,例如 **Pictures**,请运行:
|
||||
```
|
||||
$ fim Pictures/
|
||||
|
||||
```
|
||||
|
||||
We can also open the images recursively in a folder and its sub-folder and then sorting the list like below.
|
||||
我们也可以在文件夹及其子文件夹中递归地打开图像,然后像下面那样对列表进行排序。
|
||||
```
|
||||
$ fim -R Pictures/ --sort
|
||||
|
||||
```
|
||||
|
||||
To render the image in ASCII format, you can use **-t** flag.
|
||||
要以 ASCII 格式渲染图像,可以使用 **-t** 标志。
|
||||
```
|
||||
$ fim -t dog.jpg
|
||||
|
||||
```
|
||||
|
||||
To quit Fim, press **ESC** or **q**.
|
||||
要退出 Fim,请按 **ESC** 或 **q**。
|
||||
|
||||
**Keyboard shortcuts**
|
||||
**键盘快捷键**
|
||||
|
||||
You can use various keyboard shortcuts to manage the images. For example, to load next image and previous images, press PgUp/PgDown keys. Ton Zoom in or out, use +/- keys. Here is the common keys used to control images in FIM.
|
||||
您可以使用各种键盘快捷键来管理图像。例如,要加载下一张图像和之前的图像,请按下 PgUp / PgDown 键。成倍放大或缩小,请使用 +/- 键。以下是用于在FIM中控制图像的常用按键。
|
||||
|
||||
* **PageUp/Down** : Prev/Next image
|
||||
* **+/-** : Zoom in/out
|
||||
* **a** : Autoscale
|
||||
* **w** : Fit to width
|
||||
* **h** : Fit to height
|
||||
* **j/k** : Pan down/up
|
||||
* **f/m** : flip/mirror
|
||||
* **r/R** : Rotate (Clock wise and ant-clock wise)
|
||||
* **ESC/q** : Quit
|
||||
* **PageUp/Down**:上一张/下一张图片
|
||||
* **+/-**:放大/缩小
|
||||
* **a**:自动缩放
|
||||
* **w**:自适应宽度
|
||||
* **h**:自适应高度
|
||||
* **j/k**:平移/向上
|
||||
* **f/m**:翻转/镜像
|
||||
* **r/R**:旋转(顺时针/逆时针)
|
||||
* **ESC/q**:退出
|
||||
|
||||
|
||||
|
||||
For complete details, refer man pages.
|
||||
有关完整详细信息,请参阅手册页。
|
||||
```
|
||||
$ man fim
|
||||
|
||||
```
|
||||
|
||||
And, that’s all for now. Hope this helps. More good stuffs to come. Stay tuned!
|
||||
那么,就是这样。希望这对你有所帮助。后续还会介绍更多的优秀工具。敬请关注!
|
||||
|
||||
Cheers!
|
||||
干杯!
|
||||
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-------------------------------------------------- ------------------------------
|
||||
|
||||
via: https://www.ostechnix.com/how-to-display-images-in-the-terminal/
|
||||
|
||||
作者:[SK][a]
|
||||
作者:[SK] [A]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
译者:[译者KevinSJ](https://github.com/KevinSJ)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
translating---geekpi
|
||||
|
||||
3 useful things you can do with the IP tool in Linux
|
||||
======
|
||||
|
||||

|
||||
|
||||
It has been more than a decade since the `ifconfig` command has been deprecated on Linux in favor of the `iproute2` project, which contains the magical tool `ip`. Many online tutorial resources still refer to old command-line tools like `ifconfig`, `route`, and `netstat`. The goal of this tutorial is to share some of the simple networking-related things you can do easily using the `ip` tool instead.
|
||||
|
||||
### Find your IP address
|
||||
```
|
||||
[dneary@host]$ ip addr show
|
||||
|
||||
[snip]
|
||||
|
||||
44: wlp4s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
|
||||
|
||||
link/ether 5c:e0:c5:c7:f0:f1 brd ff:ff:ff:ff:ff:ff
|
||||
|
||||
inet 10.16.196.113/23 brd 10.16.197.255 scope global dynamic wlp4s0
|
||||
|
||||
valid_lft 74830sec preferred_lft 74830sec
|
||||
|
||||
inet6 fe80::5ee0:c5ff:fec7:f0f1/64 scope link
|
||||
|
||||
valid_lft forever preferred_lft forever
|
||||
|
||||
```
|
||||
|
||||
`ip addr show` will show you a lot of information about all of your network link devices. In this case, my wireless Ethernet card (wlp4s0) is the IPv4 address (the `inet` field) `10.16.196.113/23`. The `/23` means that there are 23 bits of the 32 bits in the IP address, which will be shared by all of the IP addresses in this subnet. IP addresses in the subnet will range from `10.16.196.0 to 10.16.197.254`. The broadcast address for the subnet (the `brd` field after the IP address) `10.16.197.255` is reserved for broadcast traffic to all hosts on the subnet.
|
||||
|
||||
We can show only the information about a single device using `ip addr show dev wlp4s0`, for example.
|
||||
|
||||
### Display your routing table
|
||||
```
|
||||
[dneary@host]$ ip route list
|
||||
|
||||
default via 10.16.197.254 dev wlp4s0 proto static metric 600
|
||||
|
||||
10.16.196.0/23 dev wlp4s0 proto kernel scope link src 10.16.196.113 metric 601
|
||||
|
||||
192.168.122.0/24 dev virbr0 proto kernel scope link src 192.168.122.1 linkdown
|
||||
|
||||
```
|
||||
|
||||
The routing table is the local host's way of helping network traffic figure out where to go. It contains a set of signposts, sending traffic to a specific interface, and a specific next waypoint on its journey.
|
||||
|
||||
If you run any virtual machines or containers, these will get their own IP addresses and subnets, which can make these routing tables quite complicated, but in a single host, there are typically two instructions. For local traffic, send it out onto the local Ethernet, and the network switches will figure out (using a protocol called ARP) which host owns the destination IP address, and thus where the traffic should be sent. For traffic to the internet, send it to the local gateway node, which will have a better idea how to get to the destination.
|
||||
|
||||
In the situation above, the first line represents the external gateway for external traffic, the second line is for local traffic, and the third is reserved for a virtual bridge for VMs running on the host, but this link is not currently active.
|
||||
|
||||
### Monitor your network configuration
|
||||
```
|
||||
[dneary@host]$ ip monitor all
|
||||
|
||||
[dneary@host]$ ip -s link list wlp4s0
|
||||
|
||||
```
|
||||
|
||||
The `ip monitor` command can be used to monitor changes in routing tables, network addressing on network interfaces, or changes in ARP tables on the local host. This command can be particularly useful in debugging network issues related to containers and networking, when two VMs should be able to communicate with each other but cannot.
|
||||
|
||||
`all`, `ip monitor` will report all changes, prefixed with one of `[LINK]` (network interface changes), `[ROUTE]` (changes to a routing table), `[ADDR]` (IP address changes), or `[NEIGH]` (nothing to do with horses—changes related to ARP addresses of neighbors).
|
||||
|
||||
When used withwill report all changes, prefixed with one of(network interface changes),(changes to a routing table),(IP address changes), or(nothing to do with horses—changes related to ARP addresses of neighbors).
|
||||
|
||||
You can also monitor changes on specific objects (for example, a specific routing table or an IP address).
|
||||
|
||||
Another useful option that works with many commands is `ip -s`, which gives some statistics. Adding a second `-s` option adds even more statistics. `ip -s link list wlp4s0` above will give lots of information about packets received and transmitted, with the number of packets dropped, errors detected, and so on.
|
||||
|
||||
### Handy tip: Shorten your commands
|
||||
|
||||
In general, for the `ip` tool, you need to include only enough letters to uniquely identify what you want to do. Instead of `ip monitor`, you can use `ip mon`. Instead of `ip addr list`, you can use `ip a l`, and you can use `ip r` in place of `ip route`. `Ip link list` can be shorted to `ip l ls`. To read about the many options you can use to change the behavior of a command, visit the [ip manpage][1].
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/18/5/useful-things-you-can-do-with-IP-tool-Linux
|
||||
|
||||
作者:[Dave Neary][a]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[译者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/dneary
|
||||
[1]:https://www.systutorials.com/docs/linux/man/8-ip-route/
|
||||
@@ -1,166 +0,0 @@
|
||||
开始 Vagrant 之旅
|
||||
=====
|
||||
|
||||

|
||||
如果你和我一样,你可能在某一个地方有一个“沙盒”,你可以在那里进行你正在做的任何项目。随着时间的推移,沙箱会变得杂乱无章,充斥着各种想法,工具链元素,你不使用的代码模块,以及其他你不需要的东西。当你完成某件事情时,这会使你的部署变得复杂,因为你可能不确定项目的实际依赖关系 - 随着时间推移你在沙盒中已经有了一些工具,但是你忘了必须安装它。你需要一个干净的环境,将所有的依赖关系放在一个地方,以便以后更方便。
|
||||
|
||||
或者你可能工作在 DevOps 中,你所服务的开发人员用模糊的依赖关系来编写代码,这使得测试变得更加困难。你需要一种方法来获得一个干净的盒子,将代码放入其中,并通过它运行代码,而且你希望这些环境是一次性的和可重复的。
|
||||
|
||||
那么选择 [Vagrant][1] 吧。由 HashiCorp 根据 [MIT License][2] 创建,Vagrant 可充当 VirtualBox, Microsoft Hyper-V 或 Docker 容器的包装器和前端,并且可以通过[许多其他供应商][3]的插件进行扩展。你可以配置 Vagrant 以提供可重复干净的环境,并且已安装需要的基础架构。配置脚本是可移植的,因此,如果你的仓库和 Vagrant 配置脚本位于基于云存储上,那么你只需要很少的限制就可以启动并在多台机器机器上工作。让我们来看一看。
|
||||
|
||||
### 安装
|
||||
|
||||
对于本次安装,我的环境是 Linux Mint 桌面,版本是 18.3 Cinnamon 64 位,在其他大多数 Debian 派生系统上安装非常类似。在大多数发行版中,对于基于 RPM 的系统也有类似的安装程序。Vagrant 的[安装页面][4]为 Debian, Windows, CentOS, MacOS 和 Arch Linux 都提供下载,但是我在我的软件包管理器中找到了它,所以我在那进行了安装。
|
||||
|
||||
最简单的安装使用了 VirtualBox 作为虚拟化提供者,所以我需要安装它:
|
||||
```
|
||||
sudo apt-get install virtualbox vagrant
|
||||
|
||||
```
|
||||
|
||||
安装程序将会获取依赖项 - 主要是 Ruby 一些东西,安装它们。
|
||||
|
||||
### 建立一个项目
|
||||
|
||||
在设置你的项目之前,你需要了解一些你想要运行它的环境。你可以在 [Vagrant Boxes 仓库][5]中为许多虚拟化提供者找到大量预配置的盒子。许多会预先配置一些你可能需要的核心基础设置,比如 PHP, MySQL 和 Apache,但是对于本次测试,我将安装一个 Debian 8 64 位裸机 "Jessie" 沙盒并手动安装一些东西,这样你就可以看到具体过程了。
|
||||
```
|
||||
mkdir ~/myproject
|
||||
|
||||
cd ~/myproject
|
||||
|
||||
vagrant init debian/contrib-jessie64
|
||||
|
||||
vagrant up
|
||||
|
||||
```
|
||||
|
||||
最后一条命令将根据需要从仓库中获取或更新 VirtualBox 镜像,然后拉起启动器,你的系统上会出现一个运行框!下次启动这个项目时,除非镜像已经在仓库中更新,否则不会花费太长时间。
|
||||
|
||||
要访问沙盒,只需要输入 `vagrant ssh`,你将被放到虚拟机的全功能 SSH 会话中,你将会是 `vagrant` 用户,但你是 `sudo` 组的成员,所以你可以切换到 root,并在这里做你想做的任何事情。
|
||||
|
||||
你会在沙盒中看到一个名为 `/vagrant` 目录,对这个目录小心点,因为它与你主机上的 `~/myproject` 文件夹保持同步。在虚拟机 `/vagrant` 下建立一个文件它会立即复制到主机上,反之亦然。注意,有些沙盒并没有安装 VirtualBox 的附加功能,所以拷贝只能在启动时才起作用。有一些用于手动同步的命令行工具,这可能是测试环境中非常有用的特性。我倾向于坚持使用那些有附加功能的沙盒,所以这个目录正常工作,不必考虑它。
|
||||
|
||||
这个方案的好处很快显现出来了: 如果你在主机上有一个代码编辑工具链,并处于某种原因不希望它出现在虚拟机上,那么这不是问题 - 在主机上进行编辑,虚拟机会立刻更改。快速更改虚拟机,它也将其同步到主机上的“官方”副本
|
||||
。
|
||||
|
||||
让我们关闭这个盒子,这样我们就可以在这个盒子里提供一些我们需要的东西:`vagrant halt`。
|
||||
|
||||
### 在 Vm 上安装额外的软件
|
||||
|
||||
对于这个例子,我将使用 [Apache][6], [PostgreSQL][7] 和 [Dancer][8] web 框架为 Perl 的一个项目开发。我将修改Vagrant配置脚本,以便我需要的东西已经安装。 为了使事情更容易保持稍后更新,我将在项目根目录下创建一个脚本`~/myproject/Vagrantfile`:
|
||||
```
|
||||
$provision_script = <<SCRIPT
|
||||
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
apt-get update
|
||||
|
||||
apt-get -y install \
|
||||
|
||||
apache2 \
|
||||
|
||||
postgresql-client-9.4 \
|
||||
|
||||
postgresql-9.4 \
|
||||
|
||||
libdbd-pg-perl \
|
||||
|
||||
libapache2-mod-fastcgi \
|
||||
|
||||
libdata-validate-email-perl \
|
||||
|
||||
libexception-class-perl \
|
||||
|
||||
libexception-class-trycatch-perl \
|
||||
|
||||
libtemplate-perl \
|
||||
|
||||
libtemplate-plugin-json-escape-perl \
|
||||
|
||||
libdbix-class-perl \
|
||||
|
||||
libyaml-tiny-perl \
|
||||
|
||||
libcrypt-saltedhash-perl \
|
||||
|
||||
libdancer2-perl \
|
||||
|
||||
libtemplate-plugin-gravatar-perl \
|
||||
|
||||
libtext-csv-perl \
|
||||
|
||||
libstring-tokenizer-perl \
|
||||
|
||||
cpanminus
|
||||
|
||||
cpanm -f -n \
|
||||
|
||||
Dancer2::Session::Cookie \
|
||||
|
||||
Dancer2::Plugin::DBIC \
|
||||
|
||||
Dancer2::Plugin::Auth::Extensible::Provider::DBIC \
|
||||
|
||||
Dancer2::Plugin::Locale \
|
||||
|
||||
Dancer2::Plugin::Growler
|
||||
|
||||
sudo a2enmod rewrite fastcgi
|
||||
|
||||
sudo apache2ctl restart
|
||||
|
||||
SCRIPT
|
||||
|
||||
```
|
||||
|
||||
在 Vagrantfile 结尾附近,你会发现一行 `config.vm.provision` 变量,正如你在示例中看到的那样,你可以在此处以内联方式进行操作,只需通过取消注释以下行:
|
||||
```
|
||||
# config.vm.provision "shell", inline: <<-SHELL
|
||||
|
||||
# sudo apt-get update
|
||||
|
||||
# sudo apt-get install -y apache2
|
||||
|
||||
# SHELL
|
||||
|
||||
```
|
||||
|
||||
相反,将那四行替换为使用你在文件顶部定义为变量的配置脚本:
|
||||
```
|
||||
config.vm.provision "shell", inline: $provision_script
|
||||
|
||||
```
|
||||
|
||||
取消注释 `forwarded_port`。如果你愿意,你可以将端口从 8080 更改为其它端口。我通常使用 5000 端口,在浏览器中输入 `http://localhost:5000` 以访问虚拟机上的 Apache 服务器。
|
||||
|
||||
你可能还希望将转发的端口设置为从主机访问 VM 上的 Apache。寻找包含的行并取消注释它。如果你愿意,也可以将端口从 8080 更改为其他内容。我通常使用端口 5000,并在我的浏览器访问我虚拟机上的 Apache 服务器。
|
||||
|
||||
这里有一个设置提示:如果你的仓库位于云存储上,为了在多台机器上使用 Vagrant,你可能希望将不同机器上的 `VAGRANT_HOME` 环境变量设置为不同的东西。通过 VirtualBox 的工作方式,你需要分别为这些系统存储状态信息,确保你的版本控制系统忽略了用于此的目录 - 我将 `.vagrant.d*` 添加到仓库的 `.gitignore` 文件中。不过,我确实让 Vagrantfile 成为仓库的一部分!
|
||||
|
||||
### 好了!
|
||||
|
||||
我进入 `vagrant up`,我准备开始写代码了。一旦你做了一两次,你可能会想出一些你会回收很多的 Vagrantfile 模板文件(就像我刚刚那样),这就是 Vagrant 的优势之一。你可以更快地完成实际的编码工作,并将很少的时间花在基础设施上!
|
||||
|
||||
你可以使用 Vagrant 做更多事情。配置工具存在于许多工具链中,因此,无论你需要复制什么环境,它都是快速而简单的。
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/18/4/getting-started-vagrant
|
||||
|
||||
作者:[Ruth Holloway][a]
|
||||
译者:[MjSeven](https://github.com/MjSeven)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://opensource.com/users/druthb
|
||||
[1]:https://vagrantup.com
|
||||
[2]:https://opensource.org/licenses/MIT
|
||||
[3]:https://github.com/hashicorp/vagrant/wiki/Available-Vagrant-Plugins#providers
|
||||
[4]:https://www.vagrantup.com/downloads.html
|
||||
[5]:https://app.vagrantup.com/boxes/search
|
||||
[6]:https://httpd.apache.org/
|
||||
[7]:https://postgresql.org
|
||||
[8]:https://perldancer.org
|
||||
@@ -0,0 +1,82 @@
|
||||
你可以用 Linux 中的 IP 工具做 3 件有用的事情
|
||||
======
|
||||
|
||||

|
||||
|
||||
`ifconfig` 命令在 Linux 上被弃用已有十多年的时间了,而 `iproute2` 项目包含了神奇的工具 `ip`。许多在线教程资源仍然采用旧的命令行工具,如 `ifconfig`、`route` 和 `netstat`。本教程的目标是分享一些可以使用 `ip` 工具轻松完成的网络相关的事情。
|
||||
|
||||
### 找出你的 IP 地址
|
||||
```
|
||||
[dneary@host]$ ip addr show
|
||||
|
||||
[snip]
|
||||
|
||||
44: wlp4s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
|
||||
|
||||
link/ether 5c:e0:c5:c7:f0:f1 brd ff:ff:ff:ff:ff:ff
|
||||
|
||||
inet 10.16.196.113/23 brd 10.16.197.255 scope global dynamic wlp4s0
|
||||
|
||||
valid_lft 74830sec preferred_lft 74830sec
|
||||
|
||||
inet6 fe80::5ee0:c5ff:fec7:f0f1/64 scope link
|
||||
|
||||
valid_lft forever preferred_lft forever
|
||||
|
||||
```
|
||||
|
||||
`ip addr show` 会告诉你很多关于你的所有网络链接设备的信息。在这里,我的无线以太网卡(wlp4s0)是 IPv4 地址(`inet` 字段)`10.16.196.113/23`。 `/23` 表示 32 位 IP 地址中的 23 位将被该子网中的所有 IP 地址共享。子网中的 IP 地址范围从 `10.16.196.0 到 10.16.197.254`。子网的广播地址(IP 地址后面的 `brd` 字段)`10.16.197.255` 保留给子网上所有主机的广播流量。
|
||||
|
||||
例如,我们只能使用 `ip addr show dev wlp4s0` 来显示单个设备的信息。
|
||||
|
||||
### 显示你的路由表
|
||||
```
|
||||
[dneary@host]$ ip route list
|
||||
|
||||
default via 10.16.197.254 dev wlp4s0 proto static metric 600
|
||||
|
||||
10.16.196.0/23 dev wlp4s0 proto kernel scope link src 10.16.196.113 metric 601
|
||||
|
||||
192.168.122.0/24 dev virbr0 proto kernel scope link src 192.168.122.1 linkdown
|
||||
|
||||
```
|
||||
|
||||
路由表是本地主机帮助网络流量确定去哪里的方式。它包含一组路标,将流量发送到特定的接口,以及在旅途中的特定下一个地点。
|
||||
|
||||
如果你运行任何虚拟机或容器,它们将获得自己的 IP 地址和子网,这可能会使这些路由表非常复杂,但在单个主机中,通常有两条指令。对于本地流量,将其发送到本地以太网上,并且网络交换机将找出(使用称为 ARP 的协议)哪个主机拥有目标 IP 地址,并且要将流量发送到哪里。对于到互联网的流量,将其发送到本地网关节点,它将更好地了解如何到达目的地。
|
||||
|
||||
在上面的情况中,第一行代表外部流量的外部网关,第二行代表本地流量,第三行代表主机上运行的虚拟机的虚拟网桥,但该链接当前未激活。
|
||||
|
||||
### 监视你的网络配置
|
||||
```
|
||||
[dneary@host]$ ip monitor all
|
||||
|
||||
[dneary@host]$ ip -s link list wlp4s0
|
||||
|
||||
```
|
||||
|
||||
`ip monitor` 命令可用于监视路由表中的更改,网络接口上的网络寻址或本地主机上 ARP 表的更改。此命令在调试与容器和网络相关的网络问题时特别有用,如当两个虚拟机应该能彼此通信,但实际不能。
|
||||
|
||||
在使用 all 时,ip monitor 会报告报告以 [LINK](网络接口更改),[ROUTE](更改路由表)、[ADDR](IP 地址更改)或 [NEIGH](与马无关 - 与邻居的 ARP 地址相关的变化)。
|
||||
|
||||
你还可以监视特定对象上的更改(例如,特定的路由表或 IP 地址)。
|
||||
|
||||
另一个适用于许多命令的有用选项是 `ip -s`,它提供了一些统计信息。添加第二个 `-s` 选项可以添加更多统计信息。上面的 `ip -s link list wlp4s0` 会给出很多关于接收和发送的数据包的信息、丢弃的数据包数量、检测到的错误等等。
|
||||
|
||||
### 提示:缩短你的命令
|
||||
|
||||
一般来说,对于 `ip` 工具,你只需要包含足够的字母来唯一标识你想要做的事情。你可以使用 `ip mon` 来代替 `ip monitor`。你可以使用 `ip a l`,,而不是 `ip addr list`,并且可以使用 `ip r`来代替 `ip route`。`ip link list` 可以缩写为 `ip l ls`。要了解可用于更改命令行为的许多选项,请浏览[ ip 手册页][1]。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/18/5/useful-things-you-can-do-with-IP-tool-Linux
|
||||
|
||||
作者:[Dave Neary][a]
|
||||
选题:[lujun9972](https://github.com/lujun9972)
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://opensource.com/users/dneary
|
||||
[1]:https://www.systutorials.com/docs/linux/man/8-ip-route/
|
||||
Reference in New Issue
Block a user