mirror of
https://github.com/LCTT/TranslateProject.git
synced 2025-03-24 02:20:09 +08:00
commit
31a261d759
56
README.md
56
README.md
@ -56,6 +56,7 @@ LCTT 的组成
|
||||
* 2016/02/29 选题 DeadFire 病逝。
|
||||
* 2016/05/09 提升 PurlingNayuki 为校对。
|
||||
* 2016/09/10 LCTT 三周年。
|
||||
* 2016/12/24 拟定 LCTT [Core 规则](core.md),并增加新的 Core 成员: @ucasFL、@martin2011qi,及调整一些组。
|
||||
|
||||
活跃成员
|
||||
-------------------------------
|
||||
@ -63,8 +64,7 @@ LCTT 的组成
|
||||
目前 TP 活跃成员有:
|
||||
- Leader @wxy,
|
||||
- Source @oska874,
|
||||
- Proofreader @PurlingNayuki,
|
||||
- Proofreader @carolinewuyan,
|
||||
- Proofreaders @jasminepeng,
|
||||
- CORE @geekpi,
|
||||
- CORE @GOLinux,
|
||||
- CORE @ictlyh,
|
||||
@ -77,95 +77,95 @@ LCTT 的组成
|
||||
- CORE @alim0x,
|
||||
- CORE @tinyeyeser,
|
||||
- CORE @Locez,
|
||||
- CORE @ucasFL
|
||||
- CORE @martin2011qi
|
||||
- Senior @DeadFire,
|
||||
- Senior @reinoir222,
|
||||
- Senior @vito-L,
|
||||
- Senior @jasminepeng,
|
||||
- Senior @willqian,
|
||||
- Senior @vizv,
|
||||
- Senior @dongfengweixiao,
|
||||
- Senior @PurlingNayuki,
|
||||
- Senior @carolinewuyan,
|
||||
- cposture,
|
||||
- ZTinoZ,
|
||||
- martin2011qi,
|
||||
- theo-l,
|
||||
- Luoxcat,
|
||||
- GHLandy,
|
||||
- wi-cuckoo,
|
||||
- StdioA,
|
||||
- disylee,
|
||||
- haimingfg,
|
||||
- wwy-hust,
|
||||
- felixonmars,
|
||||
- KayGuoWhu,
|
||||
- mr-ping,
|
||||
- su-kaiyao,
|
||||
- StdioA,
|
||||
- wyangsun,
|
||||
- su-kaiyao,
|
||||
- ivo-wang,
|
||||
- GHLandy,
|
||||
- cvsher,
|
||||
- OneNewLife
|
||||
- DongShuaike,
|
||||
- flsf,
|
||||
- SPccman,
|
||||
- Stevearzh
|
||||
- Stevearzh,
|
||||
- bestony,
|
||||
- Linchenguang,
|
||||
- Linux-pdz,
|
||||
- 2q1w2007,
|
||||
- H-mudcup,
|
||||
- MikeCoder,
|
||||
- NearTan,
|
||||
- goreliu,
|
||||
- H-mudcup,
|
||||
- GitFuture,
|
||||
- MikeCoder,
|
||||
- xiqingongzi,
|
||||
- goreliu,
|
||||
- rusking,
|
||||
- jiajia9linuxer,
|
||||
- name1e5s,
|
||||
- TxmszLou,
|
||||
- ZhouJ-sh,
|
||||
- wangjiezhe,
|
||||
- icybreaker,
|
||||
- zky001,
|
||||
- vim-kakali,
|
||||
- shipsw,
|
||||
- LinuxBars,
|
||||
- Moelf,
|
||||
- name1e5s,
|
||||
- Chao-zhi
|
||||
- johnhoow,
|
||||
- soooogreen,
|
||||
- kokialoves,
|
||||
- linuhap,
|
||||
- GitFuture,
|
||||
- ChrisLeeGit,
|
||||
- blueabysm,
|
||||
- yangmingming,
|
||||
- boredivan,
|
||||
- yechunxiao19,
|
||||
- XLCYun,
|
||||
- KevinSJ,
|
||||
- zky001,
|
||||
- l3b2w1,
|
||||
- tenght,
|
||||
- firstadream,
|
||||
- coloka,
|
||||
- luoyutiantang,
|
||||
- sonofelice,
|
||||
- jiajia9linuxer,
|
||||
- scusjs,
|
||||
- woodboow,
|
||||
- 1w2b3l,
|
||||
- JonathanKang,
|
||||
- bestony,
|
||||
- crowner,
|
||||
- dingdongnigetou,
|
||||
- mtunique,
|
||||
- Rekii008,
|
||||
- hyaocuk,
|
||||
- szrlee,
|
||||
- Xuanwo,
|
||||
- nd0104,
|
||||
- xiaoyu33,
|
||||
- ynmlml,
|
||||
- Flowsnow,
|
||||
- ggaaooppeenngg,
|
||||
- mudongliang,
|
||||
- Tanete,
|
||||
- lfzark,
|
||||
- chenzhijun,
|
||||
- frankatlingingdigital,
|
||||
- willcoderwang,
|
||||
- liuaiping,
|
||||
- rogetfan,
|
||||
- JeffDing,
|
||||
- Yuking-net,
|
||||
|
||||
(按增加行数排名前百,更新于2016/09/10)
|
||||
(按增加行数排名前百,更新于2016/12/24)
|
||||
|
||||
谢谢大家的支持!
|
||||
|
||||
|
39
core.md
Normal file
39
core.md
Normal file
@ -0,0 +1,39 @@
|
||||
给核心成员的一封信
|
||||
===================
|
||||
|
||||
鉴于您的卓越贡献,我邀请您成为 LCTT 的核心(Core)成员。
|
||||
|
||||
作为核心成员,您拥有如下权利:
|
||||
|
||||
- 您能够合并您以及其它普通成员的 PR
|
||||
- 您能够校对其它普通成员的文章,并提交校对 PR
|
||||
- 您能够建议或反对将某位普通成员升级为核心成员
|
||||
- 您能够自主添加符合 LCTT 定位的选题并翻译
|
||||
- 您能够以 LCTT 核心成员名义宣称、署名
|
||||
- 在得到 LCTT 同意后,以 LCTT 身份出席活动
|
||||
- 在得到 LCTT 同意后,创建 LCTT 名下的其它仓库并管理(及邀请其它成员参与)
|
||||
- 成为 LinuxCN 管理团队的一员
|
||||
- 参与 LCTT 及 LinuxCN 决策投票
|
||||
|
||||
以下是不允许的行为,虽然您可能有这样的权限:
|
||||
|
||||
- 直接在 LCTT 主仓库上提交修改
|
||||
- 在 LCTT 主仓库上创建分支
|
||||
|
||||
除此以外,您有以下义务:
|
||||
|
||||
- 为您的 GitHub 账户创建安全的密码
|
||||
- 为您的 GitHub 账户创建 2FA 验证
|
||||
- 不得外借您的 GitHub 账户,您需要为您的账户负责
|
||||
- 保持参与度,如长期不能参与,会转换身份为荣誉成员,并放弃相应权限
|
||||
- 接待新加入的成员,并做好引导个工作
|
||||
- 维护 Wiki
|
||||
|
||||
作为核心成员,您会执行一些管理工作,以下是一些惯例:
|
||||
|
||||
- 合并 PR 时,要按时间顺序,从最早的(最下方)的开始合并
|
||||
- 合并 PR 时,如果与仓库或前面的 PR 冲突,则关闭该 PR,并提醒 PR 发起人修改处理
|
||||
- 除非必要,合并 PR 时不要 squash-merge
|
||||
|
||||
wxy@LCTT
|
||||
2016/12/24
|
@ -0,0 +1,126 @@
|
||||
Vim 初学者入门指南
|
||||
============================================================
|
||||

|
||||
|
||||
|
||||
这篇文章是 [VIM 用户指南][12] 系列文章中的一篇:
|
||||
|
||||
* Vim 初学者入门指南
|
||||
* [Vim 快捷键速查表][3]
|
||||
* [5 个针对有经验用户的 Vim 技巧][4]
|
||||
* [3 个针对高级用户的 Vim 编辑器有用技巧][5]
|
||||
|
||||
对一个程序员来说,选择一个文本编辑器是一件非常重要的事。因为不同编辑器之间有着不少的差异:图形界面或者非图形界面、不同的快捷键、不同的编程语言支持、不同的插件以及自定义设置等等。我建议不是去搜索最棒的编辑器,而是去选择最适合你的习惯且最适应你的任务的那一个。假如你打算在一个团体中工作,那么最好和你的共事者选择一样的编辑器。这样的话,一旦你在使用中遇到问题,你就可以去向他们寻求帮助。
|
||||
|
||||
这正是我在几年之前开始使用 Vim 的原因。通常来说,Vim 会被置于传说中的 Emacs 的对立面。我承认我对 Emacs 知之甚少,但是对于它俩,你需要知道的是它们都可以被深度定制,并且在初学时也都非常令人困惑。这个教程并不会介绍有关 Vim 的所有内容,而是将介绍一些基础以使你在最初就能正确使用它,随后还会展示一些小技巧,借此(希望能)让你有能力自己去探索学习。
|
||||
|
||||
Vim 一词来源于 “VI iMproved”。Vi 是一个被广泛安装于 Unix 系统的非图形界面文本编辑器,并且它也被默认安装在了 Linux 系统中。Vim 是这个原始编辑器的增强版,但是不同于 Vi,并不是每个发行版都默认安装了它。
|
||||
|
||||
### 安装
|
||||
|
||||
在 Ubuntu 中可以使用如下命令来安装 Vim:
|
||||
|
||||
```
|
||||
sudo apt-get install vim
|
||||
```
|
||||
|
||||
如果你已经对某些插件有了兴趣,使用以下命令:
|
||||
|
||||
```
|
||||
sudo apt-cache search vim
|
||||
```
|
||||
|
||||
这命令将给你输出一个很长的和 Vim 有关的包列表。在这之中,有针对不同编程语言的工具,有插件管理器,等等。
|
||||
|
||||
在这系列教程中,我将会在 Ubuntu 上使用最新版的 Vim(7.3.154,LCTT 译注:现在最新版为 8.0)。当然你也可以使用其它任何版本。
|
||||
|
||||
### 热身
|
||||
|
||||
在终端输入 `vim` 命令,你将会看到一个非常棒的欢迎界面。
|
||||
|
||||

|
||||
|
||||
(LCTT 译注:看到了欢迎界面中那行“Help poor children in Uganda!” 了吗?)
|
||||
|
||||
如果你之前从未使用过 Vi 或者 Vim,那么你很可能甚至不知道该怎么退出它... 是的,这是事实。**任何你常用的快捷键在 Vim 中都将失去原有的效果**。(LCTT 译注:网上有个流传的笑话——“如何制造乱码”,“让新手退出 vi”)
|
||||
|
||||
首先,要使用任何命令式的功能,像保存(save)或者退出(exit),你都先得输入一个冒号(`:`)。保存是 `:w` 而退出是 `:q`。如果你想不保存文件就退出,那么就要使用强制退出命令 `:q!`。Vim 中非常棒的一点是你不需要分开输入各个命令,换言之,如果你想保存然后退出,你就可以直接使用 `:wq`。
|
||||
|
||||
现在,我们退出 Vim 再打开一个文本文件。为此,你只需把想要编辑的文件名加在命令后面即可:
|
||||
|
||||
```
|
||||
vim [文本文件名]
|
||||
```
|
||||
|
||||

|
||||
|
||||
一般而言,当你打开一个文本文件,你将会处在查看模式。这使得 Vim 与众不同并且最初会让人感到困惑。Vim 主要由两种模式构成:查看模式和编辑模式。查看模式用于查看内容并且使用一些命令。想要进入编辑模式,只需按 `i` 键进行插入(insert)或者 `a` 键进行添加(add)。想要返回到查看模式或者进行命令式功能的操作,按 `Escape` 键即可。插入(insert)和添加(add)的差异仅仅在于你是想在光标位置之前还是在光标之后进入编辑模式并进行文字输入。要想彻底地明白,你应该亲自去尝试一下。我的建议是:仅在行尾使用添加(add),而在其它时候使用插入(insert)。
|
||||
|
||||
(LCTT 译注:此段落中“查看模式”原文是 “visual mode”,疑为“view mode”,在此模式下可以查看文本,但是不能进行编辑;而“visual mode” 是编辑模式的一种,可以按 `v` 键进入,然后就可以用方向键从当前光标位置开始进行选择,并以反白的视觉效果显示,通常选择后可以按 `y` 进行复制、按 `d` 进行剪切等操作。)
|
||||
|
||||
要想在文本之中移动光标,你通常可以使用键盘上的方向键,它们无论是在查看模式还是在编辑模式都可以生效。不过,一个真正的纯粹主义者将会告诉你使用按键 `h` 向左,`j` 向下,`k` 向上,`l` 向右来(在查看模式)进行移动。
|
||||
|
||||
现在你已经明白了如何和简单地控制 Vim,我们再来更加深入一些。
|
||||
|
||||
### 一些简单命令
|
||||
|
||||
现在你已经熟悉了在正常模式和插入模式之间进行切换,下面是一些可以在正常模式中使用的命令:
|
||||
|
||||
* `x`:删除一个字符
|
||||
* `u`:撤销一个操作(相当与 `Ctrl+z`)
|
||||
* `dd`:删除一行内容
|
||||
* `dw`:删除一个单词
|
||||
* `yy`:复制一行内容
|
||||
* `yw`:复制一个单词
|
||||
* `p`:粘贴一个之前删除或复制的行或者单词
|
||||
* `e`:跳到下个单词(LCTT 译注:词尾)(比单纯用方向键更快)
|
||||
* `r`:替换一个字母(按 `r`,松开,然后再按新字母)
|
||||
|
||||
当然不止这些,不过这些对现在来说已经足够了。如果你掌握了上面的全部,你将能你很顺溜地使用 Vim 了。
|
||||
|
||||
对于那些还想知道更多的人,我再多提一下。你可以在任何这些命令之前加上一个数值,那么这个命令将被重复执行相应的次数。例如,`5x` 将在当前行连续删除 5 个字母,而 `3p` 将会粘贴 3 次。
|
||||
|
||||
### 高级命令
|
||||
|
||||
最后,作为对你自己继续探索的鼓励和示例,这里给出几个高级且常用的命令:
|
||||
|
||||
* `/所搜索的内容`:在文中搜索特定内容
|
||||
* `:sp 文本文件名`:将屏幕水平分割成上下两半,新文件展示在另一半。想要在两侧切换焦点,可以使用 `Ctrl+w` 快捷键。
|
||||
|
||||

|
||||
* `:vsp 文本文件名`:同上,但是是垂直分割屏幕
|
||||
* `Ctrl+Shift+C` 和 `Ctrl+Shift+V`:在终端中复制和粘贴文本
|
||||
* `:! 命令名`:在 Vim 中运行 Vim 外的终端命令,直接发送给 shell。例如,`:! ls` 将在不退出编辑器的同时,显示你当前目录内的文件。
|
||||
|
||||

|
||||
|
||||
### 结论
|
||||
|
||||
我觉得你现在应该已经有了足够的准备来开始使用 Vim。你还可以通过安装各种插件,编辑 `~.vimrc` 文件,或者在 shell 中输入 `vimtutor` 命令来使用交互式教程以学到更多。
|
||||
|
||||
如果你有任何你想分享的关于 Vim 的其它命令,请在评论中告知我们。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.maketecheasier.com/start-with-vim-linux/
|
||||
|
||||
作者:[Himanshu Arora][a]
|
||||
译者:[Yinr](https://github.com/Yinr)
|
||||
校对:[jasminepeng](https://github.com/jasminepeng)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://www.maketecheasier.com/author/himanshu/
|
||||
[1]:https://www.maketecheasier.com/author/adrienbrochard/
|
||||
[2]:https://www.maketecheasier.com/start-with-vim-linux/#comments
|
||||
[3]:https://www.maketecheasier.com/vim-keyboard-shortcuts-cheatsheet/
|
||||
[4]:https://www.maketecheasier.com/vim-tips-tricks-for-experienced-users/
|
||||
[5]:https://www.maketecheasier.com/vim-tips-tricks-advanced-users/
|
||||
[6]:https://www.maketecheasier.com/category/linux-tips/
|
||||
[7]:http://www.facebook.com/sharer.php?u=https%3A%2F%2Fwww.maketecheasier.com%2Fstart-with-vim-linux%2F
|
||||
[8]:http://twitter.com/share?url=https%3A%2F%2Fwww.maketecheasier.com%2Fstart-with-vim-linux%2F&text=The+Beginner%26%238217%3Bs+Guide+to+Start+Using+Vim
|
||||
[9]:mailto:?subject=The%20Beginner%E2%80%99s%20Guide%20to%20Start%20Using%20Vim&body=https%3A%2F%2Fwww.maketecheasier.com%2Fstart-with-vim-linux%2F
|
||||
[10]:https://www.maketecheasier.com/turn-dropbox-into-a-blogging-tool-with-scriptogram/
|
||||
[11]:https://www.maketecheasier.com/4-sms-back-up-applications-to-keep-your-messages-safe-android/
|
||||
[12]:https://www.maketecheasier.com/series/vim-user-guide/
|
||||
[13]:https://support.google.com/adsense/troubleshooter/1631343
|
211
published/20131227 Vim Keyboard Shortcuts Cheatsheet - part2.md
Normal file
211
published/20131227 Vim Keyboard Shortcuts Cheatsheet - part2.md
Normal file
@ -0,0 +1,211 @@
|
||||
Vim 快捷键速查表
|
||||
============================================================
|
||||
|
||||
|
||||

|
||||
|
||||
本文是 [Vim 用户指南][12] 系列的其中一篇:
|
||||
|
||||
* [Vim 初学者入门指南][3]
|
||||
* Vim 快捷键速查表
|
||||
* [5 个针对有经验用户的 Vim 技巧][4]
|
||||
* [3 个针对高级用户的 Vim 编辑器实用技巧][5]
|
||||
|
||||
Vim 编辑器是一个基于命令行的工具,是传奇编辑器 vi 的增强版。尽管图形界面的富文本编辑有很多,但是熟悉 Vim 对于每一位 Linux 的使用者都能有所帮助——无论你是经验丰富的系统管理员,还是刚上手树莓派的新手用户。
|
||||
|
||||
这个轻量级的编辑器是个非常强大的工具。在有经验的使用者手中,它能完成不可思议的任务。除了常规的文本编辑功能以外,它还支持一些进阶特性。例如,基于正则表达式的搜索和替换、编码转换,以及语法高亮、代码折叠等的编程特性。
|
||||
|
||||
使用 Vim 时有一个非常重要的一点需要注意,那就是按键的功能取决于编辑器当前的“模式”。例如,在“普通模式”输入字母`j`时,光标会向下移动一行。而当你在“插入模式”下输入字符,则只是正常的文字录入。
|
||||
|
||||
下面就是速查表,以便于你充分利用 Vim。
|
||||
|
||||
### 基本操作
|
||||
|
||||
| 快捷键 | 功能 |
|
||||
| --- | --- |
|
||||
| `Esc` | 从当前模式转换到“普通模式”。所有的键对应到命令。 |
|
||||
| `i` | “插入模式”用于插入文字。回归按键的本职工作。 |
|
||||
| `:` | “命令行模式” Vim 希望你输入类似于保存该文档命令的地方。 |
|
||||
|
||||
|
||||
### 方向键
|
||||
|
||||
| 快捷键 | 功能 |
|
||||
| --- | --- |
|
||||
| `h` | 光标向左移动一个字符 |
|
||||
| `j` 或 `Ctrl + J` | 光标向下移动一行 |
|
||||
| `k` 或 `Ctrl + P` | 光标向上移动一行 |
|
||||
| `l` | 光标向右移动一个字符 |
|
||||
| `0` | (数字 0)移动光标至本行开头 |
|
||||
| `$` | 移动光标至本行末尾 |
|
||||
| `^` | 移动光标至本行第一个非空字符处 |
|
||||
| `w` | 向前移动一个词 (上一个字母和数字组成的词之后) |
|
||||
| `W` | 向前移动一个词 (以空格分隔的词) |
|
||||
| `5w` | 向前移动五个词 |
|
||||
| `b` | 向后移动一个词 (下一个字母和数字组成的词之前) |
|
||||
| `B` | 向后移动一个词 (以空格分隔的词) |
|
||||
| `5b` | 向后移动五个词 |
|
||||
| `G` | 移动至文件末尾 |
|
||||
| `gg` | 移动至文件开头 |
|
||||
|
||||
|
||||
### 浏览文档
|
||||
|
||||
| 快捷键 | 功能 |
|
||||
| --- | --- |
|
||||
| `(` | 跳转到上一句 |
|
||||
| `)` | 跳转到下一句 |
|
||||
| `{` | 跳转到上一段 |
|
||||
| `}` | 跳转到下一段 |
|
||||
| `[[` | 跳转到上一部分 |
|
||||
| `]]` | 跳转到下一部分 |
|
||||
| `[]` | 跳转到上一部分的末尾 |
|
||||
| `][` | 跳转到上一部分的开头 |
|
||||
|
||||
|
||||
### 插入文本
|
||||
|
||||
| 快捷键 | 功能 |
|
||||
| --- | --- |
|
||||
| `a` | 在光标后插入文本 |
|
||||
| `A` | 在行末插入文本 |
|
||||
| `i` | 在光标前插入文本 |
|
||||
| `o` | (小写字母 o)在光标下方新开一行 |
|
||||
| `O` | (大写字母 O)在光标上方新开一行 |
|
||||
|
||||
|
||||
|
||||
### 特殊插入
|
||||
|
||||
| 快捷键 | 功能 |
|
||||
| --- | --- |
|
||||
| `:r [filename]` | 在光标下方插入文件 [filename] 的内容 |
|
||||
| `:r ![command]` | 执行命令 [command] ,并将输出插入至光标下方 |
|
||||
|
||||
|
||||
|
||||
### 删除文本
|
||||
|
||||
| 快捷键 | 功能 |
|
||||
| --- | --- |
|
||||
| `x` | 删除光标处字符 |
|
||||
| `dw` | 删除一个词 |
|
||||
| `d0` | 删至行首 |
|
||||
| `d$` | 删至行末 |
|
||||
| `d)` | 删至句末 |
|
||||
| `dgg` | 删至文件开头 |
|
||||
| `dG` | 删至文件末尾 |
|
||||
| `dd` | 删除该行 |
|
||||
| `3dd` | 删除三行 |
|
||||
|
||||
### 简单替换文本
|
||||
|
||||
| 快捷键 | 功能 |
|
||||
| --- | --- |
|
||||
| `r{text}` | 将光标处的字符替换成 {text} |
|
||||
| `R` | 进入覆写模式,输入的字符将替换原有的字符 |
|
||||
|
||||
### 复制/粘贴文本
|
||||
|
||||
| 快捷键 | 功能 |
|
||||
| --- | --- |
|
||||
| `yy` | 复制当前行至存储缓冲区 |
|
||||
| `["x]yy` | 复制当前行至寄存器 x |
|
||||
| `p` | 在当前行之后粘贴存储缓冲区中的内容 |
|
||||
| `P` | 在当前行之前粘贴存储缓冲区中的内容 |
|
||||
| `["x]p` | 在当前行之后粘贴寄存器 x 中的内容 |
|
||||
| `["x]P` | 在当前行之前粘贴寄存器 x 中的内容 |
|
||||
|
||||
### 撤销/重做操作
|
||||
|
||||
| 快捷键 | 功能 |
|
||||
| --- | --- |
|
||||
| `u` | 撤销最后的操作 |
|
||||
| `Ctrl+r` | 重做最后撤销的操作 |
|
||||
|
||||
### 搜索和替换
|
||||
|
||||
| 快捷键 | 功能 |
|
||||
| --- | --- |
|
||||
| `/search_text` | 检索文档,在文档后面的部分搜索 search_text |
|
||||
| `?search_text` | 检索文档,在文档前面的部分搜索 search_text |
|
||||
| `n` | 移动到后一个检索结果 |
|
||||
| `N` | 移动到前一个检索结果 |
|
||||
| `:%s/original/replacement` | 检索第一个 “original” 字符串并将其替换成 “replacement” |
|
||||
| `:%s/original/replacement/g` | 检索并将所有的 “original” 替换为 “replacement” |
|
||||
| `:%s/original/replacement/gc` | 检索出所有的 “original” 字符串,但在替换成 “replacement” 前,先询问是否替换 |
|
||||
|
||||
### 书签
|
||||
|
||||
| 快捷键 | 功能 |
|
||||
| --- | --- |
|
||||
| `m {a-zA-Z}` | 在当前光标位置设置书签,书签名可用一个大小写字母({a-zA-Z}) |
|
||||
| `:marks` | 列出所有书签 |
|
||||
| `{a-zA-Z}` | 跳转到书签 {a-zA-Z} |
|
||||
|
||||
|
||||
### 选择文本
|
||||
|
||||
| 快捷键 | 功能 |
|
||||
| --- | --- |
|
||||
| `v` | 进入逐字可视模式 |
|
||||
| `V` | 进入逐行可视模式 |
|
||||
| `Esc` | 退出可视模式 |
|
||||
|
||||
|
||||
### 改动选中文本
|
||||
|
||||
| 快捷键 | 功能 |
|
||||
| --- | --- |
|
||||
| `~` | 切换大小写 |
|
||||
| `d` | 删除一个词 |
|
||||
| `c` | 变更 |
|
||||
| `y` | 复制 |
|
||||
| `>` | 右移 |
|
||||
| `<` | 左移 |
|
||||
| `!` | 通过外部命令进行过滤 |
|
||||
|
||||
|
||||
### 保存并退出
|
||||
|
||||
| 快捷键 | 功能 |
|
||||
| --- | --- |
|
||||
| `:q` | 退出 Vim,如果文件已被修改,将退出失败 |
|
||||
| `:w` | 保存文件 |
|
||||
| `:w new_name` | 用 new_name 作为文件名保存文件 |
|
||||
| `:wq` | 保存文件并退出 Vim |
|
||||
| `:q!` | 退出 Vim,不保存文件改动 |
|
||||
| `ZZ` | 退出 Vim,如果文件被改动过,保存改动内容 |
|
||||
| `ZQ` | 与 :q! 相同,退出 Vim,不保存文件改动 |
|
||||
|
||||
### 下载 Vim 快捷键速查表
|
||||
|
||||
仅仅是这样是否还不足以满足你?别担心,我们已经为你整理好了一份下载版的速查表,以备不时之需。
|
||||
|
||||
[点此下载(英文)][14]
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.maketecheasier.com/vim-keyboard-shortcuts-cheatsheet/
|
||||
|
||||
作者:[Himanshu Arora][a]
|
||||
译者:[martin2011qi](https://github.com/martin2011qi)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://www.maketecheasier.com/author/himanshu/
|
||||
[1]:https://www.maketecheasier.com/author/mayank/
|
||||
[2]:https://www.maketecheasier.com/vim-keyboard-shortcuts-cheatsheet/#comments
|
||||
[3]:https://linux.cn/article-8143-1.html
|
||||
[4]:https://www.maketecheasier.com/vim-tips-tricks-for-experienced-users/
|
||||
[5]:https://www.maketecheasier.com/vim-tips-tricks-advanced-users/
|
||||
[6]:https://www.maketecheasier.com/category/linux-tips/
|
||||
[7]:http://www.facebook.com/sharer.php?u=https%3A%2F%2Fwww.maketecheasier.com%2Fvim-keyboard-shortcuts-cheatsheet%2F
|
||||
[8]:http://twitter.com/share?url=https%3A%2F%2Fwww.maketecheasier.com%2Fvim-keyboard-shortcuts-cheatsheet%2F&text=Vim+Keyboard+Shortcuts+Cheatsheet
|
||||
[9]:mailto:?subject=Vim%20Keyboard%20Shortcuts%20Cheatsheet&body=https%3A%2F%2Fwww.maketecheasier.com%2Fvim-keyboard-shortcuts-cheatsheet%2F
|
||||
[10]:https://www.maketecheasier.com/locate-system-image-tool-in-windows-81/
|
||||
[11]:https://www.maketecheasier.com/create-system-image-in-windows8/
|
||||
[12]:https://www.maketecheasier.com/series/vim-user-guide/
|
||||
[13]:https://support.google.com/adsense/troubleshooter/1631343
|
||||
[14]:http://www.maketecheasier.com/cheatsheet/vim-keyboard-shortcuts-cheatsheet/
|
@ -0,0 +1,73 @@
|
||||
aria2 与 wget :选择你的下载管理器
|
||||
============================================================
|
||||
|
||||
任何没有下载管理器的 Linux 操作系统是不完整的。多年来,基于 Linux 的发行版使用 wget 作为默认下载管理器。它是一个很棒的小程序,可以在命令行下工作,如果你需要安装东西、下载东西、运行 shell 脚本等,某种程度上都可以在 wget 中完成任务。在过去的很多年里,我们发现 wget 缺乏一些高级的功能,而它的替代品 ** aria2** ,由于满足了高级 Linux 用户的渴望而受到了许多用户的关注。我们将在本文中回顾 **aria2** 的安装过程以及 wget 和 aria2 之间的区别,因此你可以决定哪个下载管理器最符合你的需要。
|
||||
|
||||
### 安装 aria2
|
||||
|
||||
**在 Ubuntu/Debian 中安装 aria2:**
|
||||
|
||||
只要在 Ubuntu 中运行下面的命令安装:
|
||||
|
||||
```
|
||||
sudo apt-get install aria2
|
||||
```
|
||||
|
||||
[
|
||||

|
||||
][1]
|
||||
|
||||
**在 Fedora/RHEL/Centos 中安装 aria2:**
|
||||
|
||||
运行下面的命令在 Fedora/RHEL 和基于 Centos 的系统中安装:
|
||||
|
||||
```
|
||||
sudo yum install aria2
|
||||
```
|
||||
|
||||
**在 Arch Linux 中安装 aria2:**
|
||||
|
||||
运行下面的命令在基于 Arch Linux 的系统中安装。
|
||||
|
||||
```
|
||||
sudo pacman -Sy aria2
|
||||
```
|
||||
|
||||
### aria2 的重要功能
|
||||
|
||||
让我们来讨论 aria2 中使它如此受欢迎的重要功能:
|
||||
|
||||
* 通过使用多个连接下载文件,最大限度地利用可用带宽。
|
||||
* 同时下载多个文件和同时下载的能力。
|
||||
* torrent 客户端提供的所有功能都可以在这个小程序中找到。
|
||||
* 它提供 meta 链接下载。
|
||||
* 支持使用 JSON-RPC 和 XML-RPC 协议的远程过程调用。
|
||||
* 无需等待当前下载完成,轻松批量下载文件。
|
||||
|
||||
### aria2 的一些副作用:
|
||||
|
||||
aria2 的多线程机制可能会使目标服务器过载。相比下来 wget 就轻量级多了,wget 比 aria2 消耗资源少 20%。aria2 尚未经受 wget 那样巨大的使用规模的测试,因此可能完全准备好成为默认下载管理器。
|
||||
|
||||
### wget 的重要特性
|
||||
|
||||
* 当然它是最广泛使用和测试的下载管理器。
|
||||
* 它是一个简单的程序,具有较少的功能,但稳定工作了几十年。
|
||||
* 默认所有 Linux 发行版上都有,不需要繁重的安装。
|
||||
* 与 aria2 相比更轻量级。
|
||||
|
||||
### 总结
|
||||
|
||||
虽然 wget 没有丰富的功能,但仍然工作得相当不错,然而,高级用户肯定会喜欢 aria2,因为它满足更快和并发下载的需要。aria2 可能需要很长时间来取代 wget 成为默认下载管理器,而目前 wget 用在几乎所有 linux 发行版的安装程序脚本中。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: http://linuxpitstop.com/aria-2-vs-wget/
|
||||
|
||||
作者:[Aun][a]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:http://linuxpitstop.com/author/aun/
|
||||
[1]:http://linuxpitstop.com/wp-content/uploads/2015/06/aria2.png
|
@ -0,0 +1,256 @@
|
||||
Powerline:给 Vim 和 Bash 提供更棒的状态行和提示信息
|
||||
=================================================
|
||||
|
||||
Powerline 是一个极棒的 [Vim 编辑器][1]的状态行插件,这个插件是使用 Python 开发的,主要用于显示状态行和提示信息,适用于很多软件,比如 bash、zsh、tmux 等等。
|
||||
|
||||
[
|
||||

|
||||
][2]
|
||||
|
||||
*Powerline 使 Linux 终端更具威力*
|
||||
|
||||
### 特色
|
||||
|
||||
1. 使用 python 编写,使其更具扩展性且功能丰富
|
||||
2. 稳定易测的代码库,兼容 python 2.6+ 和 python 3
|
||||
3. 支持多种 Linux 功能及工具的提示和状态栏
|
||||
4. 通过 JSON 保存配置和颜色方案
|
||||
5. 快速、轻量级,具有后台守护进程支持,提供更佳的性能
|
||||
|
||||
### Powerline 效果截图
|
||||
|
||||
[
|
||||

|
||||
][3]
|
||||
|
||||
*Vim 中 Powerline 状态行效果*
|
||||
|
||||
在本文中,我会介绍如何安装 Powerline 及其字体,以及如何在 RedHat 和 Debian 类的系统中使 Bash 和 Vim 支持 Powerline。
|
||||
|
||||
### 第一步:准备好安装 Powerline 所需的软件
|
||||
|
||||
由于和其它无关项目之间存在命名冲突,因此 powerline 只能放在 PyPI(Python Package Index)中的 `powerline-status` 包下.
|
||||
|
||||
为了从 PyPI 中安装该包,需要先准备好 `pip`(该工具专门用于 Python 包的管理)工具。所以首先要在 Linux 系统下安装好 `pip` 工具。
|
||||
|
||||
#### 在 Debian、Ubuntu 和 Linux Mint 中安装 pip
|
||||
|
||||
```
|
||||
# apt-get install python-pip
|
||||
```
|
||||
**示例输出:**
|
||||
|
||||
```
|
||||
Reading package lists... Done
|
||||
Building dependency tree
|
||||
Reading state information... Done
|
||||
Recommended packages:
|
||||
python-dev-all python-wheel
|
||||
The following NEW packages will be installed:
|
||||
python-pip
|
||||
0 upgraded, 1 newly installed, 0 to remove and 533 not upgraded.
|
||||
Need to get 97.2 kB of archives.
|
||||
After this operation, 477 kB of additional disk space will be used.
|
||||
Get:1 http://archive.ubuntu.com/ubuntu/ trusty-updates/universe python-pip all 1.5.4-1ubuntu3 [97.2 kB]
|
||||
Fetched 97.2 kB in 1s (73.0 kB/s)
|
||||
Selecting previously unselected package python-pip.
|
||||
(Reading database ... 216258 files and directories currently installed.)
|
||||
Preparing to unpack .../python-pip_1.5.4-1ubuntu3_all.deb ...
|
||||
Unpacking python-pip (1.5.4-1ubuntu3) ...
|
||||
Processing triggers for man-db (2.6.7.1-1ubuntu1) ...
|
||||
Setting up python-pip (1.5.4-1ubuntu3) ...
|
||||
```
|
||||
|
||||
#### 在 CentOS、RHEL 和 Fedora 中安装 pip
|
||||
|
||||
在 Fedora 类系统中,需要先打开 [epel 仓库][4],然后按照如下方法安装 pip 包。
|
||||
|
||||
```
|
||||
# yum install python-pip
|
||||
# dnf install python-pip [Fedora 22+ 以上]
|
||||
```
|
||||
|
||||
**示例输出:**
|
||||
|
||||
```
|
||||
Installing:
|
||||
python-pip noarch 7.1.0-1.el7 epel 1.5 M
|
||||
Transaction Summary
|
||||
=================================================================================
|
||||
Install 1 Package
|
||||
Total download size: 1.5 M
|
||||
Installed size: 6.6 M
|
||||
Is this ok [y/d/N]: y
|
||||
Downloading packages:
|
||||
python-pip-7.1.0-1.el7.noarch.rpm | 1.5 MB 00:00:01
|
||||
Running transaction check
|
||||
Running transaction test
|
||||
Transaction test succeeded
|
||||
Running transaction
|
||||
Installing : python-pip-7.1.0-1.el7.noarch 1/1
|
||||
Verifying : python-pip-7.1.0-1.el7.noarch 1/1
|
||||
Installed:
|
||||
python-pip.noarch 0:7.1.0-1.el7
|
||||
Complete!
|
||||
```
|
||||
|
||||
### 第二步:在 Linux 中安装 Powerline
|
||||
|
||||
现在可以从 Git 仓库中安装 Powerline 的最新开发版。在此之前系统需要安装好 Git 工具以便可以从仓库拉下代码。
|
||||
|
||||
```
|
||||
# apt-get install git
|
||||
# yum install git
|
||||
# dnf install git
|
||||
```
|
||||
|
||||
然后你可以通过 `pip` 命令安装 Powerline。
|
||||
|
||||
```
|
||||
# pip install git+git://github.com/Lokaltog/powerline
|
||||
```
|
||||
|
||||
**示例输出:**
|
||||
|
||||
```
|
||||
Cloning git://github.com/Lokaltog/powerline to /tmp/pip-WAlznH-build
|
||||
Running setup.py (path:/tmp/pip-WAlznH-build/setup.py) egg_info for package from git+git://github.com/Lokaltog/powerline
|
||||
warning: no previously-included files matching '*.pyc' found under directory 'powerline/bindings'
|
||||
warning: no previously-included files matching '*.pyo' found under directory 'powerline/bindings'
|
||||
Installing collected packages: powerline-status
|
||||
Found existing installation: powerline-status 2.2
|
||||
Uninstalling powerline-status:
|
||||
Successfully uninstalled powerline-status
|
||||
Running setup.py install for powerline-status
|
||||
warning: no previously-included files matching '*.pyc' found under directory 'powerline/bindings'
|
||||
warning: no previously-included files matching '*.pyo' found under directory 'powerline/bindings'
|
||||
changing mode of build/scripts-2.7/powerline-lint from 644 to 755
|
||||
changing mode of build/scripts-2.7/powerline-daemon from 644 to 755
|
||||
changing mode of build/scripts-2.7/powerline-render from 644 to 755
|
||||
changing mode of build/scripts-2.7/powerline-config from 644 to 755
|
||||
changing mode of /usr/local/bin/powerline-config to 755
|
||||
changing mode of /usr/local/bin/powerline-lint to 755
|
||||
changing mode of /usr/local/bin/powerline-render to 755
|
||||
changing mode of /usr/local/bin/powerline-daemon to 755
|
||||
Successfully installed powerline-status
|
||||
Cleaning up...
|
||||
```
|
||||
|
||||
### 第三步:在 Linux 中安装 Powerline 的字体
|
||||
|
||||
Powerline 使用特殊的符号来为开发者显示特殊的箭头效果和符号内容。因此你的系统中必须要有符号字体或者补丁过的字体。
|
||||
|
||||
通过下面的 [wget][5] 命令下载最新的系统字体及字体配置文件。
|
||||
|
||||
```
|
||||
# wget https://github.com/powerline/powerline/raw/develop/font/PowerlineSymbols.otf
|
||||
# wget https://github.com/powerline/powerline/raw/develop/font/10-powerline-symbols.conf
|
||||
```
|
||||
|
||||
然后你将下载的字体放到字体目录下 `/usr/share/fonts` 或者 `/usr/local/share/fonts`,或者你可以通过 `xset q` 命令找到一个有效的字体目录。
|
||||
|
||||
```
|
||||
# mv PowerlineSymbols.otf /usr/share/fonts/
|
||||
```
|
||||
|
||||
接下来你需要通过如下命令更新你系统的字体缓存。
|
||||
|
||||
```
|
||||
# fc-cache -vf /usr/share/fonts/
|
||||
```
|
||||
|
||||
其次安装字体配置文件。
|
||||
|
||||
```
|
||||
# mv 10-powerline-symbols.conf /etc/fonts/conf.d/
|
||||
```
|
||||
|
||||
注意:如果相应的符号没有出现,可以尝试关闭终端会话并重启 X window,这样就会生效了。
|
||||
|
||||
### 第四步:给 Bash Shell 和 Vim 状态行设置 Powerline
|
||||
|
||||
在这一节将介绍 bash shell 和 vim 编辑器中关于 Powerline 的配置。首先通过在 `~/.bashrc` 中添加如下内容以便设置终端为 256 色。
|
||||
|
||||
```
|
||||
export TERM="screen-256color"
|
||||
```
|
||||
|
||||
#### 打开 Bash Shell 中的 Powerline
|
||||
|
||||
如果希望在 bash shell 中默认打开 Powerline,可以在 `~/.bashrc` 中添加如下内容。
|
||||
|
||||
首先通过如下命令获取 powerline 的安装位置。
|
||||
|
||||
```
|
||||
# pip show powerline-status
|
||||
Name: powerline-status
|
||||
Version: 2.2.dev9999-git.aa33599e3fb363ab7f2744ce95b7c6465eef7f08
|
||||
Location: /usr/local/lib/python2.7/dist-packages
|
||||
Requires:
|
||||
```
|
||||
|
||||
一旦找到 powerline 的具体位置后,根据你系统的情况替换到下列行中的 `/usr/local/lib/python2.7/dist-packages` 对应的位置。
|
||||
|
||||
```
|
||||
powerline-daemon -q
|
||||
POWERLINE_BASH_CONTINUATION=1
|
||||
POWERLINE_BASH_SELECT=1
|
||||
. /usr/local/lib/python2.7/dist-packages/powerline/bindings/bash/powerline.sh
|
||||
```
|
||||
|
||||
然后退出后重新登录,现在 powerline 的状态行应该如下显示了。
|
||||
|
||||
[
|
||||

|
||||
][6]
|
||||
|
||||
现在切换目录并注意显示你当前路径的面包屑导航提示的变化。
|
||||
|
||||
如果远程 Linux 服务器上安装了 powerline,你能看到后台挂起的任务,当你用 ssh 登录上去时,会看到该提示增加了主机名。
|
||||
|
||||
#### 在 Vim 中打开 Powerline
|
||||
|
||||
如果你喜欢使用 vim,正好有一个 vim 的强力插件。可以在 `~/.vimrc` 中添加如下内容打开该插件(LCTT 译注:注意同样需要根据你的系统情况修改路径)。
|
||||
|
||||
```
|
||||
set rtp+=/usr/local/lib/python2.7/dist-packages/powerline/bindings/vim/
|
||||
set laststatus=2
|
||||
set t_Co=256
|
||||
```
|
||||
|
||||
然后你打开 vim 后会看到一个新的状态行:
|
||||
|
||||
[
|
||||

|
||||
][7]
|
||||
|
||||
### 总结
|
||||
|
||||
Powerline 可以在某些软件中提供颜色鲜艳、很优美的状态行及提示内容,这对编程环境有利。希望这篇指南对您有帮助,如果您需要帮助或者有任何好的想法,请留言给我。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
作者简介:
|
||||
|
||||

|
||||
|
||||
我是Ravi Saive,TecMint的作者。一个喜欢分享诀窍和想法的电脑极客及Linux专家。我的大部分服务都运行在开源平台Linux中。关注我的Twitter,Facebook和Google+。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: http://www.tecmint.com/powerline-adds-powerful-statuslines-and-prompts-to-vim-and-bash/
|
||||
|
||||
作者:[Ravi Saive][a]
|
||||
译者:[beyondworld](https://github.com/beyondworld)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:http://www.tecmint.com/author/admin/
|
||||
[1]:http://www.tecmint.com/vi-editor-usage/
|
||||
[2]:http://www.tecmint.com/wp-content/uploads/2015/10/Install-Powerline-Statuslines-in-Linux.png
|
||||
[3]:http://www.tecmint.com/wp-content/uploads/2015/10/Powerline-Vim-Statuslines.png
|
||||
[4]:https://linux.cn/article-2324-1.html
|
||||
[5]:http://www.tecmint.com/10-wget-command-examples-in-linux/
|
||||
[6]:http://www.tecmint.com/wp-content/uploads/2015/10/Bash-Powerline-Statuslines.gif
|
||||
[7]:http://www.tecmint.com/wp-content/uploads/2015/10/Vim-Powerline-Statuslines.gif
|
@ -0,0 +1,212 @@
|
||||
3 个在 Linux 中永久并安全删除文件和目录的方法
|
||||
============================================================
|
||||
|
||||
在大多数情况下,我们习惯于使用 `Delete` 键、垃圾箱或 `rm` 命令[从我们的计算机中删除文件][1],但这不是永久安全地从硬盘中(或任何存储介质)删除文件的方法。
|
||||
|
||||
该文件只是对用户隐藏,它驻留在硬盘上的某个地方。它有可能被数据窃贼、执法取证或其它方式来恢复。
|
||||
|
||||
假设文件包含密级或机密内容,例如安全系统的用户名和密码,具有必要知识和技能的攻击者可以轻松地[恢复删除文件的副本][2]并访问这些用户凭证(你可以猜测到这种情况的后果)。
|
||||
|
||||
在本文中,我们将解释一些命令行工具,用于永久并安全地删除 Linux 中的文件。
|
||||
|
||||
### 1、 shred – 覆盖文件来隐藏内容
|
||||
|
||||
`shred` 会覆盖文件来隐藏它的内容,并且也可以选择删除它。
|
||||
|
||||
```
|
||||
$ shred -zvu -n 5 passwords.list
|
||||
```
|
||||
|
||||
在下面的命令中,选项有:
|
||||
|
||||
1. `-z` - 用零覆盖以隐藏碎片
|
||||
2. `-v` - 显示操作进度
|
||||
3. `-u` - 在覆盖后截断并删除文件
|
||||
4. `-n` - 指定覆盖文件内容的次数(默认值为3)
|
||||
|
||||
[
|
||||

|
||||
][3]
|
||||
|
||||
*shred - 覆盖文件来隐藏它的内容*
|
||||
|
||||
你可以在 `shred` 的帮助页中找到更多的用法选项和信息:
|
||||
|
||||
```
|
||||
$ man shred
|
||||
```
|
||||
|
||||
### 2、 wipe – 在 Linux 中安全删除文件
|
||||
|
||||
`wipe` 命令可以安全地擦除磁盘中的文件,从而不可能[恢复删除的文件或目录内容][4]。
|
||||
|
||||
首先,你需要安装 `wipe` 工具,运行以下适当的命令:
|
||||
|
||||
```
|
||||
$ sudo apt-get install wipe [Debian 及其衍生版]
|
||||
$ sudo yum install wipe [基于 RedHat 的系统]
|
||||
```
|
||||
|
||||
下面的命令会销毁 private 目录下的所有文件。
|
||||
|
||||
```
|
||||
$ wipe -rfi private/*
|
||||
```
|
||||
|
||||
当使用下面的标志时:
|
||||
|
||||
1. `-r` - 告诉 `wipe` 递归地擦除子目录
|
||||
2. `-f` - 启用强制删除并禁用确认查询
|
||||
3. `-i` - 显示擦除进度
|
||||
|
||||
[
|
||||

|
||||
][5]
|
||||
|
||||
*wipe – 在 Linux 中安全擦除文件*
|
||||
|
||||
注意:`wipe` 仅可以在磁性存储上可以可靠地工作,因此对固态磁盘(内存)请使用其他方法。
|
||||
|
||||
阅读 `wipe` 手册以获取其他使用选项和说明:
|
||||
|
||||
```
|
||||
$ man wipe
|
||||
```
|
||||
|
||||
### 3、 Linux 中的安全删除工具集
|
||||
|
||||
secure-delete 是一个安全文件删除工具的集合,它包含用于安全删除文件的 `srm`(secure_deletion)工具。
|
||||
|
||||
首先,你需要使用以下相关命令安装它:
|
||||
|
||||
```
|
||||
$ sudo apt-get install secure-delete [On Debian and its derivatives]
|
||||
$ sudo yum install secure-delete [On RedHat based systems]
|
||||
```
|
||||
|
||||
安装完成后,你可以使用 `srm` 工具在 Linux 中安全地删除文件和目录。
|
||||
|
||||
```
|
||||
$ srm -vz private/*
|
||||
```
|
||||
|
||||
下面是使用的选项:
|
||||
|
||||
1. `-v` – 启用 verbose 模式
|
||||
2. `-z` – 用0而不是随机数据来擦除最后的写入
|
||||
|
||||
[
|
||||

|
||||
][6]
|
||||
|
||||
*srm – 在 Linux 中安全删除文件*
|
||||
|
||||
阅读 srm 手册来获取更多的使用选项和信息:
|
||||
|
||||
```
|
||||
$ man srm
|
||||
```
|
||||
|
||||
### 4、 sfill -安全免费的磁盘 / inode 空间擦除器
|
||||
|
||||
`sfill` 是 secure-deletetion 工具包的一部分,是一个安全免费的磁盘和 inode 空间擦除器,它以安全的方法删除可用磁盘空间中的文件。 `sfill` 会[检查指定分区上的可用空间][7],并使用来自 `/dev/urandom` 的随机数据填充它。
|
||||
|
||||
以下命令将在我的根分区上执行 `sfill`,使用 `-v' 选项启用 verbose 模式:
|
||||
|
||||
```
|
||||
$ sudo sfill -v /home/aaronkilik/tmp/
|
||||
```
|
||||
|
||||
假设你创建了一个单独的分区 `/home` 来存储正常的系统用户主目录,你可以在该分区上指定一个目录,以便在其上应用 `sfill`:
|
||||
|
||||
```
|
||||
$ sudo sfill -v /home/username
|
||||
```
|
||||
|
||||
你可以在 sfill 的手册上看到一些限制,你也可以看到额外的使用标志和命令:
|
||||
|
||||
```
|
||||
$ man sfill
|
||||
```
|
||||
|
||||
注意:secure-deletetion 工具包中的另外两个工具(`sswap` 和 `sdmem`)与本指南的范围不直接相关,但是,为了将来的使用和传播知识的目的,我们会在下面介绍它们。
|
||||
|
||||
### 5、 sswap – 安全 swap 擦除器
|
||||
|
||||
它是一个安全的分区擦除器,`sswap` 以安全的方式删除 swap 分区上存在的数据。
|
||||
|
||||
警告:请记住在使用 `sswap` 之前卸载 swap 分区! 否则你的系统可能会崩溃!
|
||||
|
||||
要找到交换分区(并检查分页和交换设备/文件是否已经使用,请使用 `swapon` 命令),接下来,使用 `swapoff` 命令禁用分页和交换设备/文件(使 swap 分区不可用)。
|
||||
|
||||
然后在(关闭的) swap 分区上运行 `sswap` 命令:
|
||||
|
||||
```
|
||||
$ cat /proc/swaps
|
||||
$ swapon
|
||||
$ sudo swapoff /dev/sda6
|
||||
$ sudo sswap /dev/sda6 #this command may take some time to complete with 38 default passes
|
||||
```
|
||||
|
||||
[
|
||||

|
||||
][8]
|
||||
|
||||
*sswap – 安全 swap 擦除器*
|
||||
|
||||
阅读 `sswap` 的手册来获取更多的选项和信息:
|
||||
|
||||
```
|
||||
$ man sswap
|
||||
```
|
||||
|
||||
### 6、 sdmem – 安全内存擦除器
|
||||
|
||||
`sdmem` 是一个安全的内存擦除器,其设计目的是以安全的方式删除存储器(RAM)中的数据。
|
||||
|
||||
它最初命名为 [smem][9],但是因为在 Debain 系统上存在另一个包 [smem - 报告每个进程和每个用户的内存消耗][10],开发人员决定将它重命名为 `sdmem`。
|
||||
|
||||
```
|
||||
$ sudo sdmem -f -v
|
||||
```
|
||||
|
||||
关于更多的使用信息,阅读 `sdmen` 的手册:
|
||||
|
||||
```
|
||||
$ man sdmem
|
||||
```
|
||||
|
||||
**推荐阅读:** [在 Linux 系统下使用 PhotoRec & TestDisk 工具来恢复文件][11]。
|
||||
|
||||
就是这样了!在本文中,我们查看了一系列可以永久安全地删除 Linux 中的文件的工具。像往常一样,通过下面的评论栏发表你对本篇文章的想法或建议。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
作者简介:
|
||||
|
||||

|
||||
|
||||
Aaron Kili 是一个 Linux 系统及 F.O.S.S 爱好者,即将成为一名系统管理员及 Web 开发人员,他现在是 TecMint 网站的内容创建者,他喜欢使用电脑来工作,并且他坚信分享知识是一种美德。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: http://www.tecmint.com/permanently-and-securely-delete-files-directories-linux/
|
||||
|
||||
作者:[Aaron Kili][a]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[jasminepeng](https://github.com/jasminepeng)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:http://www.tecmint.com/author/admin/
|
||||
[1]:https://linux.cn/article-7954-1.html
|
||||
[2]:https://linux.cn/article-8122-1.html
|
||||
[3]:http://www.tecmint.com/wp-content/uploads/2017/01/shred-command-example.png
|
||||
[4]:https://linux.cn/article-7974-1.html
|
||||
[5]:http://www.tecmint.com/wp-content/uploads/2017/01/Wipe-Securely-Erase-Files.png
|
||||
[6]:http://www.tecmint.com/wp-content/uploads/2017/01/srm-securely-delete-Files-in-Linux.png
|
||||
[7]:https://linux.cn/article-8024-1.html
|
||||
[8]:http://www.tecmint.com/wp-content/uploads/2017/01/sswap-Secure-Swap-Wiper.png
|
||||
[9]:https://linux.cn/article-7681-1.html
|
||||
[10]:https://linux.cn/article-7681-1.html
|
||||
[11]:https://linux.cn/article-8122-1.html
|
62
published/20160823 Getting Started with HTTP2 - Part 1.md
Normal file
62
published/20160823 Getting Started with HTTP2 - Part 1.md
Normal file
@ -0,0 +1,62 @@
|
||||
初识 HTTP/2(一)
|
||||
============================================================
|
||||

|
||||
|
||||
> 用披萨来说明当你订单数很大的时候 HTTP/2 是怎么打败 HTTP/1.1 的。
|
||||
|
||||
在建立网站和应用的方式上 HTTP/2 有些令人惊叹的改变,在 HTTP/2 发布后的一年半,几乎 [10% 的网站使用了 HTTP/2][4]。它绝对值得采用,但是这篇文章应该首先推给使用 HTTP/2 的前端开发者。这个连载的文章是指导前端开发者怎么转换到 HTTP/2。
|
||||
|
||||
本文涵盖了 HTTP/2 对 HTTP/1.1 来说有什么提高的内容,并且向前端开发者介绍了 HTTP/2。
|
||||
|
||||
### 再次让我想起什么是 HTTP ...
|
||||
|
||||
超文本传输协议,也就是 HTTP,这个协议决定了 web 内容怎么传输。HTTP/1.1 在 1999 年被标准化,那时候的 web 和现在有很大的不同,表格霸占了整个网络。样式通常被内联在元素中,如果网站管理员更加的细致,他们会在头部写个 `<style>`标签。 JavaScript 也被丢在文档里面,那时候完整的网站通常也不会超过几页。
|
||||
|
||||
HTTP/1.1 预计这种情况会持续一段时间,所以它并没有太过关注在让一个站点可以加载大量的资源方面,因为那时候的开发者并不需要这个。因此它使用了一个非常简单的方式来处理资源,你访问一个资源然后服务器去寻找它,并且返回你访问的资源,或者告诉你这个资源不存在。这种被叫作"线头堵塞"方式非常高效,但是当你需要多个资源的时候,这个进程会依次寻找每个资源。这意味着在你访问第二个资源之前,服务器必须找到你访问的第一个资源并且载入它,或者告诉你没找到。
|
||||
|
||||
### 大型站点的发展
|
||||
|
||||
在 1999 年之后的几年里,随着 php 和其他像 Rails 这样的动态语言的崛起,站点变得越来越复杂。css 文件也随着向响应式开发的转变而变的越来越大,因此像 Sass 这样的可以创造一个简单的工作环境的 CSS 编译器就应运而生。 JavaScript 也在 web 上有了更大的作用,它允许开发者编写复杂的应用,这曾经只是 C++ 开发人员的工作。随着 Retina 和高清显示屏的兴起,也让图片变得更高清。随着这些改变,文件大小呈现指数式的增长,使得本来是等待几个字节的资源变成了加载几千字节,甚至在某些情况下有几兆。当你开始载入页面的其它东西前,必须先载入数百 K 的东西,你只能乐观的假设你的用户有很快的网络接入。
|
||||
|
||||
想象 HTTP/1.1 是个过去的那种柜台购买式的街旁披萨店。你能自己过去并且预定一个雪碧和 2 片 Angry Hawaiian ,然后等待 3 分钟。他们可以很容易地处理这些,实际上这是一个蓬勃发展的商业模式-定单简单、处理迅速。
|
||||
|
||||

|
||||
|
||||
然而,一旦你决定在同样的披萨店主办一场小区域的季度颁奖典礼,事情就变的更复杂了。每个人都预定不同的东西,快速而杂乱无章让等待时间直线上升。
|
||||
|
||||

|
||||
|
||||
### 哪里是 HTTP/2 的舞台
|
||||
|
||||
HTTP/2 对前端开发者主要的承诺就是复用。意思就是资源请求能发生在同一时间,并且服务器能马上响应这些资源。在请求之间没有等待,因为它们发生在同一时间。
|
||||
|
||||
使用同样的比喻,HTTP/2 允许披萨店在餐馆他们自己区域举办派对。派一个服务员接受订单,并把所有已经准备好的订单交付。当其他人的比萨在制作的时候,你也不需要花 30 分钟去等待你的雪碧,它们在第一批交付的东西之中。这方式使得管理大量订单更加简单,并且防止人们等他们的订单时间太长。
|
||||
|
||||
复用带给我们的 web 开发的大变化是改变了文件的加载方式。帮助绕过资源加载的 HTTP/1.1 瓶颈的方式是通过连接和压缩需要被加载的文件。所有任务运行器都默认采取这样的操作方式,或者需要作一点小设置就行。和过去一样,开发人员可以将图像放在精灵拼图(sprite sheets)中,这会减少了对服务器的请求数。
|
||||
|
||||
### 改进 HTTP/1.1
|
||||
|
||||
将文件连接起来是个处理 HTTP1.1 的请求限制问题的非常聪明的方式,但是连接文件的主要问题是它要求用户第一次访问整个网站时下载所有的资源。一旦它们载入后,浏览器就会缓存所有的资源。这能提高用户每次访问网页时的速度,但是前期负载很重,对[跳出率不利][5]。此外,他们可能为所不访问的页面加载资源。期望用户访问每个页面以查看每个样式,并与每个脚本进行交互是不现实的。此外,在加拿大和欧洲以及几乎每个美国移动提供商的地方,有每月的带宽上限。不是加载额外的 54 千字节的内容就会超过每月的流量限制,而是让我们假设用户想保留这些额外的流量看 Taylor Swift 的 gif。
|
||||
|
||||
使用 HTTP/2 和多路复用,您可以开发一些最高效的网站,但它需要一些重新思考、甚至撤销之前的最佳做法。重复一次,我的目的是加快 HTTP/2 的会话,使用我们新的工具,我们可以发现这些新的最佳的做法。
|
||||
|
||||
在我的下一篇文章,[我将探索建设基于 HTTP/2 的网站的一些最好方式][6]。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.viget.com/articles/getting-started-with-http-2-part-1?imm_mid=0eb24a&cmp=em-web-na-na-newsltr_20161130
|
||||
|
||||
作者:[Ben][a]
|
||||
译者:[hkurj](https://github.com/hkurj)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 组织编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://www.viget.com/about/team/btinsley
|
||||
[1]:https://twitter.com/home?status=Using%20pizza%20to%20show%20how%20HTTP%2F2%20beats%20HTTP%2F1.1%20when%20your%20orders%20get%20too%20big.%20https%3A%2F%2Fwww.viget.com%2Farticles%2Fgetting-started-with-http-2-part-1
|
||||
[2]:https://www.facebook.com/sharer/sharer.php?u=https%3A%2F%2Fwww.viget.com%2Farticles%2Fgetting-started-with-http-2-part-1
|
||||
[3]:http://www.linkedin.com/shareArticle?mini=true&url=https%3A%2F%2Fwww.viget.com%2Farticles%2Fgetting-started-with-http-2-part-1
|
||||
[4]:https://w3techs.com/technologies/details/ce-http2/all/all
|
||||
[5]:https://blog.kissmetrics.com/speed-is-a-killer/
|
||||
[6]:https://www.viget.com/articles/getting-started-with-http-2-part-2
|
||||
[7]:https://www.viget.com/about/team/btinsley
|
@ -0,0 +1,276 @@
|
||||
忘记技术债务 —— 教你如何创造技术财富
|
||||
===============
|
||||
|
||||
电视里正播放着《老屋》节目,[Andrea Goulet][58] 和她的商业合作伙伴正悠闲地坐在客厅里,商讨着他们的战略计划。那正是大家思想的火花碰撞出创新事物的时刻。他们正在寻求一种能够实现自身价值的方式 —— 为其它公司清理<ruby>遗留代码<rt>legacy code</rt></ruby>及科技债务。他们此刻的情景,像极了电视里的场景。(LCTT 译注:《老屋》电视节目提供专业的家装、家庭改建、重新装饰、创意等等信息,与软件的改造有异曲同工之处)。
|
||||
|
||||
“我们意识到我们现在做的工作不仅仅是清理遗留代码,实际上我们是在用重建老屋的方式来重构软件,让系统运行更持久、更稳定、更高效,”Goulet 说。“这让我开始思考公司如何花钱来改善他们的代码,以便让他们的系统运行更高效。就好比为了让屋子变得更有价值,你不得不使用一个全新的屋顶。这并不吸引人,但却是至关重要的,然而很多人都搞错了。“
|
||||
|
||||
如今,她是 [Corgibytes][57] 公司的 CEO —— 这是一家提高软件现代化和进行系统重构方面的咨询公司。她曾经见过各种各样糟糕的系统、遗留代码,以及严重的科技债务事件。Goulet 认为**创业公司需要转变思维模式,不是偿还债务,而是创造科技财富,不是要铲除旧代码,而是要逐步修复代码**。她解释了这种新的方法,以及如何完成这些看似不可能完成的事情 —— 实际上是聘用优秀的工程师来完成这些工作。
|
||||
|
||||
### 反思遗留代码
|
||||
|
||||
关于遗留代码最常见的定义是由 Michael Feathers 在他的著作[<ruby>《高效利用遗留代码》<rt>Working Effectively with Legacy Code</rt></ruby>][56]一书中提出:遗留代码就是没有被测试所覆盖的代码。这个定义比大多数人所认为的 —— 遗留代码仅指那些古老、陈旧的系统这个说法要妥当得多。但是 Goulet 认为这两种定义都不够明确。“遗留代码与软件的年头儿毫无关系。一个两年的应用程序,其代码可能已经进入遗留状态了,”她说。“**关键要看软件质量提高的难易程度。**”
|
||||
|
||||
这意味着写得不够清楚、缺少解释说明的代码,是没有包含任何关于代码构思和决策制定的流程的成果。单元测试就是这样的一种成果,但它并没有包括了写那部分代码的原因以及逻辑推理相关的所有文档。如果想要提升代码,但没办法搞清楚原开发者的意图 —— 那些代码就属于遗留代码了。
|
||||
|
||||
> **遗留代码不是技术问题,而是沟通上的问题。**
|
||||
|
||||

|
||||
|
||||
如果你像 Goulet 所说的那样迷失在遗留代码里,你会发现每一次的沟通交流过程都会变得像那条[<ruby>康威定律<rt>Conway’s Law</rt></ruby>][54]所描述的一样。
|
||||
|
||||
Goulet 说:“这个定律认为你的代码能反映出整个公司的组织沟通结构,如果想修复公司的遗留代码,而没有一个好的组织沟通方式是不可能完成的。那是很多人都没注意到的一个重要环节。”
|
||||
|
||||
Goulet 和她的团队成员更像是考古学家一样来研究遗留系统项目。他们根据前开发者写的代码构件相关的线索来推断出他们的思想意图。然后再根据这些构件之间的关系来做出新的决策。
|
||||
|
||||
代码构件最重要的什么呢?**良好的代码结构、清晰的思想意图、整洁的代码**。例如,如果使用通用的名称如 “foo” 或 “bar” 来命名一个变量,半年后再返回来看这段代码时,根本就看不出这个变量的用途是什么。
|
||||
|
||||
如果代码读起来很困难,可以使用源代码控制系统,这是一个非常有用的工具,因为它可以提供代码的历史修改信息,并允许软件开发者写明他们作出本次修改的原因。
|
||||
|
||||
Goulet 说:“我一个朋友认为提交代码时附带的信息,每一个概要部分的内容应该有半条推文那么长(几十个字),如需要的话,代码的描述信息应该有一篇博客那么长。你得用这个方式来为你修改的代码写一个合理的说明。这不会浪费太多额外的时间,并且能给后期的项目开发者提供非常多的有用信息,但是让人惊讶的是很少有人会这么做。我们经常能看到一些开发人员在被一段代码激怒之后,要用 `git blame` 扒代码库找出这些垃圾是谁干的,结果最后发现是他们自己干的。”
|
||||
|
||||
使用自动化测试对于理解程序的流程非常有用。Goulet 解释道:“很多人都比较认可 Michael Feathers 提出的关于遗留代码的定义。测试套件对于理解开发者的意图来说是非常有用的工具,尤其当用来与[<ruby>行为驱动开发模式<rt>Behavior Driven Development</rt></ruby>][53]相结合时,比如编写测试场景。”
|
||||
|
||||
理由很简单,如果你想将遗留代码限制在一定程度下,注意到这些细节将使代码更易于理解,便于在以后也能工作。编写并运行一个代码单元,接受、认可,并且集成测试。写清楚注释的内容,方便以后你自己或是别人来理解你写的代码。
|
||||
|
||||
尽管如此,由于很多已知的和不可意料的原因,遗留代码仍然会出现。
|
||||
|
||||
在创业公司刚成立初期,公司经常会急于推出很多新的功能。开发人员在巨大的交付压力下,测试常常半途而废。Corgibytes 团队就遇到过好多公司很多年都懒得对系统做详细的测试了。
|
||||
|
||||
确实如此,当你急于开发出系统原型的时候,强制性地去做太多的测试也许意义不大。但是,一旦产品开发完成并投入使用后,你就需要投入时间精力来维护及完善系统了。Goulet 说:“很多人说,‘别在维护上费心思,重要的是功能!’ **如果真这样,当系统规模到一定程序的时候,就很难再扩展了。同时也就失去市场竞争力了。**”
|
||||
|
||||
最后才明白过来,原来热力学第二定律对代码也同样适用:**你所面临的一切将向熵增的方向发展。**你需要与混乱无序的技术债务进行一场无休无止的战斗。随着时间的推移,遗留代码也逐渐变成一种债务。
|
||||
|
||||
她说:“我们再次拿家来做比喻。你必须坚持每天收拾餐具、打扫卫生、倒垃圾。如果你不这么做,情况将来越来越糟糕,直到有一天你不得不向 HazMat 团队求助。”(LCTT 译注:HazMat 团队,危害物质专队)
|
||||
|
||||
就跟这种情况一样,Corgibytes 团队接到很多公司 CEO 的求助电话,比如 Features 公司的 CEO 在电话里抱怨道:“现在我们公司的开发团队工作效率太低了,三年前只需要两个星期就完成的工作,现在却要花费12个星期。”
|
||||
|
||||
> **技术债务往往反映出公司运作上的问题。**
|
||||
|
||||
很多公司的 CTO 明知会发生技术债务的问题,但是他们很难说服其它同事相信花钱来修复那些已经存在的问题是值得的。这看起来像是在走回头路,很乏味,也不是新的产品。有些公司直到系统已经严重影响了日常工作效率时,才着手去处理这些技术债务方面的问题,那时付出的代价就太高了。
|
||||
|
||||
### 忘记债务,创造技术财富
|
||||
|
||||
如果你想把[<ruby>重构技术债务<rt>reframe your technical debt</rt></ruby>][52] — [敏捷开发讲师 Declan Whelan 最近造出的一个术语][51] — 作为一个积累技术财富的机会,你很可能要先说服你们公司的 CEO、投资者和其它的股东接受并为之共同努力。
|
||||
|
||||
“我们没必要把技术债务想像得很可怕。当产品处于开发设计初期,技术债务反而变得非常有用,”Goulet 说。“当你解决一些系统遗留的技术问题时,你会充满成就感。例如,当你在自己家里安装新窗户时,你确实会花费一笔不少的钱,但是之后你每个月就可以节省 100 美元的电费。程序代码亦是如此。虽然暂时没有提高工作效率,但随时时间推移将提高生产力。”
|
||||
|
||||
一旦你意识到项目团队工作不再富有成效时,就需要确认下是哪些技术债务在拖后腿了。
|
||||
|
||||
“我跟很多不惜一切代价招募英才的初创公司交流过,他们高薪聘请一些工程师来只为了完成更多的工作。”她说。“与此相反,他们应该找出如何让原有的每个工程师能更高效率工作的方法。你需要去解决什么样的技术债务以增加额外的生产率?”
|
||||
|
||||
如果你改变自己的观点并且专注于创造技术财富,你将会看到产能过剩的现象,然后重新把多余的产能投入到修复更多的技术债务和遗留代码的良性循环中。你们的产品将会走得更远,发展得更好。
|
||||
|
||||
> **别把你们公司的软件当作一个项目来看。从现在起,把它想象成一栋自己要长久居住的房子。**
|
||||
|
||||
“这是一个极其重要的思想观念的转变,”Goulet 说。“这将带你走出短浅的思维模式,并让你比之前更加关注产品的维护工作。”
|
||||
|
||||
这就像对一栋房子,要实现其现代化及维护的方式有两种:小动作,表面上的更改(“我买了一块新的小地毯!”)和大改造,需要很多年才能偿还所有债务(“我想我们应替换掉所有的管道...”)。你必须考虑好两者,才能让你们已有的产品和整个团队顺利地运作起来。
|
||||
|
||||
这还需要提前预算好 —— 否则那些较大的花销将会是硬伤。定期维护是最基本的预期费用。让人震惊的是,很多公司都没把维护当成商务成本预算进来。
|
||||
|
||||
这就是 Goulet 提出“**<ruby>软件重构<rt>software remodeling</rt></ruby>**”这个术语的原因。当你房子里的一些东西损坏的时候,你并不是铲除整个房子,从头开始重建。同样的,当你们公司出现老的、损坏的代码时,重写代码通常不是最明智的选择。
|
||||
|
||||
下面是 Corgibytes 公司在重构客户代码用到的一些方法:
|
||||
|
||||
* 把大型的应用系统分解成轻量级的更易于维护的微服务。
|
||||
* 让功能模块彼此解耦以便于扩展。
|
||||
* 更新形象和提升用户前端界面体验。
|
||||
* 集合自动化测试来检查代码可用性。
|
||||
* 代码库可以让重构或者修改更易于操作。
|
||||
|
||||
系统重构也进入到 DevOps 领域。比如,Corgibytes 公司经常推荐新客户使用 [Docker][50],以便简单快速的部署新的开发环境。当你们团队有 30 个工程师的时候,把初始化配置时间从 10 小时减少到 10 分钟对完成更多的工作很有帮助。系统重构不仅仅是应用于软件开发本身,也包括如何进行系统重构。
|
||||
|
||||
如果你知道做些什么能让你们的代码管理起来更容易更高效,就应该把这它们写入到每年或季度的项目规划中。别指望它们会自动呈现出来。但是也别给自己太大的压力来马上实施它们。Goulets 看到很多公司从一开始就致力于 100% 测试覆盖率而陷入困境。
|
||||
|
||||
**具体来说,每个公司都应该把以下三种类型的重构工作规划到项目建设中来:**
|
||||
|
||||
* 自动测试
|
||||
* 持续交付
|
||||
* 文化提升
|
||||
|
||||
咱们来深入的了解下每一项内容。
|
||||
|
||||
#### 自动测试
|
||||
|
||||
“有一位客户即将进行第二轮融资,但是他们没办法在短期内招聘到足够的人才。我们帮助他们引进了一种自动化测试框架,这让他们的团队在 3 个月的时间内工作效率翻了一倍,”Goulets 说。“这样他们就可以在他们的投资人面前自豪的说,‘我们一个精英团队完成的任务比两个普通的团队要多。’”
|
||||
|
||||
自动化测试从根本上来讲就是单个测试的组合,就是可以再次检查某一行代码的单元测试。可以使用集成测试来确保系统的不同部分都正常运行。还可以使用验收性测试来检验系统的功能特性是否跟你想像的一样。当你把这些测试写成测试脚本后,你只需要简单地用鼠标点一下按钮就可以让系统自行检验了,而不用手工的去梳理并检查每一项功能。
|
||||
|
||||
在产品市场尚未打开之前就来制定自动化测试机制有些言之过早。但是一旦你有一款感到满意,并且客户也很依赖的产品,就应该把这件事付诸实施了。
|
||||
|
||||
#### 持续交付
|
||||
|
||||
这是与自动化交付相关的工作,过去是需要人工完成。目的是当系统部分修改完成时可以迅速进行部署,并且短期内得到反馈。这使公司在其它竞争对手面前有很大的优势,尤其是在客户服务行业。
|
||||
|
||||
“比如说你每次部署系统时环境都很复杂。熵值无法有效控制,”Goulets 说。“我们曾经见过花 12 个小时甚至更多的时间来部署一个很大的集群环境。在这种情况下,你不会愿意频繁部署了。因为太折腾人了,你还会推迟系统功能上线的时间。这样,你将落后于其它公司并失去竞争力。”
|
||||
|
||||
**在持续性改进的过程中常见的其它自动化任务包括:**
|
||||
|
||||
* 在提交完成之后检查构建中断部分。
|
||||
* 在出现故障时进行回滚操作。
|
||||
* 自动化审查代码的质量。
|
||||
* 根据需求增加或减少服务器硬件资源。
|
||||
* 让开发、测试及生产环境配置简单易懂。
|
||||
|
||||
举一个简单的例子,比如说一个客户提交了一个系统 Bug 报告。开发团队越高效解决并修复那个 Bug 越好。对于开发人员来说,修复 Bug 的挑战根本不是个事儿,这本来也是他们的强项,主要是系统设置上不够完善导致他们浪费太多的时间去处理 bug 以外的其它问题。
|
||||
|
||||
使用持续改进的方式时,你要严肃地决定决定哪些工作应该让机器去做,哪些交给研发去完成更好。如果机器更擅长,那就使其自动化完成。这样也能让研发愉快地去解决其它有挑战性的问题。同时客户也会很高兴地看到他们报怨的问题被快速处理了。你的待修复的未完成任务数减少了,之后你就可以把更多的时间投入到运用新的方法来提高产品的质量上了。**这是创造科技财富的一种转变。**因为开发人员可以修复 bug 后立即发布新代码,这样他们就有时间和精力做更多事。
|
||||
|
||||
“你必须时刻问自己,‘我应该如何为我们的客户改善产品功能?如何做得更好?如何让产品运行更高效?’不过还要不止于此。”Goulets 说。“一旦你回答完这些问题后,你就得询问下自己,如何自动去完成那些需要改善的功能。”
|
||||
|
||||
#### 文化提升
|
||||
|
||||
Corgibytes 公司每天都会看到同样的问题:一家创业公司建立了一个对开发团队毫无推动的文化环境。公司 CEO 抱着双臂思考着为什么这样的环境对员工没多少改变。然而事实却是公司的企业文化对工作并不利。为了激励工程师,你必须全面地了解他们的工作环境。
|
||||
|
||||
为了证明这一点,Goulet 引用了作者 Robert Henry 说过的一段话:
|
||||
|
||||
> **目的不是创造艺术,而是在最美妙的状态下让艺术应运而生。**
|
||||
|
||||
“你们也要开始这样思考一下你们的软件,”她说。“你们的企业文件就类似那个状态。你们的目标就是创造一个让艺术品应运而生的环境,这件艺术品就是你们公司的代码、一流的售后服务、充满幸福感的开发者、良好的市场预期、盈利能力等等。这些都息息相关。”
|
||||
|
||||
优先考虑解决公司的技术债务和遗留代码也是一种文化。那是真正为开发团队清除障碍,以制造影响的方法。同时,这也会让你将来有更多的时间精力去完成更重要的工作。如果你不从根本上改变固有的企业文化环境,你就不可能重构公司产品。改变对产品维护及现代化的投资的态度是开始实施变革的第一步,最理想情况是从公司的 CEO 开始自顶向下转变。
|
||||
|
||||
以下是 Goulet 关于建立那种流态文化方面提出的建议:
|
||||
|
||||
* 反对公司嘉奖那些加班到深夜的“英雄”。提倡高效率的工作方式。
|
||||
* 了解协同开发技术,比如 Woody Zuill 提出的[<ruby>合作编程<rt>Mob Programming</rt></ruby>][44]模式。
|
||||
* 遵从 4 个[现代敏捷开发][42]原则:用户至上、实践及快速学习、把安全放在首位、持续交付价值。
|
||||
* 每周为研发人员提供项目外的职业发展时间。
|
||||
* 把[日工作记录][43]作为一种驱动开发团队主动解决问题的方式。
|
||||
* 把同情心放在第一位。Corgibytes 公司让员工参加 [Brene Brown 勇气工厂][40]的培训是非常有用的。
|
||||
|
||||
“如果公司高管和投资者不支持这种升级方式,你得从客户服务的角度去说服他们,”Goulet 说,“告诉他们通过这次调整后,最终产品将如何给公司的大多数客户提高更好的体验。这是你能做的一个很有力的论点。”
|
||||
|
||||
### 寻找最具天才的代码重构者
|
||||
|
||||
整个行业都认为顶尖的工程师不愿意干修复遗留代码的工作。他们只想着去开发新的东西。大家都说把他们留在维护部门真是太浪费人才了。
|
||||
|
||||
**其实这些都是误解。如果你知道去哪里和如何找工程师,并为他们提供一个愉快的工作环境,你就可以找到技术非常精湛的工程师,来帮你解决那些最棘手的技术债务问题。**
|
||||
|
||||
“每次在会议上,我们都会问现场的同事‘谁喜欢去在遗留代码上工作?’每次只有不到 10% 的与会者会举手。”Goulet 说。“但是我跟这些人交流后,我发现这些工程师恰好是喜欢最具挑战性工作的人才。”
|
||||
|
||||
有一位客户来寻求她的帮助,他们使用国产的数据库,没有任何相关文档,也没有一种有效的方法来弄清楚他们公司的产品架构。她称修理这种情况的一类工程师为“修正者”。在 Corgibytes 公司,她有一支这样的修正者团队由她支配,热衷于通过研究二进制代码来解决技术问题。
|
||||
|
||||

|
||||
|
||||
那么,如何才能找到这些技术人才呢? Goulet 尝试过各种各样的方法,其中有一些方法还是富有成效的。
|
||||
|
||||
她创办了一个社区网站 [legacycode.rocks][49] 并且在招聘启示上写道:“长期招聘那些喜欢重构遗留代码的另类开发人员...如果你以从事处理遗留代码的工作为自豪,欢迎加入!”
|
||||
|
||||
“我开始收到很多人发来邮件说,‘噢,天呐,我也属于这样的开发人员!’”她说。“只需要发布这条信息,并且告诉他们这份工作是非常有意义的,就吸引了合适的人才。”
|
||||
|
||||
在招聘的过程中,她也会使用持续性交付的经验来回答那些另类开发者想知道的信息:包括详细的工作内容以及明确的要求。“我这么做的原因是因为我讨厌重复性工作。如果我收到多封邮件来咨询同一个问题,我会把答案发布在网上,我感觉自己更像是在写说明文档一样。”
|
||||
|
||||
但是随着时间的推移,她发现可以重新定义招聘流程来帮助她识别出更出色的候选人。比如说,她在应聘要求中写道,“公司 CEO 将会重新审查你的简历,因此请确保求职信中致意时不用写明性别。所有以‘尊敬的先生’或‘先生’开头的信件将会被当垃圾处理掉”。这些只是她的招聘初期策略。
|
||||
|
||||
“我开始这么做是因为很多申请人把我当成男性,因为我是一家软件公司的男性 CEO,我必须是男性!?”Goulet 说。“所以,有一天我想我应该它当作应聘要求放到网上,看有多少人注意到这个问题。令我惊讶的是,这让我过滤掉一些不太严谨的申请人。还突显出了很多擅于从事遗留代码方面工作的人。”
|
||||
|
||||
Goulet 想起一个应聘者发邮件给我说,“我查看了你们网站的代码(我喜欢这个网站,这也是我的工作)。你们的网站架构很奇特,好像是用 PHP 写的,但是你们却运行在用 Ruby 语言写的 Jekyll 下。我真的很好奇那是什么呢。”
|
||||
|
||||
Goulet 从她的设计师那里得知,原来,在 HTML、CSS 和 JavaScript 文件中有一个未使用的 PHP 类名,她一直想解决这个问题,但是一直没机会。Goulet 的回复是:“你正在找工作吗?”
|
||||
|
||||
另外一名候选人注意到她曾经在一篇说明文档中使用 CTO 这个词,但是她的团队里并没有这个头衔(她的合作伙伴是 Chief Code Whisperer)。这些注重细节、充满求知欲、积极主动的候选者更能引起她的注意。
|
||||
|
||||
> **代码修正者不仅需要注重细节,而且这也是他们必备的品质。**
|
||||
|
||||
让人吃惊的是,Goulet 从来没有为招募最优秀的代码修正者而感到厌烦过。“大多数人都是通过我们的网站直接投递简历,但是当我们想扩大招聘范围的时候,我们会通过 [PowerToFly][48] 和 [WeWorkRemotely][47] 网站进行招聘。我现在确实不需要招募新人马了。他们需要经历一段很艰难的时期才能理解代码修正者的意义是什么。”
|
||||
|
||||
如果他们通过首轮面试,Goulet 将会让候选者阅读一篇 Arlo Belshee 写的文章“[<ruby>命名是一个过程<rt>Naming is a Process</rt></ruby>][46]”。它讲的是非常详细的处理遗留代码的的过程。她最经典的指导方法是:“阅读完这段代码并且告诉我,你是怎么理解的。”
|
||||
|
||||
她将找出对问题的理解很深刻并且也愿意接受文章里提出的观点的候选者。这对于区分有深刻理解的候选者和仅仅想获得工作的候选者来说,是极其有用的办法。她强烈要求候选者找出一段与他操作相关的代码,来证明他是充满激情的、有主见的及善于分析问题的人。
|
||||
|
||||
最后,她会让候选者跟公司里当前的团队成员一起使用 [Exercism.io][45] 工具进行编程。这是一个开源项目,它允许开发者学习如何在不同的编程语言环境下使用一系列的测试驱动开发的练习进行编程。结对编程课程的第一部分允许候选者选择其中一种语言来使用。下一个练习中,面试官可以选择一种语言进行编程。他们总能看到那些人处理异常的方法、随机应便的能力以及是否愿意承认某些自己不了解的技术。
|
||||
|
||||
“当一个人真正的从执业者转变为大师的时候,他会毫不犹豫的承认自己不知道的东西,”Goulet说。
|
||||
|
||||
让他们使用自己不熟悉的编程语言来写代码,也能衡量其坚韧不拔的毅力。“我们想听到某个人说,‘我会深入研究这个问题直到彻底解决它。’也许第二天他们仍然会跑过来跟我们说,‘我会一直留着这个问题直到我找到答案为止。’那是作为一个成功的修正者表现出来的一种气质。”
|
||||
|
||||
> **产品开发人员在我们这个行业很受追捧,因此很多公司也想让他们来做维护工作。这是一个误解。最优秀的维护修正者并不是最好的产品开发工程师。**
|
||||
|
||||
如果一个有天赋的修正者在眼前,Goulet 懂得如何让他走向成功。下面是如何让这种类型的开发者感到幸福及高效工作的一些方式:
|
||||
|
||||
* 给他们高度的自主权。把问题解释清楚,然后安排他们去完成,但是永不命令他们应该如何去解决问题。
|
||||
* 如果他们要求升级他们的电脑配置和相关工具,尽管去满足他们。他们明白什么样的需求才能最大限度地提高工作效率。
|
||||
* 帮助他们[避免分心][39]。他们喜欢全身心投入到某一个任务直至完成。
|
||||
|
||||
总之,这些方法已经帮助 Corgibytes 公司培养出二十几位对遗留代码充满激情的专业开发者。
|
||||
|
||||
### 稳定期没什么不好
|
||||
|
||||
大多数创业公司都都不想跳过他们的成长期。一些公司甚至认为成长期应该是永无止境的。而且,他们觉得也没这个必要跳过成长期,即便他们已经进入到了下一个阶段:稳定期。**完全进入到稳定期意味着你拥有人力资源及管理方法来创造技术财富,同时根据优先权适当支出。**
|
||||
|
||||
“在成长期和稳定期之间有个转折点,就是维护人员必须要足够壮大,并且相对于专注新功能的产品开发人员,你开始更公平的对待维护人员,”Goulet 说。“你们公司的产品开发完成了。现在你得让他们更加稳定地运行。”
|
||||
|
||||
这就意味着要把公司更多的预算分配到产品维护及现代化方面。“你不应该把产品维护当作是一个不值得关注的项目,”她说。“这必须成为你们公司固有的一种企业文化 —— 这将帮助你们公司将来取得更大的成功。“
|
||||
|
||||
最终,你通过这些努力创建的技术财富,将会为你的团队带来一大批全新的开发者:他们就像侦查兵一样,有充足的时间和资源去探索新的领域,挖掘新客户资源并且给公司创造更多的机遇。当你们在新的市场领域做得更广泛并且不断取得进展 —— 那么你们公司已经真正地进入到繁荣发展的状态了。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: http://firstround.com/review/forget-technical-debt-heres-how-to-build-technical-wealth/
|
||||
|
||||
作者:[http://firstround.com/][a]
|
||||
译者:[rusking](https://github.com/rusking)
|
||||
校对:[jasminepeng](https://github.com/jasminepeng)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: http://firstround.com/
|
||||
[1]:http://corgibytes.com/blog/2016/04/15/inception-layers/
|
||||
[2]:http://www.courageworks.com/
|
||||
[3]:http://corgibytes.com/blog/2016/08/02/how-we-use-daily-journals/
|
||||
[4]:https://www.industriallogic.com/blog/modern-agile/
|
||||
[5]:http://mobprogramming.org/
|
||||
[6]:http://exercism.io/
|
||||
[7]:http://arlobelshee.com/good-naming-is-a-process-not-a-single-step/
|
||||
[8]:https://weworkremotely.com/
|
||||
[9]:https://www.powertofly.com/
|
||||
[10]:http://legacycode.rocks/
|
||||
[11]:https://www.docker.com/
|
||||
[12]:http://legacycoderocks.libsyn.com/technical-wealth-with-declan-wheelan
|
||||
[13]:https://www.agilealliance.org/resources/initiatives/technical-debt/
|
||||
[14]:https://en.wikipedia.org/wiki/Behavior-driven_development
|
||||
[15]:https://en.wikipedia.org/wiki/Conway%27s_law
|
||||
[16]:https://www.amazon.com/Working-Effectively-Legacy-Michael-Feathers/dp/0131177052
|
||||
[17]:http://corgibytes.com/
|
||||
[18]:https://www.linkedin.com/in/andreamgoulet
|
||||
[19]:http://corgibytes.com/blog/2016/04/15/inception-layers/
|
||||
[20]:http://www.courageworks.com/
|
||||
[21]:http://corgibytes.com/blog/2016/08/02/how-we-use-daily-journals/
|
||||
[22]:https://www.industriallogic.com/blog/modern-agile/
|
||||
[23]:http://mobprogramming.org/
|
||||
[24]:http://mobprogramming.org/
|
||||
[25]:http://exercism.io/
|
||||
[26]:http://arlobelshee.com/good-naming-is-a-process-not-a-single-step/
|
||||
[27]:https://weworkremotely.com/
|
||||
[28]:https://www.powertofly.com/
|
||||
[29]:http://legacycode.rocks/
|
||||
[30]:https://www.docker.com/
|
||||
[31]:http://legacycoderocks.libsyn.com/technical-wealth-with-declan-wheelan
|
||||
[32]:https://www.agilealliance.org/resources/initiatives/technical-debt/
|
||||
[33]:https://en.wikipedia.org/wiki/Behavior-driven_development
|
||||
[34]:https://en.wikipedia.org/wiki/Conway%27s_law
|
||||
[35]:https://www.amazon.com/Working-Effectively-Legacy-Michael-Feathers/dp/0131177052
|
||||
[36]:https://www.amazon.com/Working-Effectively-Legacy-Michael-Feathers/dp/0131177052
|
||||
[37]:http://corgibytes.com/
|
||||
[38]:https://www.linkedin.com/in/andreamgoulet
|
||||
[39]:http://corgibytes.com/blog/2016/04/15/inception-layers/
|
||||
[40]:http://www.courageworks.com/
|
||||
[41]:http://corgibytes.com/blog/2016/08/02/how-we-use-daily-journals/
|
||||
[42]:https://www.industriallogic.com/blog/modern-agile/
|
||||
[43]:http://corgibytes.com/blog/2016/08/02/how-we-use-daily-journals/
|
||||
[44]:http://mobprogramming.org/
|
||||
[45]:http://exercism.io/
|
||||
[46]:http://arlobelshee.com/good-naming-is-a-process-not-a-single-step/
|
||||
[47]:https://weworkremotely.com/
|
||||
[48]:https://www.powertofly.com/
|
||||
[49]:http://legacycode.rocks/
|
||||
[50]:https://www.docker.com/
|
||||
[51]:http://legacycoderocks.libsyn.com/technical-wealth-with-declan-wheelan
|
||||
[52]:https://www.agilealliance.org/resources/initiatives/technical-debt/
|
||||
[53]:https://en.wikipedia.org/wiki/Behavior-driven_development
|
||||
[54]:https://en.wikipedia.org/wiki/Conway%27s_law
|
||||
[56]:https://www.amazon.com/Working-Effectively-Legacy-Michael-Feathers/dp/0131177052
|
||||
[57]:http://corgibytes.com/
|
||||
[58]:https://www.linkedin.com/in/andreamgoulet
|
181
published/20160929 Getting Started with HTTP2 - Part 2.md
Normal file
181
published/20160929 Getting Started with HTTP2 - Part 2.md
Normal file
@ -0,0 +1,181 @@
|
||||
初识 HTTP/2(二)
|
||||
============================================================
|
||||

|
||||
|
||||
> HTTP/2 时代的开启为前端开发带来了最佳体验。
|
||||
|
||||
如果你对 HTTP/2 有所了解,那你可能用过它,或者至少想过怎样能把它融入你的项目中。尽管有很多关于它如何改变工作流程,提高 Web 速度和效率等方面的猜想,但最佳使用方式还没有定下来。这里我想讲的就是我在之前的项目中所发现的 HTTP/2 的最佳实践。
|
||||
|
||||
如果你还不确定什么是 HTTP/2,或者为什么它能改进你的工作,可以先看看我[介绍背景方面的第一篇文章][4]。
|
||||
|
||||
记住:开始之前,我要告诉你,尽管你的浏览器可能支持 HTTP/2,但你的服务器可能不支持。检查你的主机托管服务,看看他们是否提供 HTTP/2 的支持。否则你可能要建立你自己的服务器。这篇文章并不会涉及这方面该如何做,但你可以查看 [http2 github][5] 页面,找一找这方面的工具。
|
||||
|
||||
### 🙏 [热身工作]
|
||||
|
||||
首先组织好你的文件。看一看下面的文件树结构,作为组织你的样式表的起点:
|
||||
|
||||
```
|
||||
/styles
|
||||
|── /setup
|
||||
| /* 变量、混入(minin)和函数 */
|
||||
|── /global
|
||||
| /* 能放在任何组件和部分中的可重用组件 */
|
||||
|── /components
|
||||
| /* 特殊组件和部分 */
|
||||
|── setup.scss // setup 样式索引
|
||||
|── global.scss // 全局样式索引
|
||||
```
|
||||
|
||||
这会把你的样式分到三个目录下面:`setup`、`global` 和 `componenets`。接下来我会说明这些目录对你的项目有什么用。
|
||||
|
||||
### setup 目录
|
||||
|
||||
`setup` 目录保存所有的变量、函数、混入(minin)以及一些正常编译需要的其它文件的定义。要想让这个目录物尽其用,把这个目录下所有内容导入到 `setup.scss` 文件中是个很不错的主意,这样这个文件就会像下面所展示的一样:
|
||||
|
||||
```
|
||||
/* setup.scss */
|
||||
|
||||
/* 变量 */
|
||||
@import "setup/variables/colors";
|
||||
|
||||
/* 混入 */
|
||||
@import "setup/mixins/color";
|
||||
|
||||
/* 函数 */
|
||||
@import "setup/functions/color";
|
||||
|
||||
... 等等
|
||||
```
|
||||
|
||||
现在我们能快速引用这个站点中的所有定义,应该确保在所有的样式文件顶部包含我们这里创建的这个文件。
|
||||
|
||||
### global 目录
|
||||
|
||||
接下来的目录,global 目录,应该包含可在当前站点的多个部分或者每一个页面中重复使用的组件。像按钮、文本、主要样式,以及你的浏览器默认设置应该放在这里。我不建议把页面的头部或底部样式放在这儿,因为某些项目中没有头部,或者不同页面头部不同。而且,底部永远是页面的最后一个元素,所以在用户加载完当前站点的其它东西前,不必过分优先考虑加载底部样式。
|
||||
|
||||
记住,如果没有那些定义在 setup 目录下的东西,你的 global 样式就可能没有作用,你的 global 文件看起来应该像这样:
|
||||
|
||||
```
|
||||
/* global.scss */
|
||||
|
||||
/* 应用定义 */
|
||||
@import "setup";
|
||||
|
||||
/* 全局样式 */
|
||||
@import "global/reset";
|
||||
@import "global/buttons";
|
||||
@import "global/typography";
|
||||
@import "global/grid";
|
||||
|
||||
... 等等
|
||||
```
|
||||
|
||||
注意,首先要做的就是导入 setup 样式。这样的话,之后的文件都可以引用这个样式里的定义。
|
||||
|
||||
由于站点内的每个页面都需要 global 样式,我们可以用典型的方式,在 `<head>` 标签内用一个 `<link>` 标签来加载它们。你所看到的将是一个十分小巧的 css 文件,或者说理论上小巧的,这取决于你需要多少全局样式。
|
||||
|
||||
### 最后,你的组件
|
||||
|
||||
注意,我没有在上述目录树中的 components 目录里包含索引文件。这是 HTTP/2 所带来的效用。直到现在,我们已经按照标准步骤构建了一个典型的站点,保持相当简单的结构,仅选择全局化那些最重要的样式。组件充当它们自己的索引文件。
|
||||
|
||||
大多数开发者有独特的组织组件的方式,因此我并不想影响你的策略。但是,你所有的组件看起来应该像这样:
|
||||
|
||||
```
|
||||
/* header.scss */
|
||||
|
||||
/* 应用定义 */
|
||||
@import "../setup";
|
||||
|
||||
header {
|
||||
// 样式
|
||||
}
|
||||
|
||||
... 等等
|
||||
```
|
||||
|
||||
同样的,你要把 setup 样式包含进来,确保所有东西在编译时都定义过。除了编译这些文件,以及可能要把他们放到 `/assets` 目录,以便很容易找到模版,对这些文件你不必 <ruby>拼接<rt>concatenate</rt></ruby>、<ruby>压缩<rt>minify</rt></ruby> 它们或者改变什么。
|
||||
|
||||
现在样式表已经差不多了,构建站点应该很简单。
|
||||
|
||||
### 构建组件
|
||||
|
||||
或许对于模板语言你有自己的选择,这取决于你的项目,有可能是 Twig、Rails、Jade 或者 Handlebars。我认为考虑组件最好的方式是它是否有自己的模版文件,它该有个与名字相应的样式。这样你的项目中,模版和样式的比例就会是个不错的 1:1 的比例,而且你知道哪个文件有哪些东西,哪里有哪个文件,因为它们的命名是有规律的。
|
||||
|
||||
现在它正步入正轨,用好 HTTP/2 的多种功能十分简单,让我们做一个模版:
|
||||
|
||||
```
|
||||
{# header.html #}
|
||||
|
||||
{# compiled header styles #}
|
||||
<link href="assets/components/header.css" rel="stylesheet" media="all">
|
||||
|
||||
<header>
|
||||
<h1>This Awesome HTTP/2 Site</h1>
|
||||
... 等等
|
||||
```
|
||||
|
||||
非常好!在模版里你可能有更简单的方式链接到资源,但这里显示你所要做的仅是在开始构建时,在模版文件中链接一个小小的头部样式。这将允许你的站点仅仅加载特定资源到任意给定页面的组件中,而且,能够设定页面从头到脚的组件的优先级。
|
||||
|
||||
### 结合在一起
|
||||
|
||||
现在所有的组件都有结构,浏览器将会类似以下方式来渲染它们:
|
||||
|
||||
```
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" media="all" href="/assets/global.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<link rel="stylesheet" media="all" href="/assets/components/header.css">
|
||||
<header>
|
||||
... etc
|
||||
</header>
|
||||
|
||||
<link rel="stylesheet" media="all" href="/assets/components/title.css">
|
||||
<section class="title">
|
||||
... etc
|
||||
</section>
|
||||
|
||||
<link rel="stylesheet" media="all" href="/assets/components/image-component.css">
|
||||
<section class="image-component">
|
||||
... etc
|
||||
</section>
|
||||
|
||||
<link rel="stylesheet" media="all" href="/assets/components/text-component.css">
|
||||
<section class="text-component">
|
||||
... etc
|
||||
</section>
|
||||
|
||||
<link rel="stylesheet" media="all" href="/assets/components/footer.css">
|
||||
<footer>
|
||||
... etc
|
||||
</footer>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
这是一个高级别方法,但你的项目中可能有调整的更细致的组件。例如,在头部的 `<nav>` 组件可能要加载自己的样式表。尽你所能地自由发挥,让组件更有作用 - HTTP/2 不会因这些需求而阻碍你!
|
||||
|
||||
### 结论
|
||||
|
||||
这只是一个关于如何在前端用 HTTP/2 构建项目的基本介绍,仅是皮毛而已。你可能注意到我上面所用的方法有的还有改进的空间。请不吝赐教!正如我在第一篇文章中所说的,HTTP/2 可能颠覆自 HTTP/1 以来我们所熟知的某些标准,所以要慎重思考和实践,以便高效使用 HTTP/2 的开发环境。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.viget.com/articles/getting-started-with-http-2-part-2
|
||||
|
||||
作者:[Ben][a]
|
||||
译者:[GitFuture](https://github.com/GitFuture)
|
||||
校对:[jasminepeng](https://github.com/jasminepeng)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 组织编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://www.viget.com/about/team/btinsley
|
||||
[1]:https://twitter.com/home?status=Firmly%20planting%20a%20flag%20in%20the%20sand%20for%20HTTP%2F2%20best%20practices%20for%20front%20end%20development.%20https%3A%2F%2Fwww.viget.com%2Farticles%2Fgetting-started-with-http-2-part-2
|
||||
[2]:https://www.facebook.com/sharer/sharer.php?u=https%3A%2F%2Fwww.viget.com%2Farticles%2Fgetting-started-with-http-2-part-2
|
||||
[3]:http://www.linkedin.com/shareArticle?mini=true&url=https%3A%2F%2Fwww.viget.com%2Farticles%2Fgetting-started-with-http-2-part-2
|
||||
[4]:https://linux.cn/article-8111-1.html
|
||||
[5]:https://github.com/http2/http2-spec/wiki/Tools
|
@ -3,31 +3,30 @@
|
||||
|
||||

|
||||
|
||||
|
||||
我自认为自己是个奥迪亚的维基人。我通过写文章和纠正错误的文章贡献[奥迪亚][1]知识(在印度的[奥里萨邦][2]的主要的语言 )给很多维基项目,像维基百科和维基文库,我也为用印地语和英语写的维基文章做贡献。
|
||||
我自认为自己是个奥迪亚的维基人。我通过写文章和纠正文章错误给很多维基项目贡献了[奥迪亚(Odia)][1]知识(这是在印度的[奥里萨邦][2]的主要语言),比如维基百科和维基文库,我也为用印地语和英语写的维基文章做贡献。
|
||||
|
||||

|
||||
|
||||
我对维基的爱从我第 10 次考试(像在美国的 10 年级学生的年级考试)之后看到的英文维基文章[孟加拉解放战争][3]开始。一不小心我打开了印度维基文章的链接,,并且开始阅读它. 在文章左边有用奥迪亚语写的东西, 所以我点击了一下, 打开了一篇在奥迪亚维基上的 [????/Bhārat][4] 文章. 发现了用母语写的维基让我很激动!
|
||||
我对维基的爱从我第 10 次考试(像在美国的 10 年级学生的年级考试)之后看到的英文维基文章[孟加拉解放战争][3]开始。一不小心我打开了印度维基文章的链接,并且开始阅读它。在文章左边有用奥迪亚语写的东西,所以我点击了一下, 打开了一篇在奥迪亚维基上的 [ଭାରତ/Bhārat][4] 文章。发现了用母语写的维基让我很激动!
|
||||
|
||||

|
||||
|
||||
一个邀请读者参加 2014 年 4 月 1 日第二次布巴内斯瓦尔的研讨会的标语引起了我的好奇。我过去从来没有为维基做过贡献, 只用它搜索过, 我并不熟悉开源和社区贡献流程。加上,我只有 15 岁。我注册了。在研讨会上有很多语言爱好者,我是中间最年轻的一个。尽管我害怕我父亲还是鼓励我去参与。他起了非常重要的作用—他不是一个维基媒体人,和我不一样,但是他的鼓励给了我改变奥迪亚维基的动力和参加社区活动的勇气。
|
||||
一个邀请读者参加 2014 年 4 月 1 日召开的第二届布巴内斯瓦尔研讨会的旗帜广告引起了我的好奇。我过去从来没有为维基做过贡献,只用它做过研究,我并不熟悉开源和社区贡献流程。再加上,当时我只有 15 岁。我注册了,在研讨会上有很多语言爱好者,他们全比我大。尽管我害怕,我父亲还是鼓励我去参与。他起了非常重要的作用—他不是一个维基媒体人,和我不一样,但是他的鼓励给了我改变奥迪亚维基的动力和参加社区活动的勇气。
|
||||
|
||||
我相信奥迪亚语言和文学需要改进很多错误的想法和知识缺口所以,我帮助组织关于奥迪亚维基的活动和和研讨会,我完成了如下列表:
|
||||
我觉得关于奥迪亚语言和文学的知识很多需要改进,有很多错误的观念和知识缺口,所以,我帮助组织关于奥迪亚维基的活动和和研讨会,我完成了如下列表:
|
||||
|
||||
* 发起3次主要的 edit-a-thons 在奥迪亚维基:2015 年妇女节,2016年妇女节, abd [Nabakalebara edit-a-thon 2015][5]
|
||||
* 在奥迪亚维基发起 3 次主要的 edit-a-thons :2015 年妇女节、2016年妇女节、abd [Nabakalebara edit-a-thon 2015][5]
|
||||
* 在全印度发起了征集[檀车节][6]图片的比赛
|
||||
* 在谷歌的两大事件([谷歌I/O大会扩展][7]和谷歌开发节)中代表奥迪亚维基
|
||||
* 在2015[Perception][8]和第一次[Open Access India][9]会议
|
||||
* 在2015 [Perception][8] 和第一次 [Open Access India][9] 会议
|
||||
|
||||

|
||||
|
||||
我只编辑维基项目到了去年,在 2015 年一月,当我出席[孟加拉语维基百科的十周年会议][10]和[毗瑟挐][11]活动时,[互联网和社会中心][12]主任,邀请我参加[培训培训师][13] 计划。我的灵感始于扩展奥迪亚维基,为[华丽][14]的活动举办的聚会和培训新的维基人。这些经验告诉我作为一个贡献者该如何为社区工作。
|
||||
我在维基项目当编辑直到去年( 2015 年 1 月)为止,当我出席[孟加拉语维基百科的十周年会议][10]和[毗瑟挐][11]活动时,[互联网和社会中心][12]主任,邀请我参加[培训师培训计划][13]。我的开始超越奥迪亚维基,为[GLAM][14]的活动举办聚会和培训新的维基人。这些经验告诉我作为一个贡献者该如何为社区工作。
|
||||
|
||||
[Ravi][15],在当时维基的主任,在我的旅程也发挥了重要作用。他非常相信我让我参与到了[Wiki Loves Food][16],维基共享中的公共摄影比赛,组织方是[2016 印度维基会议][17]。在2015的 Loves Food 活动期间,我的团队在维基共享中加入了 10,000+ 有 CC BY-SA 协议的图片。Ravi 进一步巩固了我的承诺,和我分享很多关于维基媒体运动的信息,和他自己在 [奥迪亚维基百科13周年][18]的经历。
|
||||
[Ravi][15],在当时印度维基的总监,在我的旅程也发挥了重要作用。他非常相信我,让我参与到了 [Wiki Loves Food][16],维基共享中的公共摄影比赛,组织方是 [2016 印度维基会议][17]。在 2015 的 Loves Food 活动期间,我的团队在维基共享中加入了 10000+ 采用 CC BY-SA 协议的图片。Ravi 进一步坚定了我的信心,和我分享了很多关于维基媒体运动的信息,以及他自己在 [奥迪亚维基百科 13 周年][18]的经历。
|
||||
|
||||
不到一年后,在 2015 年十二月,我成为了网络与社会中心的[获取知识的程序][19]的项目助理( CIS-A2K 运动)。我自豪的时刻之一是在普里的研讨会,我们从印度带了 20 个新的维基人来编辑奥迪亚维基媒体社区。现在,我的指导者在一个普里非正式聚会被叫作[WikiTungi][20]。我和这个小组一起工作,把 wikiquotes 变成一个真实的计划项目。在奥迪亚维基我也致力于缩小性别差距。[八个女编辑][21]也正帮助组织聚会和研讨会,参加 [Women's History month edit-a-thon][22]。
|
||||
不到一年后,在 2015 年十二月,我成为了网络与社会中心的[获取知识计划][19]的项目助理( CIS-A2K 运动)。我自豪的时刻之一是在印度普里的研讨会,我们给奥迪亚维基媒体社区带来了 20 个新的维基人。现在,我在一个名为 [WikiTungi][20] 普里的非正式聚会上指导着维基人。我和这个小组一起工作,把奥迪亚 Wikiquotes 变成一个真实的计划项目。在奥迪亚维基我也致力于缩小性别差距。[八个女编辑][21]也正帮助组织聚会和研讨会,参加 [Women's History month edit-a-thon][22]。
|
||||
|
||||
在我四年短暂而令人激动的旅行之中,我也参与到 [维基百科的教育项目][23],[通讯团队][24],两个全球的 edit-a-thons: [Art and Feminsim][25] 和 [Menu Challenge][26]。我期待着更多的到来!
|
||||
|
||||
@ -38,8 +37,8 @@
|
||||
via: https://opensource.com/life/16/4/my-open-source-story-sailesh-patnaik
|
||||
|
||||
作者:[Sailesh Patnaik][a]
|
||||
译者:[译者ID](https://github.com/hkurj)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
译者:[hkurj](https://github.com/hkurj)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创翻译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
@ -0,0 +1,176 @@
|
||||
Python 单元测试:assertTrue 是真值,assertFalse 是假值
|
||||
===========================
|
||||
|
||||
在这篇文章中,我们将介绍单元测试的布尔断言方法 `assertTrue` 和 `assertFalse` 与身份断言 `assertIs` 之间的区别。
|
||||
|
||||
### 定义
|
||||
|
||||
下面是目前[单元测试模块文档][1]中关于 `assertTrue` 和 `assertFalse` 的说明,代码进行了高亮:
|
||||
|
||||
|
||||
> `assertTrue(expr, msg=None)`
|
||||
|
||||
> `assertFalse(expr, msg=None)`
|
||||
|
||||
>> 测试该*表达式*是真值(或假值)。
|
||||
|
||||
>> 注:这等价于
|
||||
|
||||
>> `bool(expr) is True`
|
||||
|
||||
>> 而不等价于
|
||||
|
||||
>> `expr is True`
|
||||
|
||||
>> (后一种情况请使用 `assertIs(expr, True)`)。
|
||||
|
||||
[Mozilla 开发者网络中定义 `真值`][2] 如下:
|
||||
|
||||
> 在一个布尔值的上下文环境中能变成“真”的值
|
||||
|
||||
在 Python 中等价于:
|
||||
|
||||
```
|
||||
bool(expr) is True
|
||||
```
|
||||
|
||||
这个和 `assertTrue` 的测试目的完全匹配。
|
||||
|
||||
因此该文档中已经指出 `assertTrue` 返回真值,`assertFalse` 返回假值。这些断言方法从接受到的值构造出一个布尔值,然后判断它。同样文档中也建议我们根本不应该使用 `assertTrue` 和 `assertFalse`。
|
||||
|
||||
### 在实践中怎么理解?
|
||||
|
||||
我们使用一个非常简单的例子 - 一个名称为 `always_true` 的函数,它返回 `True`。我们为它写一些测试用例,然后改变代码,看看测试用例的表现。
|
||||
|
||||
作为开始,我们先写两个测试用例。一个是“宽松的”:使用 `assertTrue` 来测试真值。另外一个是“严格的”:使用文档中建议的 `assertIs` 函数。
|
||||
|
||||
```
|
||||
import unittest
|
||||
|
||||
from func import always_true
|
||||
|
||||
|
||||
class TestAlwaysTrue(unittest.TestCase):
|
||||
|
||||
def test_assertTrue(self):
|
||||
"""
|
||||
always_true returns a truthy value
|
||||
"""
|
||||
result = always_true()
|
||||
|
||||
self.assertTrue(result)
|
||||
|
||||
def test_assertIs(self):
|
||||
"""
|
||||
always_true returns True
|
||||
"""
|
||||
result = always_true()
|
||||
|
||||
self.assertIs(result, True)
|
||||
```
|
||||
|
||||
下面是 `func.py` 中的非常简单的函数代码:
|
||||
|
||||
```
|
||||
def always_true():
|
||||
"""
|
||||
I'm always True.
|
||||
|
||||
Returns:
|
||||
bool: True
|
||||
"""
|
||||
return True
|
||||
```
|
||||
|
||||
当你运行时,所有测试都通过了:
|
||||
|
||||
```
|
||||
always_true returns True ... ok
|
||||
always_true returns a truthy value ... ok
|
||||
|
||||
----------------------------------------------------------------------
|
||||
Ran 2 tests in 0.004s
|
||||
|
||||
OK
|
||||
```
|
||||
|
||||
开心ing~
|
||||
|
||||
现在,某个人将 `always_true` 函数改变成下面这样:
|
||||
|
||||
```
|
||||
def always_true():
|
||||
"""
|
||||
I'm always True.
|
||||
|
||||
Returns:
|
||||
bool: True
|
||||
"""
|
||||
return 'True'
|
||||
```
|
||||
|
||||
它现在是用返回字符串 `"True"` 来替代之前反馈的 `True` (布尔值)。(当然,那个“某人”并没有更新文档 - 后面我们会增加难度。)
|
||||
|
||||
这次结果并不如开心了:
|
||||
|
||||
```
|
||||
always_true returns True ... FAIL
|
||||
always_true returns a truthy value ... ok
|
||||
|
||||
======================================================================
|
||||
FAIL: always_true returns True
|
||||
----------------------------------------------------------------------
|
||||
Traceback (most recent call last):
|
||||
File "/tmp/assertttt/test.py", line 22, in test_is_true
|
||||
self.assertIs(result, True)
|
||||
AssertionError: 'True' is not True
|
||||
|
||||
----------------------------------------------------------------------
|
||||
Ran 2 tests in 0.004s
|
||||
|
||||
FAILED (failures=1)
|
||||
```
|
||||
|
||||
只有一个测试用例失败了!这意味着 `assertTrue` 给了我们一个误判(false-positive)。在它不应该通过测试时,它通过了。很幸运的是我们第二个测试是使用 `assertIs` 来写的。
|
||||
|
||||
因此,跟手册上了解到的信息一样,为了保证 `always_true` 的功能和更严格测试的结果保持一致,应该使用 `assertIs` 而不是 `assertTrue`。
|
||||
|
||||
### 使用断言的辅助方法
|
||||
|
||||
使用 `assertIs` 来测试返回 `True` 和 `False` 来冗长了。因此,如果你有个项目需要经常检查是否是返回了 `True` 或者 `False`,那们你可以自己编写一些断言的辅助方法。
|
||||
|
||||
这好像并没有节省大量的代码,但是我个人觉得提高了代码的可读性。
|
||||
|
||||
```
|
||||
def assertIsTrue(self, value):
|
||||
self.assertIs(value, True)
|
||||
|
||||
def assertIsFalse(self, value):
|
||||
self.assertIs(value, False)
|
||||
```
|
||||
|
||||
### 总结
|
||||
|
||||
一般来说,我的建议是让测试越严格越好。如果你想测试 `True` 或者 `False`,听从[文档][3]的建议,使用 `assertIs`。除非不得已,否则不要使用 `assertTrue` 和 `assertFalse`。
|
||||
|
||||
如果你面对的是一个可以返回多种类型的函数,例如,有时候返回布尔值,有时候返回整形,那么考虑重构它。这是代码的异味。在 Python 中,抛出一个异常比使用 `False` 表示错误更好。
|
||||
|
||||
此外,如果你确实想使用断言来判断函数的返回值是否是真,可能还存在第二个代码异味 - 代码是正确封装了吗?如果 `assertTrue` 和 `assertFalse` 是根据正确的 `if` 语句来执行,那么值得检查下你是否把所有你想要的东西都封装在合适的位置。也许这些 `if` 语句应该封装在测试的函数中。
|
||||
|
||||
测试开心!
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: http://jamescooke.info/python-unittest-asserttrue-is-truthy-assertfalse-is-falsy.html
|
||||
|
||||
作者:[James Cooke][a]
|
||||
译者:[chunyang-wen](https://github.com/chunyang-wen)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: http://jamescooke.info/pages/hello-my-name-is-james.html
|
||||
[1]:https://docs.python.org/3/library/unittest.html#unittest.TestCase.assertTrue
|
||||
[2]:https://developer.mozilla.org/en-US/docs/Glossary/Truthy
|
||||
[3]:https://docs.python.org/3/library/unittest.html#unittest.TestCase.assertTrue
|
@ -0,0 +1,133 @@
|
||||
科学音频处理(三):如何使用 Octave 的高级数学技术处理音频文件
|
||||
=====
|
||||
|
||||
我们的数字音频处理技术第三部分涵盖了信号调制内容,将解释如何进行调幅(Amplitude Modulation)、颤音效果(Tremolo Effect)和频率变化(Frequency Variation)。
|
||||
|
||||
### 调制
|
||||
|
||||
#### 调幅
|
||||
|
||||
正如它的名字暗示的那样, 影响正弦信号的振幅变化依据传递的信息而不断改变。正弦波因为承载着大量的信息被称作载波(carrier)。这种调制技术被用于许多的商业广播和市民信息传输波段(AM)。
|
||||
|
||||
#### 为何要使用调幅技术?
|
||||
|
||||
**调制发射**
|
||||
|
||||
假设信道是免费资源,有天线就可以发射和接收信号。这要求有效的电磁信号发射天线,它的大小和要被发射的信号的波长应该是同一数量级。很多信号,包括音频成分,通常在 100 赫兹或更低。对于这些信号,如果直接发射,我们就需要建立长达 300 公里的天线。如果通过信号调制将信息加载到 100MHz 的高频载波中,那么天线仅仅需要 1 米(横向长度)。
|
||||
|
||||
**集中调制与多通道**
|
||||
|
||||
假设多个信号占用一个通道,调制可以将不同的信号不同频域位置,以便接收者选择该特定信号。使用集中调制(“复用”)的应用有遥感探测数据、立体声调频收音机和长途电话等。
|
||||
|
||||
**克服设备限制的调制**
|
||||
|
||||
信号处理设备,比如过滤器、放大器,以及可以用它们简单组成的设备,它们的性能依赖于信号在频域中的境况以及高频率和低频信号的关系。调制可以用于传递信号到频域中的更容易满足设计需求的位置。调制也可以将“宽带信号“(高频和低频的比例很大的信号)转换成”窄带“信号。
|
||||
|
||||
**音频特效**
|
||||
|
||||
许多音频特效由于引人注目和处理信号的便捷性使用了调幅技术。我们可以说出很多,比如颤音、合唱、镶边等等。这种实用性就是我们关注它的原因。
|
||||
|
||||
### 颤音效果
|
||||
|
||||
颤音效果是调幅最简单的应用,为实现这样的效果,我们会用周期信号改变(乘)音频信号,使用正弦或其他。
|
||||
|
||||
```
|
||||
>> tremolo='tremolo.ogg';
|
||||
>> fs=44100;
|
||||
>> t=0:1/fs:10;
|
||||
>> wo=2*pi*440*t;
|
||||
>> wa=2*pi*1.2*t;
|
||||
>> audiowrite(tremolo, cos(wa).*cos(wo),fs);
|
||||
```
|
||||
|
||||

|
||||
|
||||
这将创造一个正弦形状的信号,它的效果就像‘颤音’。
|
||||
|
||||

|
||||
|
||||
### 在真实音频文件中的颤音
|
||||
|
||||
现在我们将展示真实世界中的颤音效果。首先,我们使用之前记录过男性发声 ‘A’ 的音频文件。这个信号图就像下面这样:
|
||||
|
||||
```
|
||||
>> [y,fs]=audioread('A.ogg');
|
||||
>> plot(y);
|
||||
```
|
||||
|
||||

|
||||
|
||||
现在我们将创建一个完整的正弦信号,使用如下的参数:
|
||||
|
||||
- 增幅 = 1
|
||||
- 频率= 1.5Hz
|
||||
- 相位 = 0
|
||||
|
||||
```
|
||||
>> t=0:1/fs:4.99999999;
|
||||
>> t=t(:);
|
||||
>> w=2*pi*1.5*t;
|
||||
>> q=cos(w);
|
||||
>> plot(q);
|
||||
```
|
||||
|
||||
注意: 当我们创建一组时间值时,默认情况下,它是以列的格式呈现,如, 1x220500 的值。为了乘以这样的值,必须将其变成行的形式(220500x1)。这就是 `t=t(:)` 命令的作用。
|
||||
|
||||

|
||||
|
||||
我们将创建第二份 ogg 音频格式的文件,它包含了如下的调制信号:
|
||||
|
||||
```
|
||||
>> tremolo='tremolo.ogg';
|
||||
>> audiowrite(tremolo, q.*y,fs);
|
||||
```
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
### 频率变化
|
||||
|
||||
我们可以改变频率实现一些有趣的音效,比如原音变形,电影音效,多人比赛。
|
||||
|
||||
#### 正弦频率调制的影响
|
||||
|
||||
这是正弦调制频率变化的演示代码,根据方程:
|
||||
|
||||
```
|
||||
Y=Ac*Cos(wo*Cos(wo/k))
|
||||
```
|
||||
|
||||
这里:
|
||||
|
||||
- Ac = 增幅
|
||||
- wo = 基频
|
||||
- k = 标量除数
|
||||
|
||||
```
|
||||
>> fm='fm.ogg';
|
||||
>> fs=44100;
|
||||
>> t=0:1/fs:10;
|
||||
>> w=2*pi*442*t;
|
||||
>> audiowrite(fm, cos(cos(w/1500).*w), fs);
|
||||
>> [y,fs]=audioread('fm.ogg');
|
||||
>> figure (); plot (y);
|
||||
```
|
||||
|
||||
信号图:
|
||||
|
||||

|
||||
|
||||
你可以使用几乎任何类型的周期函数频率调制。本例中,我们仅仅用了一个正弦函数。请大胆的改变函数频率,用复合函数,甚至改变函数的类型。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.howtoforge.com/tutorial/ubuntu-octave-audio-processing-part-3/
|
||||
|
||||
作者:[David Duarte][a]
|
||||
译者:[theArcticOcean](https://github.com/theArcticOcean)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://www.howtoforge.com/tutorial/ubuntu-octave-audio-processing-part-3/
|
@ -0,0 +1,241 @@
|
||||
通过 AWS 的 Lambda 和 API Gateway 走向 Serverless
|
||||
============================
|
||||
|
||||
近来,在计算领域出现了很多关于 serverless 的讨论。serverless 是一个概念,它允许你提供代码或可执行程序给某个服务,由服务来为你执行它们,而你无需自己管理服务器。这就是所谓的执行即服务(execution-as-a-service),它带来了很多机会,同时也遇到了它独有的挑战。
|
||||
|
||||
### 简短回忆下计算领域的发展
|
||||
|
||||
早期,出现了……好吧,这有点复杂。很早的时候,出现了机械计算机,后来又有了埃尼阿克 ENIAC(Electronic Numerical Integrator And Computer,很早的电子计算机),但是都没有规模生产。直到大型机出现后,计算领域才快速发展。
|
||||
|
||||
- 上世纪 50 年代 - 大型机
|
||||
- 上世纪 60 年代 - 微型机
|
||||
- 1994 - 机架服务器
|
||||
- 2001 - 刀片服务器
|
||||
- 本世纪初 - 虚拟服务器
|
||||
- 2006 - 服务器云化
|
||||
- 2013 - 容器化
|
||||
- 2014 - serverless(计算资源服务化)
|
||||
|
||||
> 这些日期是大概的发布或者流行日期,无需和我争论时间的准确性。
|
||||
|
||||
计算领域的演进趋势是执行的功能单元越来越小。每一次演进通常都意味着运维负担的减小和运维灵活性的增加。
|
||||
|
||||
### 发展前景
|
||||
|
||||
喔,Serverless!但是,serverless 能给我们带来什么好处? 我们将面临什么挑战呢?
|
||||
|
||||
**未执行代码时无需付费。**我认为,这是个巨大的卖点。当无人访问你的站点或用你的 API 时,你无需付钱。没有持续支出的基础设施成本,仅仅支付你需要的部分。换句话说,这履行了云计算的承诺:“仅仅支付你真正用的资源”。
|
||||
|
||||
**无需维护服务器,也无需考虑服务器安全。**服务器的维护和安全将由你的服务提供商来处理(当然,你也可以架设自己的 serverless 主机,只是这似乎是在向错误的方向前进)。由于你的执行时间也是受限的,安全补丁也被简化了,因为完全不需要重启。这些都应该由你的服务提供商无缝地处理。
|
||||
|
||||
**无限的可扩展性。**这是又一个大的好处。假设你又开发了一个 Pokemon Go, 与其频繁地把站点下线维护升级,不如用 serverless 来不断地扩展。当然,这也是个双刃剑,大量的账单也会随之而来。如果你的业务的利润强依赖于站点上线率的话,serverless 确实能帮上忙。
|
||||
|
||||
**强制的微服务架构。**这也有两面性,一方面,微服务似乎是一种好的构建灵活可扩展的、容错的架构的方式。另一方面,如果你的业务没有按照这种方式设计,你将很难在已有的架构中引入 serverless。
|
||||
|
||||
### 但是现在你被限制在**他们的**平台上
|
||||
|
||||
**受限的环境。**你只能用服务提供商提供的环境,你想在 Rust 中用 serverless?你可能不会太幸运。
|
||||
|
||||
**受限的预装包。**你只有提供商预装的包。但是你或许能够提供你自己的包。
|
||||
|
||||
**受限的执行时间。**你的 Function 只可以运行这么长时间。如果你必须处理 1TB 的文件,你可能需要有一个解决办法或者用其他方案。
|
||||
|
||||
**强制的微服务架构。**参考上面的描述。
|
||||
|
||||
**受限的监视和诊断能力。**例如,你的代码**在**干什么? 在 serverless 中,基本不可能在调试器中设置断点和跟踪流程。你仍然可以像往常一样记录日志并发出统计度量,但是这带来的帮助很有限,无法定位在 serverless 环境中发生的难点问题。
|
||||
|
||||
### 竞争领域
|
||||
|
||||
自从 2014 年出现 AWS Lambda 以后,serverless 的提供商已经增加了一些。下面是一些主流的服务提供商:
|
||||
|
||||
- AWS Lambda - 起步最早的
|
||||
- OpenWhisk - 在 IBM 的 Bluemix 云上可用
|
||||
- Google Cloud Functions
|
||||
- Azure Functions
|
||||
|
||||
这些平台都有它们的相对优势和劣势(例如,Azure 支持 C#,或者紧密集成在其他提供商的平台上)。这里面最大的玩家是 AWS。
|
||||
|
||||
### 通过 AWS 的 Lambda 和 API Gateway 构建你的第一个 API
|
||||
|
||||
我们来试一试 serverless。我们将用 AWS Lambda 和 API Gateway 来构建一个能返回 [Jimmy][2] 所说的“Guru Meditations”的 API。
|
||||
|
||||
所有代码在 [GitHub][1] 上可以找到。
|
||||
|
||||
API文档:
|
||||
|
||||
```
|
||||
POST /
|
||||
{
|
||||
"status": "success",
|
||||
"meditation": "did u mention banana cognac shower"
|
||||
}
|
||||
```
|
||||
|
||||
### 怎样组织工程文件
|
||||
|
||||
文件结构树:
|
||||
|
||||
```
|
||||
.
|
||||
├── LICENSE
|
||||
├── README.md
|
||||
├── server
|
||||
│ ├── __init__.py
|
||||
│ ├── meditate.py
|
||||
│ └── swagger.json
|
||||
├── setup.py
|
||||
├── tests
|
||||
│ └── test_server
|
||||
│ └── test_meditate.py
|
||||
└── tools
|
||||
├── deploy.py
|
||||
├── serve.py
|
||||
├── serve.sh
|
||||
├── setup.sh
|
||||
└── zip.sh
|
||||
```
|
||||
|
||||
AWS 中的信息(想了解这里究竟在做什么的详细信息,可查看源码 `tools/deploy.py`)。
|
||||
|
||||
- **API。**实际构建的对象。它在 AWS 中表示为一个单独的对象。
|
||||
- **执行角色。**在 AWS 中,每个 Function 作为一个单独的角色执行。在这里就是 meditations。
|
||||
- **角色策略。**每个 Function 作为一个角色执行,每个角色需要权限来干活。我们的 Lambda Function 不干太多活,故我们只添加一些日志记录权限。
|
||||
- **Lambda Function。**运行我们的代码的地方。
|
||||
- **Swagger。** Swagger 是 API 的规范。API Gateway 支持解析 swagger 的定义来为 API 配置大部分资源。
|
||||
- **部署。**API Gateway 提供部署的概念。我们只需要为我们的 API 用一个就行(例如,所有的都用生产或者 yolo等),但是得知道它们是存在的,并且对于真正的产品级服务,你可能想用开发和暂存环境。
|
||||
- **监控。**在我们的业务崩溃的情况下(或者因为使用产生大量账单时),我们想以云告警查看方式为这些错误和费用添加一些监控。注意你应该修改 `tools/deploy.py` 来正确地设置你的 email。
|
||||
|
||||
### 代码
|
||||
|
||||
Lambda Function 将从一个硬编码列表中随机选择一个并返回 guru meditations,非常简单:
|
||||
|
||||
```
|
||||
import logging
|
||||
import random
|
||||
|
||||
|
||||
logger = logging.getLogger()
|
||||
logger.setLevel(logging.INFO)
|
||||
|
||||
|
||||
def handler(event, context):
|
||||
|
||||
logger.info(u"received request with id '{}'".format(context.aws_request_id))
|
||||
|
||||
meditations = [
|
||||
"off to a regex/",
|
||||
"the count of machines abides",
|
||||
"you wouldn't fax a bat",
|
||||
"HAZARDOUS CHEMICALS + RKELLY",
|
||||
"your solution requires a blood eagle",
|
||||
"testing is broken because I'm lazy",
|
||||
"did u mention banana cognac shower",
|
||||
]
|
||||
|
||||
meditation = random.choice(meditations)
|
||||
|
||||
return {
|
||||
"status": "success",
|
||||
"meditation": meditation,
|
||||
}
|
||||
```
|
||||
|
||||
### deploy.py 脚本
|
||||
|
||||
这个脚本相当长,我没法贴在这里。它基本只是遍历上述“AWS 中的信息”下的项目,确保每项都存在。
|
||||
|
||||
### 我们来部署这个脚本
|
||||
|
||||
只需运行 `./tools/deploy.py`。
|
||||
|
||||
基本完成了。不过似乎在权限申请上有些问题,由于 API Gateway 没有权限去执行你的 Function,所以你的 Lambda Function 将不能执行,报错应该是“Execution failed due to configuration error: Invalid permissions on Lambda function”。我不知道怎么用 botocore 添加权限。你可以通过 AWS console 来解决这个问题,找到你的 API, 进到 `/POST` 端点,进到“integration request”,点击“Lambda Function”旁边的编辑图标,修改它,然后保存。此时将弹出一个窗口提示“You are about to give API Gateway permission to invoke your Lambda function”, 点击“OK”。
|
||||
|
||||
当你完成后,记录下 `./tools/deploy.py` 打印出的 URL,像下面这样调用它,然后查看你的新 API 的行为:
|
||||
|
||||
```
|
||||
$ curl -X POST https://a1b2c3d4.execute-api.us-east-1.amazonaws.com/prod/
|
||||
{"status": "success", "meditation": "the count of machines abides"}
|
||||
```
|
||||
|
||||
### 本地运行
|
||||
|
||||
不幸的是,AWS Lambda 没有好的方法能在本地运行你的代码。在这个例子里,我们将用一个简单的 flask 服务器来在本地托管合适的端点,并调用 handler 函数。
|
||||
|
||||
```
|
||||
from __future__ import absolute_import
|
||||
|
||||
from flask import Flask, jsonify
|
||||
|
||||
from server.meditate import handler
|
||||
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
@app.route("/", methods=["POST"])
|
||||
def index():
|
||||
|
||||
class FakeContext(object):
|
||||
aws_request_id = "XXX"
|
||||
|
||||
return jsonify(**handler(None, FakeContext()))
|
||||
|
||||
app.run(host="0.0.0.0")
|
||||
```
|
||||
|
||||
你可以在仓库中用 `./tools/serve.sh` 运行它,像这样调用:
|
||||
|
||||
```
|
||||
$ curl -X POST http://localhost:5000/
|
||||
{
|
||||
"meditation": "your solution requires a blood eagle",
|
||||
"status": "success"
|
||||
}
|
||||
```
|
||||
|
||||
### 测试
|
||||
|
||||
你总是应该测试你的代码。我们的测试方法是导入并运行我们的 handler 函数。这是最基本的 python 测试方法:
|
||||
|
||||
```
|
||||
from __future__ import absolute_import
|
||||
|
||||
import unittest
|
||||
|
||||
from server.meditate import handler
|
||||
|
||||
|
||||
class SubmitTestCase(unittest.TestCase):
|
||||
|
||||
def test_submit(self):
|
||||
|
||||
class FakeContext(object):
|
||||
|
||||
aws_request_id = "XXX"
|
||||
|
||||
response = handler(None, FakeContext())
|
||||
|
||||
self.assertEquals(response["status"], "success")
|
||||
self.assertTrue("meditation" in response)
|
||||
```
|
||||
|
||||
你可以在仓库里通过 nose2 运行这个测试代码。
|
||||
|
||||
### 更多前景
|
||||
|
||||
- **和 AWS 服务的无缝集成。**通过 boto,你可以完美地轻易连接到任何其他的 AWS 服务。你可以轻易地让你的执行角色用 IAM 访问这些服务。你可以从 S3 取文件或放文件到 S3,连接到 Dynamo DB,调用其他 Lambda Function,等等。
|
||||
- **访问数据库。**你也可以轻易地访问远程数据库。在你的 Lambda handler 模块的最上面连接数据库,并在handler 函数中执行查询。你很可能必须从它的安装位置上传相关的包内容才能使它正常工作。可能你也需要静态编译某些库。
|
||||
- **调用其他 webservices。**API Gateway 也是一种把 webservices 的输出从一个格式转换成另一个格式的方法。你可以充分利用这个特点通过不同的 webservices 来代理调用,或者当业务变更时提供后向兼容能力。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: http://blog.ryankelly.us/2016/08/07/going-serverless-with-aws-lambda-and-api-gateway.html
|
||||
|
||||
作者:[Ryan Kelly][a]
|
||||
译者:[messon007](https://github.com/messon007)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://github.com/f0rk/blog.ryankelly.us/
|
||||
[1]: https://github.com/f0rk/meditations
|
||||
[2]: http://blog.ryankelly.us/2016/07/11/jimmy.html
|
@ -0,0 +1,74 @@
|
||||
8 个构建容器应用的最佳实践
|
||||
====
|
||||
|
||||

|
||||
|
||||
容器是未来在共有云和私有云进行应用开发的主要趋势,但是容器到底是什么,为什么它们成为了一种广受欢迎的部署机制,而且你需要怎样来修改你的应用来为容器化的环境优化它?
|
||||
|
||||
### 什么是容器?
|
||||
|
||||
容器技术的历史始于 2000 年的 SELinux 和 2005 年的 Solaris zones。今天,容器是由包括 SELinux、Linux 命名空间和控制组(cgroup)等几项内核特性构成,提供了用户进程、网络空间和文件系统空间的隔离。
|
||||
|
||||
### 为什么它们如此流行?
|
||||
|
||||
最近容器技术大规模的应用在很大程度上是由于旨在使容器更加易于使用的标准的发展,例如 Docker 镜像格式和分布模型,这个标准使用不可变镜像(immutable image),这正是容器运行时环境的起点,不可变镜像可以保证开发团队发布的镜像就是经过测试的,和部署到生产环境中的镜像是同样的镜像。
|
||||
|
||||
容器所提供的轻量级隔离为一个应用组件提供了一个更好的抽象。在容器中运行的组件将不会干扰其它可能直接运行在虚拟机上的应用。它们可以避免对系统资源的争夺,而且除非它们共享一个持久卷,否则不会阻止对同一个文件的写请求。容器使得日志和指标采集的实践得以标准化,而且它们可以在物理机和虚拟机上支持更大的用户密度,所有的这些优点将导致更低的部署成本。
|
||||
|
||||
### 我们应该如何构建一个基于容器的应用呢?
|
||||
|
||||
将应用改为运行在容器中并不是什么很高的要求。主要的 Linux 发行版都有提供了基础镜像,任何可以在虚拟机上运行的程序都可以在上面运行。但是容器化应用的趋势是遵循如下最佳实践:
|
||||
|
||||
#### 1. 实例是一次性的
|
||||
|
||||
你的应用的任何实例都不需要小心地保持运行。如果你的一个运行了许多容器的系统崩溃了,你还能够转移到其它可用的系统去创建新的容器。
|
||||
|
||||
#### 2. 重试而不是崩溃
|
||||
|
||||
当你的应用的一个服务依赖于另一个服务的时候,在另一个服务不可用的时候它应该不会崩溃。例如,你的 API 服务正在启动而且监测到数据库不能连接。你应该设计它使得其不断重试连接,而不是运行失败和拒绝启动。当数据库连接断开的时候 API 可以返回 503 状态码,告诉客户端服务现在不可用。应用应该已经遵守了这个实践,但是如果你正在一个一次性实例的容器环境中工作,那么对这个实践的需要会更加明显。
|
||||
|
||||
#### 3. 持久性数据是特殊的
|
||||
|
||||
容器是基于共享镜像启动,它使用了写时复制(COW)文件系统。如果容器的进程选择写入文件,那么这些写的内容只有在直到容器存在时才存在。当容器被删除的时候,写时复制文件系统中的那一层会被删除。提供给容器一个挂载的文件系统目录,使之在容器存活之外也能持久保存,这需要另外的配置,而且会额外消耗物理存储。明确的抽象定义了什么存储是持久的,催生出了实例是一次性的观点。拥有一个抽象层也使得容器编制引擎可以处理挂载和卸载持久卷的复杂请求,以便这些持久卷可以用于容器。
|
||||
|
||||
#### 4. 使用 stdout 而不是日志文件
|
||||
|
||||
现在你或许会思考,如果持久的数据是特殊的,那么我用日志文件来做什么事情?容器运行时环境和编制引擎项目所采用的方法是进程应该[写入 stdout/stderr][1],而且具有归档和维护[容器日志][2]的基础设施。
|
||||
|
||||
#### 5. 敏感信息(以及其它配置信息)也是特殊的
|
||||
|
||||
你绝不应该将敏感信息例如密码、密钥和证书硬编码到你的镜像中。通常在你的应用与开发服务、测试服务,或者生产服务相交互时,这些敏感信息通常都是不同的。大多数开发者并没有访问生产环境的敏感信息的权限,所以如果敏感信息被打包到镜像中,那么必须创建一个新的镜像层来覆盖这个开发服务的敏感信息。基于这一点来看,你再也不能使用与你们开发团队所创建的和质量测试所测试的相同的镜像了,而且也失去了不可修改的镜像的好处。相反的,这些值应该被存储在环境变量中文件中,它们会在容器启动时导入。
|
||||
|
||||
#### 6. 不要假设服务的协同定位
|
||||
|
||||
在一个编排好的容器环境中,你会希望让编排器将你的容器发送到任何最适合的节点。最适合意味着很多事情:它应该基于那个节点现在拥有最多的空间、容器所需的服务质量、容器是否需要持久卷,等等。这可能意味这你的前端、API 和数据库容器最终都会放在不同的节点。尽管给每个节点强制分配一个 API 容器是可以做到的(参考 Kubernetes 的 [DaemonSets][3]),但这种方式应该留给执行监控节点自身这类任务的容器。
|
||||
|
||||
#### 7. 冗余/高可用计划
|
||||
|
||||
即使你没有那么多负载需要高可用性的配置,你也不应该以单路方式编写服务,否则会阻止它运行多份拷贝。这将会允许你运用滚动式部署,使得将负载从一个节点移动到另外一个节点非常容易,或者将服务从一个版本更新到下一个版本而不需要下线。
|
||||
|
||||
#### 8. 实现就绪检查和灵活性检查
|
||||
|
||||
应用在响应请求之前会有一定的启动时间是一件很正常的事情,例如,一个 API 服务器需要填充内存数据缓存。容器编排引擎需要一种方法来检测你的容器是否准备好服务用户请求。为一个新的容器提供就绪检查可以允许我们进行滚动式部署,使得旧容器可以继续运行直到不再需要它,这可以防止服务宕机。类似的,一个存活检查也是一种容器编排引擎持续检查容器是否在健康可用状态的方法。决定容器健康或者说“存活”应该由容器应用的创建者说了算。一个不再存活的容器将会被结束,而且一个新的容器会被创建来替代它。
|
||||
|
||||
### 想查找更多资料?
|
||||
|
||||
我将会出席十月份的格雷丝霍普计算机女性峰会(Grace Hopper Celebration of Women in Computing),你可以在这里来看一下关于我的访谈:[应用的容器化:是什么,为什么,和如何实现][4]。今年不去 GHC 吗?那你可以在 [OpenShift][5] 和 [Kubernetes][6] 的项目站点来了解关于容器、编排和应用的相关内容。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/life/16/9/8-best-practices-building-containerized-applications
|
||||
|
||||
作者:[Jessica Forrester][a]
|
||||
译者:[LinuxBars](https://github.com/LinuxBars)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/jwforres
|
||||
[1]: https://docs.docker.com/engine/reference/commandline/logs/
|
||||
[2]: http://kubernetes.io/docs/getting-started-guides/logging/
|
||||
[3]: http://kubernetes.io/docs/admin/daemons/
|
||||
[4]: https://www.eiseverywhere.com/ehome/index.php?eventid=153076&tabid=351462&cid=1350690&sessionid=11443135&sessionchoice=1&
|
||||
[5]: https://www.openshift.org/
|
||||
[6]: http://kubernetes.io/
|
@ -0,0 +1,97 @@
|
||||
NitroShare:内网多操作系统间快捷文件共享工具
|
||||
====
|
||||
|
||||
网络的最重要用途之一就是实现文件共享的目的。现在,虽然有多种方式可以让在同一网络中的 Linux 和 Windows 以及 MacOS X 用户之间共享文件,但这篇文章,我们只打算介绍 Nitroshare。这是一款跨平台、开源以及易于使用的应用软件,可以在本地网络(内网)中共享文件。
|
||||
|
||||
Nitroshare 大大简化了本地网络的文件共享操作,一旦安装上,它就会与操作系统无缝集成。Ubuntu 系统中,从应用程序显示面板中可以简单的打开,在 Windows 系统中,在系统托盘中可以找到它。
|
||||
|
||||
此外,在装有 Nirtroshare 的机器上,它会自动检测在同一网段的其它安装了它的设备,用户只需选择好需要传输到的设备,就可以直接向其传输文件。
|
||||
|
||||
Nitroshare 的特性如下:
|
||||
|
||||
- 跨平台,即可以运行于 Linux, Windows 和 MacOS X 系统
|
||||
- 设置容易,无需配置
|
||||
- 易于使用
|
||||
- 支持在本地网络上自动发现运行着 Nitroshare 设备的能力
|
||||
- 安全性上支持可选的 TLS (Transport Layer Security,传输层安全协议) 编码传输方式
|
||||
- 支持网络高速传输功能
|
||||
- 支持文件和目录(Windows 上的文件夹)传输
|
||||
- 支持对发送文件、连接设备等这些的桌面通知功能
|
||||
|
||||
最新版本的 Nitroshare 是使用 Qt5 开发的,它做了一些重大的改进,例如:
|
||||
|
||||
- 用户界面焕然一新
|
||||
- 简化设备发现过程
|
||||
- 移除不同版本传输文件大小的限制
|
||||
- 为了使用方便,已经去除配置向导
|
||||
|
||||
### Linux 系统中安装 Nitroshare
|
||||
|
||||
NitroShare 可运行于各种各样的现代 Linux 发行版和桌面环境。
|
||||
|
||||
#### Debian Sid 和 Ubuntu 16.04+
|
||||
|
||||
NitroShare 已经包含在 Debian 和 Ubuntu 的软件源仓库中,所以可以很容易的就安装上,使用如下命令:
|
||||
|
||||
```
|
||||
$ sudo apt-get install nitroshare
|
||||
```
|
||||
|
||||
但安装的版本可能已经过期了。要安装最新的版本的话,可按照如下的命令添加最新的 PPA。
|
||||
|
||||
```
|
||||
$ sudo apt-add-repository ppa:george-edison55/nitroshare
|
||||
$ sudo apt-get update
|
||||
$ sudo apt-get install nitroshare
|
||||
```
|
||||
|
||||
#### Fedora 24-23
|
||||
|
||||
最近,NitroShare 已经包含在 Fedora 源仓库中了,可以按如下命令安装:
|
||||
|
||||
```
|
||||
$ sudo dnf install nitroshare
|
||||
```
|
||||
|
||||
#### Arch Linux
|
||||
|
||||
在 Arch Linux 系统中,NitroShare 包在 AUR 上已经可用了,可以用如下命令来构建/安装:
|
||||
|
||||
```
|
||||
# wget https://aur.archlinux.org/cgit/aur.git/snapshot/nitroshare.tar.gz
|
||||
# tar xf nitroshare.tar.gz
|
||||
# cd nitroshare
|
||||
# makepkg -sri
|
||||
```
|
||||
|
||||
### Linux 中使用 NitroShare
|
||||
|
||||
注意:如我前面所述,在本地网络中,您想要共享文件的其它机器设备都需要安装上 Nitroshare 并运行起来。
|
||||
|
||||
在成功安装后,在系统 dash 面板里或系统菜单里搜索 Nitroshare,然后启动。Nitroshare 非常容易使用,你可从该应用或托盘图标上找到“发送文件”、“发送目录”、“查看传输”等选项。
|
||||
|
||||

|
||||
|
||||
选择文件后,点击“打开”继续选择目标设备,如下图所示。如果在本地网络有设备正的运行 Nitroshare 的话,选择相应的设备然后点击“确定”。
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
如果需要,在 NitroShare 的配置 -- 通用标签页里,您可以增加设备的名字,设置默认文件下载位置,在高级设置里您能设置端口、缓存、超时时间等等。
|
||||
|
||||
主页:<https://nitroshare.net/index.html>
|
||||
|
||||
这就是所要介绍的,如果您有关于 Nitroshare 的任何问题,可以在下面的评论区给我们分享。您也可以给我们提供一些建议,告诉一些可能我们不知道的很不错的跨平台文件共享应用程序。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: http://www.tecmint.com/nitroshare-share-files-between-linux-ubuntu-windows/
|
||||
|
||||
作者:[Aaron Kili][a]
|
||||
译者:[runningwater](https://github.com/runningwater)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: http://www.tecmint.com/author/aaronkili/
|
@ -0,0 +1,159 @@
|
||||
用 Ansible 来交付 Vagrant 实例
|
||||
====
|
||||
|
||||

|
||||
|
||||
Ansible 是一款系统管理员进行自动化运维的强大工具。Ansible 让配置、交付、管理各种容器,软件部署[变得非常简单][1]。基于轻量级模块的架构非常适合系统管理,一个优点就是如果某个节点没有被 Ansible 管理的话,它的资源就不会被使用。
|
||||
|
||||
这篇文章介绍用 Ansible 来配置 [Vagrant 实例][2],它是一个配置好的基础虚拟机映像,包含了开发环境中需要用到的工具。你可以用它来部署开发环境,然后和其他成员协同工作。用 Ansible,你可以用你的开发包自动化交付 Vagrant 实例。
|
||||
|
||||
我们用 Fedora 24 做主机,用 [CentOS][3] 7 来作 Vagrant 实例。
|
||||
|
||||
### 设置工作环境
|
||||
|
||||
在用 Ansible 配置 Vagrant 实例时,你需要做几件准备的事情。首先在宿主机上安装 Ansible 和 Vagrant,在你的主机上运行下面的命令来安装:
|
||||
|
||||
```
|
||||
sudo dnf install ansible vagrant vagrant-libvirt
|
||||
```
|
||||
|
||||
上面的命令将 Ansible 和 Vagrant 在你的宿主机上,以及包括 Vagrant 的 libvirt 接口。Vagrant 并没有提供托管你的虚拟机的功能,需要第三方工具比如:libirt、VirtualBox、VMWare 等等。这些工具可以直接与你的 Fedora 系统上的 libvirt 和 KVM 协同工作。
|
||||
|
||||
接着确认你的账户在正确的 wheel 用户组当中,确保你可以运行系统管理员命令。如果你的账号在安装过程中就创建为管理员,那么你就肯定在这个用户组里。运行下面的命令查看:
|
||||
|
||||
```
|
||||
id | grep wheel
|
||||
```
|
||||
|
||||
如果你能看到输出,那么你的账户就在这个组里,可以进行下一步。如果没有的话,你需要运行下面的命令,这一步需要你提供 root 账户的密码,将 \<username> 换成你的用户名:
|
||||
|
||||
```
|
||||
su -c 'usermod -a -G wheel <username>'
|
||||
```
|
||||
|
||||
然后,你需要注销然后重新登录,确保在用户组里。
|
||||
|
||||
现在要建立你的第一个 Vagrant 实例了,你需要用 Ansible 来配置它。
|
||||
|
||||
### 设置 Vagrant 实例
|
||||
|
||||
配置一个镜像实例之前,你需要先创建它。创建一个目录,存放 Vagrant 实例 相关的文件,并且将它作为当前工作目录,用下面这条命令:
|
||||
|
||||
```
|
||||
mkdir -p ~/lampbox && cd ~/lampbox
|
||||
```
|
||||
|
||||
在创建镜像实例之前,你需要搞清楚目的,这个镜像实例是一个运行 CentOS 7 基础系统,模板包括 Apache 的 Web 服务,MariaDB(MySQL 原开发者创建的一个流行的开源数据库)数据库和 PHP 服务。
|
||||
|
||||
初始化 Vagrant 实例,用 `vagrant init` 命令:
|
||||
|
||||
```
|
||||
vagrant init centos/7
|
||||
```
|
||||
|
||||
这个命令初始化 Vagrant 实例,并创建一个名为 Vagrantfile 的文件,包含一些预先配置的变量。打开并编辑它,下面的命令显示了用于这次配置的基本镜像实例。
|
||||
|
||||
```
|
||||
config.vm.box = "centos/7"
|
||||
```
|
||||
|
||||
现在设置端口转发,以便你配置完毕 Vagrant 实例并让它运行起来之后可以测试它。将下述配置加入到 Vagrantfile 的最终的 `end` 语句之前:
|
||||
|
||||
```
|
||||
config.vm.network "forwarded_port", guest: 80, host: 8080
|
||||
```
|
||||
|
||||
这个命令将 Vagrant 实例 的 80 端口映射为主机的 8080 端口。
|
||||
|
||||
下一步是设置 Ansible 作为配置 Vagrant 实例的工具,将下述配置加入到 Vagrantfile 的 `end` 语句之前,将 Ansible 作为配置工具(provisioning provider):
|
||||
|
||||
```
|
||||
config.vm.provision :ansible do |ansible|
|
||||
ansible.playbook = "lamp.yml"
|
||||
end
|
||||
```
|
||||
|
||||
(必须将这三行在最后的 `end` 语句之前加入)注意 `ansible.playbook = "lamp.yml"` 这一句定义了配置镜像实例的 Ansible playbook 的名字。
|
||||
|
||||
### 创建 Ansible playbook
|
||||
|
||||
在 Ansible 之中,playbook 是指在你的远端节点执行的策略,换句话说,它管理远端节点的配置和部署。详细的说,playbook 是一个 Yaml 文件,在里面写入你要在远端节点上将要执行的任务。所以,你需要创建一个名为 lamp.yml 的 playbook 来配置镜像实例。
|
||||
|
||||
在 Vagrantfile 相同的目录里创建一个 lamp.yml 文件,将下面的内容粘贴到文件当中:
|
||||
|
||||
```
|
||||
---
|
||||
- hosts: all
|
||||
become: yes
|
||||
become_user: root
|
||||
tasks:
|
||||
- name: Install Apache
|
||||
yum: name=httpd state=latest
|
||||
- name: Install MariaDB
|
||||
yum: name=mariadb-server state=latest
|
||||
- name: Install PHP5
|
||||
yum: name=php state=latest
|
||||
- name: Start the Apache server
|
||||
service: name=httpd state=started
|
||||
- name: Install firewalld
|
||||
yum: name=firewalld state=latest
|
||||
- name: Start firewalld
|
||||
service: name=firewalld state=started
|
||||
- name: Open firewall
|
||||
command: firewall-cmd --add-service=http --permanent
|
||||
```
|
||||
|
||||
每一行代表的意思:
|
||||
|
||||
- `hosts: all` 指定该 playbook 需要在 Ansible 配置文件中定义的所有主机上都执行,因为还没定义主机, playbook 将只在本地运行。
|
||||
- `sudo: true` 表明该任务需要用 root 权限运行。(LCTT 译注:此语句上述配置中缺失。)
|
||||
- `tasks:` 指定当 playbook 运行是需要执行的任务,在这一节之下:
|
||||
- `name: ...` 描述任务的名字
|
||||
- `yum: ...` 描述该任务应该由 yum 模块执行,可选的 key=value 键值对将由 yum 模块所使用。
|
||||
|
||||
当 playbook 运行时,它会安装最新的 Apache Web 服务(http),MariaDB 和 PHP。当安装完毕并启动防火墙 firewalld,给 Apache 打开一个端口。你可以通过编写 playbook 来完成这些。现在可以配置它了。
|
||||
|
||||
### 配置镜像 实例
|
||||
|
||||
用 Ansible 配置 Vagrant 实例只需要以下几步了:
|
||||
|
||||
```
|
||||
vagrant up --provider libvirt
|
||||
```
|
||||
|
||||
上面的命令运行 Vagrant 实例,将实例的基础镜像下载到宿主机当中(如果还没下载的话),然后运行 lamp.yml 来进行配置。
|
||||
|
||||
如果一切正常,输出应该和下面的例子类似:
|
||||
|
||||

|
||||
|
||||
这个输出显示镜像实例已经被配置好了,现在检查服务是否可用,在宿主机上打开浏览器,输入 `http://localhost:8080`,记住本地主机的 8080 端口是 Vagrant 实例映射过来的 80 端口。你应该可以看到如下的 Apache 的欢迎界面。
|
||||
|
||||

|
||||
|
||||
要修改你的 Vagrant 实例,你可以修改 lamp.yml,你能从 Ansible 的[官网][4]上找到很多文章。然后运行下面的命令来重新配置:
|
||||
|
||||
```
|
||||
vagrant provision
|
||||
```
|
||||
|
||||
### 总结
|
||||
|
||||
现在我们知道怎么用 Ansible 来配置 Vagrant 实例了。这只是一个基本的例子,但是你可以用这些工具来实现不同的例子。比如你可以用所需工具的最新版本来部署一个完整的应用。现在你可以用 Ansible 来配置你自己的远端服务器和容器了。
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://fedoramagazine.org/using-ansible-provision-vagrant-boxes/
|
||||
|
||||
作者:[Saurabh Badhwar][a]
|
||||
译者:[jiajia9linuxer](https://github.com/jiajia9linuxer)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: http://h4xr.id.fedoraproject.org/
|
||||
[1]: https://ansible.com/
|
||||
[2]: https://www.vagrantup.com/
|
||||
[3]: https://centos.org/
|
||||
[4]: http://docs.ansible.com/ansible/index.html
|
@ -0,0 +1,56 @@
|
||||
解决 Linux 内核代码审查人员短缺问题
|
||||
====
|
||||
|
||||
操作系统安全是[现在最重要的事情](http://www.infoworld.com/article/3124432/linux/is-the-linux-kernel-a-security-problem.html),而 Linux 则是一个主要被讨论的部分。首先要解决的问题之一就是:我们如何确定提交到上游的补丁已经进行了代码审核?
|
||||
|
||||
Wolfram Sang 从 2008 年开始成为一名 Linux 内核开发者,他经常在各地召开的 Linux 峰会上发表讲话,比如在 [2016 年柏林 Linux 峰会](https://linuxconcontainerconeurope2016.sched.org/event/7oA4/kernel-development-i-still-think-we-have-a-scaling-problem-wolfram-sang-consultant),他提出了如何提高内核开发实践的想法。
|
||||
|
||||
让我们来看看他的观点。
|
||||
|
||||

|
||||
|
||||
**在 2013 年的时候,你曾在爱丁堡(Edinburgh)提醒 ELCE 委员会,如果不作出改变,那么子系统的潜在问题和其他争议问题将会逐渐扩大。他们做出改变了吗?你所提及的那些事件发生了吗?**
|
||||
|
||||
是的,在某些程度上来说。当然了,Linux 内核是一个很多部分组成的项目,所以给以 Linux 各个子系统更多关注应该放在一个更重要的位置。然而,有太多的子系统“只是拼图中的一块”,所以通常来说,这些子系统的潜在问题还未被解决。
|
||||
|
||||
**你曾指出代码审核人数是一个大问题。为何你觉得 Linux 内核开发社区没有足够的代码审核人员呢?**
|
||||
|
||||
理由之一就是,大多数开发者实际上只是编写代码,而读代码并不多。这本是没有什么错,但却说明了并非每个人都是代码审核人员,所以我们真的应该鼓励每个人都进行代码审核。
|
||||
|
||||
我所看到另一件事就是,但我们要请人员加入我们的社区时,最重要的考核就是补丁贡献数量。我个人认为这是很正常的,并且在初期总贡献量少的时候是非常好的做法。但是随着越来越多的人员,特别是公司的加入,我们就碰到源码审核的问题。但是别误解了,有着数量可观的贡献是很棒的。但目前需要指出的是,参与社区有着更多内涵,比方说如何为下一步发展负责。有些部分在改善,但是还不够。
|
||||
|
||||
**你认为更多的代码审核人员培训或者审核激励措施是否会有帮助?**
|
||||
|
||||
我最主要的观点就是要指出,现今仍存在问题。是的,目前为止我们做到很好,但不意味着全都做的很好。我们也有类似扩张方面的问题。让人们了解事实,是希望能够让一些团体对此感兴趣并参与其中。尽管,我并不认为我们需要特殊的训练。我所熟悉的一些代码审核人员都非常棒或者很有天赋,只是这类人太少或者他们的空闲时间太少。
|
||||
|
||||
首先就是需要有这种内在动力,至于其它的,边做边学就非常好了。这又是我想要指出的优势之一:审核补丁能够使你成为更出色的代码开发者。
|
||||
|
||||
**依你之见,是否有那么一个受欢迎的大项目在扩张这方面做的很好,可以供我们借鉴?**
|
||||
|
||||
我还真不知道有这么一个项目,如果有的话随时借鉴。
|
||||
|
||||
我很专注于 Linux 内核,所以可能会存在一些偏见。然而在我看来,Linux 内核项目在规模大小、贡献数量和多样性方面真的很特别。所以当我想要找另一个项目来寻找灵感以便改善工作流是很正常的想法,目前我们的扩张问题真的比较特别。而且我发现,看看其他子系统在内核中做了什么是一个很有的方法。
|
||||
|
||||
**你曾说安全问题是我们每个人都该想到的事情,那用户应该做些什么来避免或者改善安全问题的危险?**
|
||||
|
||||
在今年(2016年)柏林 Linux 峰会我的谈话是针对开发层面的。安全隐患可能来自于没有正确审核的补丁中。我并不想要用户亲自解决这种问题,我更希望这些安全问题永远不会出现。当然这是不可能的,但这仍然是我处理问题所首选的方法。
|
||||
|
||||
**我很好奇这个庞大社区如何改善这些问题。是否有你希望用户定期以文件形式提交的某些类型的错误报告?需要定期检查的区域却因为某些原因没有注意到的?**
|
||||
|
||||
我们并不缺少错误报告。我所担心的是:由于代码审核人员的短缺造成补丁不完整,从而导致更多的错误报告。所以,到时候不仅需要处理大量的贡献,还需要处理更多错误或者进行版本回退。
|
||||
|
||||
**你是否还有什么事情希望我们读者知道,以了解你所在的努力?**
|
||||
|
||||
Linux 内核的特殊性,常常让我牢记着,在底层它就是代码而已。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/business/16/10/linux-kernel-review
|
||||
|
||||
作者:[Deb Nicholson][a]
|
||||
译者:[GHLandy](https://github.com/GHLandy)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/eximious
|
@ -0,0 +1,85 @@
|
||||
又一顶帽子:适用于初学者的 FEDORA —— CHAPEAU LINUX 24 已发布
|
||||
===================
|
||||
|
||||

|
||||
|
||||
[Chapeau][23] 是专注于初学者的[一个基于 Fedora 的 Linux 发行版][22]。 Chapeau Linux 最近发布了新的 24 版本。
|
||||
|
||||
正如名字所暗示的,Chapeau 24 基于 Fedora 24。所以,你可以在 Chapeau 24 中找到大多数(如果不是全部)的[Fedora 24 特性][21]。
|
||||
|
||||
我在这儿增加一个细节。你可能已经知道 [Fedora 是一种帽子][20]。我认为因为 [Fedora][19] 是来自[红帽][18]的一个社区项目,所以他们命名它为另一种帽子。有趣的是,[Chapeau 也是一种帽子][17],一种法国帽子。现在,这些名字变得有意义了,不是吗?如果你对这样的细节性事实感兴趣,可以去了解一下其它 [Linux 发行版命令习惯][16]的背后的逻辑。
|
||||
|
||||
### CHAPEAU 24 特性
|
||||
|
||||
Chapeau 24 的特性几乎和 Fedora 24 提供的特性一样。它仍然运行在 GNOME 3.20 上,这是可以理解的,因为[GNOME 3.22][15] 最近才刚发布。Chapeau 24 发行版一些主要的新亮点是:
|
||||
|
||||
* [Gnome][10] 3.20 桌面环境
|
||||
* LibreOffice 5
|
||||
* [PlayOnLinux][9] 和 [Wine][8]
|
||||
* [Steam][7]
|
||||
* [VLC][6]
|
||||
* [Mozilla 火狐浏览器][5],带有 [Adobe Flash][4]
|
||||
* [硬件帮助工具(hht)][3](在 [Chapeau 23][2] 中引入,这个工具能够帮助你找到硬件的驱动程序)
|
||||
* 预配置了 [RPMFusion][1] 软件源
|
||||
* 媒体解码和 DVD 回放支持
|
||||
* Gnome Boxes
|
||||
* KVM 虚拟化
|
||||
* Dropbox 集成
|
||||
* UI 改善
|
||||
* 博通(Broadcom)无线芯片硬件
|
||||
* 针对佳能打印机的 CUPS 后端
|
||||
* Linux 4.7 内核
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
### 应该使用 CHAPEAU 24 吗?
|
||||
|
||||
这是一个很难回答的问题。看,在 Linux 的世界里,我们有超过 300 种活跃的 Linux 发行版。这些系统大量是针对桌面用户的。
|
||||
|
||||
这取决于个人更偏爱什么样的系统。你可以完整的安装 Fedora 24 和它所伴有的各种工具,然后你不需要再到其他地方寻找这些工具。但是你可能也知道 Fedora 对专有硬件支持非常“吝啬”。
|
||||
|
||||
总之, Chapeau 是一个很好的 Linux 版本,使用它能够不像使用 Fedora 那么“头疼”。如果你喜欢 GNOME,那么 Chapeau Linux 会是你的菜。
|
||||
|
||||
你可以从 SourceForge 下载 Chapeau 24:
|
||||
|
||||
- [下载 Chapeau 24][12]
|
||||
|
||||
你已经尝试使用 Chapeau 24 了吗?你的使用体验是什么样的?
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://itsfoss.com/chapeau-linux-24-released/
|
||||
|
||||
作者:[Abhishek Prakash][a]
|
||||
译者:[ucasFL](https://github.com/ucasFL)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://itsfoss.com/author/abhishek/
|
||||
[1]:http://rpmfusion.org/
|
||||
[2]:https://itsfoss.com/chapeau-23-armstrong-released/
|
||||
[3]:http://chapeaulinux.org/hardware-helper-tool
|
||||
[4]:http://www.adobe.com/products/flashplayer.html
|
||||
[5]:https://www.mozilla.org/en-US/firefox/desktop
|
||||
[6]:http://www.videolan.org/
|
||||
[7]:https://itsfoss.com/install-steam-ubuntu-linux/
|
||||
[8]:https://itsfoss.com/use-windows-applications-linux/
|
||||
[9]:http://www.playonlinux.com/
|
||||
[10]:http://www.gnome.org/
|
||||
[12]:https://sourceforge.net/projects/chapeau/files/releases/Chapeau_24_x86-64.iso/download
|
||||
[13]:https://itsfoss.com/wp-content/uploads/2016/09/chapeau-24_desktop_wine.jpg
|
||||
[14]:https://itsfoss.com/wp-content/uploads/2016/09/chapeau-24-desktop-1.jpg
|
||||
[15]:https://itsfoss.com/gnome-3-22-new-features/
|
||||
[16]:https://itsfoss.com/linux-code-names/
|
||||
[17]:https://en.wikipedia.org/wiki/Chapeau
|
||||
[18]:https://www.redhat.com/en
|
||||
[19]:https://getfedora.org/
|
||||
[20]:https://en.wikipedia.org/wiki/Fedora
|
||||
[21]:https://itsfoss.com/fedora-24-released/
|
||||
[22]:https://itsfoss.com/best-fedora-linux-distributions/
|
||||
[23]:http://chapeaulinux.org/
|
||||
[24]:https://itsfoss.com/wp-content/uploads/2016/09/chapeau-24-release.jpg
|
||||
|
@ -1,17 +1,15 @@
|
||||
OneNewLife translated
|
||||
|
||||
为何 Linux 之父 Linus Torvalds 选择 x86 芯片而不是 ARM 处理器
|
||||
为何 Linux 之父 Linus Torvalds 在 ARM 会议上说他喜欢 x86
|
||||
=============
|
||||
|
||||
**Torvalds 因为 x86 的基础架构和生态系统而对其宠爱有加**
|
||||
|
||||

|
||||
|
||||
*Linus Torvalds 于 1999 年 8 月 10 日在加州圣何塞举行的 LinuxWorld 节目中给挤满礼堂的 Linux 发烧友作演讲。 ——出自:James Niccolai*
|
||||
*Linus Torvalds 于 1999 年 8 月 10 日在加州圣何塞举行的 LinuxWorld 节目中给挤满礼堂的 Linux 发烧友们作演讲。 ——出自:James Niccolai*
|
||||
|
||||
Linux 之父 Linus Torvalds 是一个直率的人——他总是心口如一。比方说最近在 Linux 内核 4.8 的 [事故][1] 中,他没有文过饰非,而是承认了自己的过失。
|
||||
Linux 领袖 Linus Torvalds 是一个直率的人——他总是心口如一。比方说最近在 Linux 内核 4.8 的 [事故][1] 中,他没有文过饰非,而是承认了自己的过失。
|
||||
|
||||
不过他在上周的 Linaro Connect 会议上倒是 [让人瞠目结舌][2]。当他被问到最喜欢的芯片架构的时候,他不假思索地说 x86,而不是 ARM。
|
||||
不过他在上周的 Linaro Connect 会议上倒是[让人瞠目结舌][2]。当他被问到最喜欢的芯片架构的时候,他不假思索地说 x86,而不是 ARM。
|
||||
|
||||
或许是 x86 电脑悠久的历史让他得出这个答案。x86 没有多少碎片化的软件和硬件,它几乎仅仅是用来工作的。
|
||||
|
||||
@ -23,39 +21,38 @@ Torvalds 说,人们总是痴迷于指令集和 CPU 核心,但事实是围绕
|
||||
|
||||
而 ARM 则迥然不同。从硬件供应商的角度来看,它引领着一个碎片化的市场,Torvalds 说。
|
||||
|
||||
“x86 的生态系统一向都秉承着兼容为先的理念,而 ARM 则不以为然,”Torvalds 在炉边与一位 ARM 开发者聊天时如是说。
|
||||
“x86 的生态系统一向都秉承着兼容为先的理念,而 ARM 则不以为然,”Torvalds 在与 ARM 开发者进行的一场炉边闲谈时如是说。
|
||||
|
||||
ARM 主导了移动设备的市场,有大量的设备都是使用基于 Linux 内核的安卓操作系统的。但是 ARM 的生态系统太过于碎片化了,这导致了很多支持和设备的问题。
|
||||
|
||||
ARM 主导了移动设备的市场,有大量的安卓设备是基于 Linux 内核的。但是 ARM 的生态系统太过于碎片化了,这导致了很多支持和设备的问题。
|
||||
问题之一:由于硬件的配置不同,在所有移动设备上部署同一个版本的 Android 是不可能的。硬件制造商会调整 Android 系统以兼容他们设备的芯片组。不像 Windows 更新到 PC,一个 Android 更新无法推送到所有的移动设备。
|
||||
|
||||
有一个问题:由于硬件的配置不同,在所有移动设备上部署同一个版本的 Android 是不可能的。硬件制造商会调整 Android 系统以兼容他们设备的芯片组。不像 Windows 更新到 PC,一个 Android 更新无法推送到所有的移动设备。
|
||||
英特尔尝试过将 x86 芯片放在智能手机上,但是现在已经放弃了。英特尔的其中一个目标就是推送可以在所有 x86 手机上下载并安装成功的[安卓更新][3]。
|
||||
|
||||
英特尔尝试过将 x86 芯片放在智能手机上,但是现在已经放弃了。英特尔的其中一个目标就是推送可以在所有 x86 手机上下载并安装成功的 [安卓更新][3]
|
||||
|
||||
还有 ARM 服务器软件的开发问题。每个芯片组的架构、网络和 I/O 特性不同,必须编写软件才能利用这些特性。这大大减慢了服务器中采用 ARM 的速度。x86 不存在匹配的问题,它将继续主导服务器市场。
|
||||
还有 ARM 服务器软件的开发问题。每个芯片组的架构、网络和 I/O 特性不同,必须编写软件才能利用这些特性。这大大减慢了服务器中采用 ARM 的速度。x86 不存在适配的问题,它将继续主导服务器市场。
|
||||
|
||||
“我对于 ARM 作为一个硬件平台而不是一个指令集感到非常失望,虽然我也有我的问题,”Torvalds 说。“作为一个硬件平台,它始终不太好对付。”
|
||||
|
||||
Torvalds 长大后在一台装配 8 位的 6502 处理器的微机上编程,他很喜欢这种架构,因为它的指令是流式的,当时还没有其它硬件可以与之媲美。这种架构为芯片提供了更高的性能。
|
||||
Torvalds 小时候在一台装配有 8 位的 6502 处理器的微机上编程,他很喜欢这种架构,因为它的指令是流式的,当时还没有其它硬件可以与之媲美。这种架构为芯片提供了更高的性能。
|
||||
|
||||
“我那时想升级的是一台 Acorn Archimedes,呃,给 ARM 命名的机器,“Torvalds说,“那曾经是我梦寐以求的机器。”
|
||||
“我那时想升级的是一台 Acorn Archimedes,呃,ARM 就是因该公司而命名的,“Torvalds说,“那曾经是我梦寐以求的机器。”
|
||||
|
||||
[Archimedes][4] 是第一台基于 Acorn 电脑公司的 ARM RISC 芯片的个人电脑。ARM 作为 Acorn 的一个分支而成立。
|
||||
[Archimedes][4] 是第一台基于 Acorn 电脑公司的 ARM RISC 芯片的个人电脑。ARM 作为 Acorn 的一个分支而成立。(LCTT 译注:ARM 的缩写来自于 Acorn RISC Machine。——引自[维基百科](https://en.wikipedia.org/wiki/Acorn_Archimedes)。)
|
||||
|
||||
Torvalds 喜欢 Archimedes,因为它搭载了像 6502 一样的流式的 RAM 芯片以获得高性能。不尽人意的是,他找不到那台电脑。
|
||||
Torvalds 喜欢 Archimedes,因为它搭载了像 6502 一样的流式指令和 RAM 芯片以获得高性能。不尽人意的是,他找不到那台电脑。
|
||||
|
||||
他尝试过一台“古怪的英式电脑”,[Sinclair QL][5],这是一台比 Acorn Archimedes 还要失败的机器,Torvalds 说。
|
||||
|
||||
“那时的芬兰不是宇宙的中心,”Torvalds 说。“在那之后我吸取教训了——再也没有去买没有基础设施的机器。”
|
||||
“那时的芬兰不是宇宙的中心,”Torvalds 说。“在那之后我吸取教训了——再也没有去买没有基础设施(生态)的机器。”
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
编译自: http://www.pcworld.com/article/3129300/linux/why-linux-pioneer-linus-torvalds-prefers-x86-over-arm.html
|
||||
via: http://www.pcworld.com/article/3129300/linux/why-linux-pioneer-linus-torvalds-prefers-x86-over-arm.html
|
||||
|
||||
作者:[Agam Shah][a]
|
||||
译者:[OneNewLife](https://github.com/OneNewLife)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
@ -0,0 +1,52 @@
|
||||
ORWL:能够删除被篡改数据的小型开源计算机
|
||||
===========
|
||||
|
||||

|
||||
|
||||
在当今这个信息时代,安全是最重要的。恐怕没有人会希望自己的重要数据落入到坏人的手里。但是即便是无安全防护的硬件同样面临不少威胁,而大多数时候人们还只是对软件采取安全防护措施。ORWL 就是来改变这件事的。
|
||||
|
||||
### [ORWL 是什么?](http://www.design-shift.com/orwl/)
|
||||
|
||||
ORWL 宣称是社区里“造得最安全的家用电脑”。 它是一台小型的飞碟形计算机,在设计上全面考虑了物理安全性。物理安全很重要,因为一旦有人获得了从物理上访问你的计算机的途径,那么就 Game Over 了,这是信息安全专业人员中的一个老生常谈。
|
||||
|
||||

|
||||
|
||||
ORWL 的基本规格包括英特尔 Skylake M3 处理器、USB-C 和微型 HDMI 接口、8GB 内存、120G 固态硬盘、蓝牙、Wifi 和 NFC 技术。目前它支持的操作系统有 Ubuntu 16.04、Qubes OS,以及 Windows 10 等,开箱即用。你只需要有一个显示器,键盘和鼠标就可以开始使用它了。
|
||||
|
||||
### ORWL 是开源的
|
||||
|
||||
ORWL 是**完全**开源的。这意味着,如果有人想设计一台自己的计算机或者对 ORWL 作出改进的话,原理图和设计文件、软件、固件、所有东西都是可以获取的。
|
||||
|
||||

|
||||
|
||||
### ORWL 是如何工作的?
|
||||
|
||||
ORWL 使用自加密固态硬盘(SSD)。一个安全微控制器集成到其主板上来产生和存储加密密匙。一旦核实了系统的完整性和已验证用户,它就使用密匙来解密固态硬盘(SSD)。无论对 ORWL 进行任何类型的篡改,密匙都会立即删除固态硬盘(SSD)上的无用数据
|
||||
|
||||
为了完成身份验证,ORWL 有一个使用和智能卡类似技术的密匙卡。它使用 NFC 技术来验证用户,同时使用蓝牙来检测用户是否在当前使用范围内。如果用户不在附近(不在使用范围内),ORWL 将会自动锁定。
|
||||
|
||||

|
||||
|
||||
整个 ORWL 系统被包裹在一个到处伴有压力开关的活动翻盖网格里。安全微控制器持续监控专用惯性测量部件,活动翻盖网格,内部温度和电源输入电压,以用于检测篡改。这将防止访问内部组件,比如试图破坏翻盖将会触发安全微控制器从而删除加密密匙。此外,出于安全考虑,动态随机存储器(DRAM)也焊有外壳。
|
||||
|
||||
这并不是全部安全防护措施,ORWL 还有更多详细的措施来确保设备绝对的物理安全性,包括冷启动防护,直接存储器访问(DMA)攻击防御等。
|
||||
|
||||
更多信息可以在 [ORWL 引导页](https://www.orwl.org/)找到。这儿是一个关于它如何工作的快速视频。
|
||||
|
||||
### ORWL 是信息安全的最终答案吗?
|
||||
|
||||
令人沮丧的是,ORWL 并不是信息安全的最终答案。ORWL 只能为计算机提供物理安全,尽管这很强大并且看起来极酷(totally ninja),但是还有许多来自其他方面的攻击会损坏你的系统。然而,ORWL 确实从整体上提高了计算机的安全性。
|
||||
|
||||
你认为 ORWL 怎么样?通过评论让我们知道你的想法。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://itsfoss.com/orwl-physically-secure-computer/
|
||||
|
||||
作者:[Munif Tanjim][a]
|
||||
译者:[ucasFL](https://github.com/ucasFL)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://itsfoss.com/author/munif/
|
120
published/201610/20161012 7 Mistakes New Linux Users Make.md
Normal file
120
published/201610/20161012 7 Mistakes New Linux Users Make.md
Normal file
@ -0,0 +1,120 @@
|
||||
7 个 Linux 新手容易犯的错误
|
||||
===================
|
||||
|
||||
换操作系统对每个人来说都是一件大事——尤其是许多用户根本不清楚操作系统是什么。
|
||||
|
||||
然而,从 Windows 切换到 Linux 特别地困难。这两个操作系统有着不同的前提和优先级,以及不同的处理方式。结果导致 Linux 新手容易混淆,因为他们在 Windows 上面得到经验不再适用。
|
||||
|
||||
例如,这里有 7 个 Windows “难民”开始使用 Linux 的时候会犯的错误(没有先后顺序):
|
||||
|
||||
### 7. 选择错误的 Linux 发行版
|
||||
|
||||
Linux 有几百个不同的版本,或者按他们的称呼叫做发行版(distributions)。其中许多是专门针对不同的版本或用户的。选择了错误的版本,你与 Linux 的第一次亲密体验将很快变成一个噩梦。
|
||||
|
||||
如果你是在朋友的帮助下切换的话,确认他们的建议是适合你,而不是他们。有大量的文章可以帮助到你,你只需要关注前 20 名左右的或者列在 [Distrowatch][46] 的即可,就不太可能会搞错。
|
||||
|
||||
更好的做法是,在你安装某个发行版之前先试试它的 [Live DVD][45]。Live DVD 是在外设上运行发行版的,这样可以允许你在不对硬盘做任何改动的情况下对其进行测试。事实上,除非你知道怎么让硬盘在 Linux 下可访问,否则你是不会看到你的硬盘的。
|
||||
|
||||
### 6. 期待什么都是一样的
|
||||
|
||||
由于经验有限,许多 Windows 用户不知道新的操作系统意味着新的程序和新的处理方式。事实上你的 Windows 程序是无法在 Linux 上运行的,除非你用 [WINE][44] 或者 Windows 虚拟机。而且你还不能用 MS Office 或者 PhotoShop —— 你必须要学会使用 LibreOffice 和 Krita。经过这些年,这些应用可能会有和 Windows 上的应用类似的功能,但它们的功能可能具有不同的名称,并且会从不同的菜单或工具栏获得。
|
||||
|
||||
就连很多想当然的都不一样了。Windows 用户会特别容易因为他们有多个桌面环境可以选择而大吃一惊——至少有一个主要的和很多次要的桌面环境。
|
||||
|
||||
### 5. 安装软件的时候不知所措
|
||||
|
||||
在 Windows 上,新软件是作为一个完全独立的程序来安装的。通常它囊括了其它所需的依赖库。
|
||||
|
||||
有两种叫做 [Flatpak][43] 和 [Snap][42] 的软件包服务目前正在 Linux 上引进类似的安装系统,但是它们对于移动设备和嵌入式设备来说太大了。更多情况下,Linux 依赖于包管理系统,它会根据已安装的包来判断软件的依赖包是否是必需的,从而提供其它所需的依赖包。
|
||||
|
||||
笔记本和工作站上的包管理本质上相当于手机或平板电脑上的 Google Play:它速度很快,并且不需要用于安装的物理介质。不仅如此,它还可以节省 20%-35% 的硬盘空间,因为依赖包不会重复安装。
|
||||
|
||||
### 4. 假想软件会自动更新好
|
||||
|
||||
Linux 用户认为控制权很重要。Linux 提供更新服务,不过默认需要用户手动运行。例如,大多数发行版会让你知道有可用的软件更新,但是你需要选择安装这些更新。
|
||||
|
||||
如果你选择更新的话,你甚至可以单独决定每一个更新。例如,你可能不想更新到新的内核,因为你安装了一些东西需要使用当前的内核。又或者你想要安装所有的安全性更新,但不想把发行版更新到一个新的版本。一切都由你来选择。
|
||||
|
||||
### 3. 忘记密码
|
||||
|
||||
许多 Windows 用户因为登录不方便而忘记密码。又或者为了方便起见,经常运行一个管理账户。
|
||||
|
||||
在 Linux 上这两种做法都不容易。许多发行版使用 [sudo][41] 来避免以 root 登录,特别是那些基于 Ubuntu 的发行版,而其它发行版大多数是安装为禁止 root 运行图形界面。但是,如果你在 Linux 上成功绕开了这些限制,请注意你的大部分 Linux 安全性优势都会无效(其实在 Windows 上也不推荐这样做)。
|
||||
|
||||
对了,你是不是在安装程序上看到一个自动登录的选项?那是在不常用的情景下使用的,例如不包含隐私信息的虚拟机。
|
||||
|
||||
### 2. 担心没有碎片整理和杀毒软件
|
||||
|
||||
Linux 偶尔需要进行碎片整理,不过只有在恢复分区或者分区差不多满了的时候。并且由于固态硬盘越来越火,碎片整理正在变成过去时,尽管固态硬盘确实需要在任何操作系统上定期运行 [trim][40]。
|
||||
|
||||
同样地,只有当你安装的 Linux 经常传输文件给 Windows 机器的时候,杀毒软件才是一个主要问题。很少有 Linux 病毒或恶意软件存在,并且日常使用非 root 用户、使用强密码、经常备份当前文件就已经足够阻止病毒了。
|
||||
|
||||
### 1. 认为自己没有软件可用
|
||||
|
||||
Windows 上的软件是收费的,大多数类别由一家公司独占——例如,办公套装 MS Office 以及图形和设计的 Adobe。这些条件鼓励用户坚持使用相同的应用程序,尽管它们错漏百出。
|
||||
|
||||
在 Linux 上,故事情节不一样了。只有少数高端程序是收费的,而且几乎每一类软件都有两三个替代品,所有这些可用的软件都可以在 10 分钟或者更短的时间内下载好。如果一个替代品不合你口味,你可以删掉它然后毫不费力就可以再装一个其它的。在 Linux 上,你几乎总会有选择。
|
||||
|
||||
### 过渡期
|
||||
|
||||
可能没有那么多建议可以让 Windows 用户充分准备好切换到 Linux。即使说新用户应该保持开放的心态也是没什么用的,因为他们的期望总是太高,以至于许多用户都没有意识到自己有如此高的期望。
|
||||
|
||||
Linux 新手可以做的最好的事情就是调整心态,并且花一点时间来适应它们。过渡期会需要一些功夫,不过,从长远来看,你的多次尝试终会得到回报。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: http://www.datamation.com/open-source/7-mistakes-new-linux-users-make.html
|
||||
|
||||
作者:[Bruce Byfield][a]
|
||||
译者:[OneNewLife](https://github.com/OneNewLife)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: http://www.datamation.com/author/Bruce-Byfield-6030.html
|
||||
[1]: https://www.youtube.com/channel/UCOfXyFkINXf_e9XNosTJZDw
|
||||
[2]: https://www.youtube.com/user/desainew
|
||||
[3]: https://www.youtube.com/channel/UCEQXp_fcqwPcqrzNtWJ1w9w
|
||||
[4]: http://www.facebook.com/sharer/sharer.php?u=https%3A%2F%2Ffreedompenguin.com%2Farticles%2Fopinion%2Fopen-source-design-thing%2F
|
||||
[5]: http://twitter.com/intent/tweet/?text=Is+Open+Source+Design+a+Thing%3F&url=https%3A%2F%2Ffreedompenguin.com%2Farticles%2Fopinion%2Fopen-source-design-thing%2F
|
||||
[6]: https://plus.google.com/share?url=https%3A%2F%2Ffreedompenguin.com%2Farticles%2Fopinion%2Fopen-source-design-thing%2F
|
||||
[7]: https://atom.io/
|
||||
[8]: http://froont.com/
|
||||
[9]: https://webflow.com/
|
||||
[10]: https://gravit.io/
|
||||
[11]: http://getbootstrap.com/
|
||||
[12]: https://inkscape.org/en/
|
||||
[13]: https://www.gimp.org/
|
||||
[14]: https://en.wikipedia.org/wiki/Free_and_open-source_software
|
||||
[15]: https://medium.com/dawn-capital/why-leverage-the-power-of-open-source-to-build-a-successful-software-business-8aba6f665bc4#.ggmn2ojxp
|
||||
[16]: https://github.com/majutsushi/tagbar
|
||||
[17]: http://ctags.sourceforge.net/
|
||||
[18]: https://github.com/majutsushi/tagbar/zipball/70fix
|
||||
[19]: https://raw.githubusercontent.com/tpope/vim-pathogen/master/autoload/pathogen.vim
|
||||
[20]: http://www.vim.org/scripts/script.php?script_id=2332
|
||||
[21]: https://www.howtoforge.com/tutorial/vim-editor-plugins-for-software-developers-2-syntastic/
|
||||
[22]: https://www.howtoforge.com/images/vim-editor-plugins-for-software-developers/big/vimplugins-delimitmate-help.png
|
||||
[23]: https://github.com/Raimondi/delimitMate
|
||||
[24]: https://www.howtoforge.com/images/vim-editor-plugins-for-software-developers/big/vimplugins-tagbar-visibility.png
|
||||
[25]: https://www.howtoforge.com/images/vim-editor-plugins-for-software-developers/big/vimplugins-tagbar-ex2.png
|
||||
[26]: https://www.howtoforge.com/images/vim-editor-plugins-for-software-developers/big/vimplugins-tagbar-example.png
|
||||
[27]: http://www.tldp.org/LDP/intro-linux/html/sect_06_02.html
|
||||
[28]: http://majutsushi.github.io/tagbar/
|
||||
[29]: http://vi.stackexchange.com/questions/388/what-is-the-difference-between-the-vim-plugin-managers
|
||||
[30]: https://www.howtoforge.com/images/vim-editor-plugins-for-software-developers/big/vimplugins-vimrc.png
|
||||
[31]: http://www.vim.org/
|
||||
[32]: https://github.com/scrooloose/syntastic
|
||||
[33]: https://github.com/scrooloose/syntastic/blob/master/doc/syntastic.txt
|
||||
[34]: https://www.howtoforge.com/images/3337/big/syntastic-error-all-descr.png
|
||||
[35]: https://www.howtoforge.com/images/3337/big/syntastic-error-descr.png
|
||||
[36]: https://www.howtoforge.com/images/3337/big/syntastic-error-highlight.png
|
||||
[37]: https://github.com/scrooloose/syntastic
|
||||
[38]: http://www.vim.org/
|
||||
[39]: https://www.howtoforge.com/tutorial/vim-editor-plugins-for-software-developers/
|
||||
[40]: https://en.wikipedia.org/wiki/Trim_%28computing%29
|
||||
[41]: https://en.wikipedia.org/wiki/Sudo
|
||||
[42]: http://snapcraft.io/
|
||||
[43]: http://flatpak.org/
|
||||
[44]: https://en.wikipedia.org/wiki/Wine_%28software%29
|
||||
[45]: https://en.wikipedia.org/wiki/Live_CD
|
||||
[46]: http://distrowatch.com/
|
@ -1,8 +1,9 @@
|
||||
开发者的实用 Vim 插件——第一部分
|
||||
开发者的实用 Vim 插件(一)
|
||||
============
|
||||
|
||||
作为 Vi 的升级版,[Vim][31] 毫无争议是 Linux 中最受欢迎的命令行编辑器之一。除了是一个多功能编辑器外,世界各地的软件开发者将 Vim 当做 IDE(Integrated Development Environment,集成开发环境)来使用。
|
||||
|
||||
事实上,是 Vim 可以通过插件来扩展其自身功能才使得它如此功能强大。不用说,肯定有那么几个 Vim 插件是指在提高用户的编程体验的。
|
||||
事实上,因为 Vim 可以通过插件来扩展其自身功能才使得它如此功能强大。不用说,肯定有那么几个 Vim 插件是旨在提高用户的编程体验的。
|
||||
|
||||
特别是对于刚刚使用 Vim 或者使用 Vim 做开发的的软件开发者来说,我们将在本教程中讨论一些非常有用的 Vim 插件,具体请看例示。
|
||||
|
||||
@ -12,25 +13,25 @@
|
||||
|
||||
这是为新用户准备的,假设他们不知道如何安装 Vim 插件。所以,首先,就是给出一些完成安装设置的步骤。
|
||||
|
||||
* 在家目录下创建 .vim 目录,并在其中创建子目录 autoload 和 bundle。
|
||||
* 然后,在 autoload 放置 [pathogen.vim][20] 文件,这个文件可以从 [此处][19] 下载。
|
||||
* 最后,在家目录创建 .vimrc 文件,并添加一下内容。
|
||||
* 在你的家目录下创建 `.vim` 目录,并在其中创建子目录 `autoload` 和 `bundle`。
|
||||
* 然后,在 `autoload` 放置 [pathogen.vim][20] 文件,这个文件可以从[此处][19] 下载。
|
||||
* 最后,在你的家目录创建 `.vimrc` 文件,并添加以下内容。
|
||||
|
||||
```
|
||||
call pathogen#infect()
|
||||
```
|
||||
|
||||
[][30]
|
||||

|
||||
|
||||
至此,你已完成了 Vim 插件安装的准备工作。
|
||||
|
||||
注意:我们已经讨论了使用 Pathogen 管理 Vim 插件。当然还有其他的插件管理工具——欲了解,请访问 [此处][29]。
|
||||
注意:我们已经讨论了使用 Pathogen 管理 Vim 插件。当然还有其他的插件管理工具——欲了解,请访问[此处][29]。
|
||||
|
||||
现在已经全部设置完毕,就让我们来讨论两个好用的 Vim 插件吧。
|
||||
|
||||
### Vim 标签侧边栏(Tagbar)插件
|
||||
|
||||
首先就是标签侧边栏(Tagbar)插件。该插件能够让你浏览源文件包含的标签,从而提供该源文件的就够简览。[官网的插件说明][28] 是这样说的:“它通过创建侧边栏,然后以一定顺序展示从当前文件提取的标签(tags)来完成这一功能。这意味着,比如,C++ 中的方法将展示在其自身所定义在的类里边。”
|
||||
首先就是标签侧边栏(Tagbar)插件。该插件能够让你浏览源文件包含的标签,从而提供该源文件的结构简览。[其官网的插件说明][28]是这样说的:“它通过创建侧边栏,然后以一定顺序展示从当前文件以 ctags 提取的标签来完成这一功能。这意味着,比如,C++ 中的方法将展示在其自身所定义在的类里边。”
|
||||
|
||||
听起来很酷,不是吗?让我们来看看该怎么安装它。
|
||||
|
||||
@ -41,41 +42,41 @@ cd ~/.vim/bundle/
|
||||
|
||||
git clone git://github.com/majutsushi/tagbar
|
||||
```
|
||||
|
||||
安装完之后就可以使用了,你可以在 Vim 中打开一个 .cpp 文件来测试它:进入[命令模式][27],然后运行 :TagbarOpen 命令。以下是运行 :TagbarOpen 命令之后出现侧边栏(右侧) 的效果图。
|
||||
安装完之后就可以使用了,你可以在 Vim 中打开一个 .cpp 文件来测试它:进入[命令模式][27],然后运行 `:TagbarOpen` 命令。以下是运行 `:TagbarOpen` 命令之后出现侧边栏(右侧) 的效果图。
|
||||
|
||||
[][26]
|
||||
|
||||
使用 :TagbarClose 可以关闭侧边栏。值得一提的是,可以使用 :TagbarOpen fj 命令打开侧边栏,和是使用 shift 键控制侧边栏的效果一样。也就是说,你可以很方便的浏览当前文件包含的标签(tags)——在对应的标签(tags)上按下 Enter 键(使用 shift 键控制)跳转到左边源码的对应位置。
|
||||
使用 `:TagbarClose` 可以关闭侧边栏。值得一提的是,可以使用 `:TagbarOpen fj` 命令打开侧边栏来打开它的跳转(shift control)功能。也就是说,你可以很方便的浏览当前文件包含的标签——在对应的标签上按下 Enter 键,然后在左侧的源代码窗口跳转到对应的位置。
|
||||
|
||||
[][25]
|
||||

|
||||
|
||||
假如你想要反复地开关侧边栏,你可以使用 :TagbarToggle 命令,而不用交替的使用 :TagbarOpen 和 :TagbarClose 命令。
|
||||
假如你想要反复地开关侧边栏,你可以使用 `:TagbarToggle` 命令,而不用交替的使用 `:TagbarOpen` 和 `:TagbarClose` 命令。
|
||||
|
||||
如果你觉得输入这些命令很费时间,你可以为 :TagbarToggle 命令创建快捷键。比如,添加一下内容到 .vimrc 文件中:
|
||||
如果你觉得输入这些命令很费时间,你可以为 `:TagbarToggle` 命令创建快捷键。比如,添加以下内容到 `.vimrc` 文件中:
|
||||
|
||||
```
|
||||
nmap <F8> :TagbarToggle<CR>
|
||||
```
|
||||
这样,你就可以用 F8 来切换标签侧边栏(Tagbar)了。
|
||||
|
||||
再往下说,有时候你可能会注意到某个标签(tags)前边有一个 +、- 或者 # 符号。比如,一下截图(取自该插件的官网)展示了一些前边有 + 号的标签(tags)。
|
||||
更进一步,有时候你可能会注意到某个标签前边有一个 `+`、`-` 或者 `#` 符号。比如,以下截图(取自该插件的官网)展示了一些前边有 `+` 号的标签。
|
||||
|
||||
[][24]
|
||||

|
||||
|
||||
这些符号基本是用来表名一个特殊标签的可视化信息。特别是 + 表示该类是 public 的,而 - 表示一个 private 类。# 则是是表示一个 protected 类。
|
||||
这些符号基本是用来表明一个特定标签的可见性信息。特别是 `+` 表示该类是 public 的,而 `-` 表示一个 private 类。`#` 则是表示一个 protected 类。
|
||||
|
||||
以下是使用标签侧边栏(Tagbar)的一些注意事项:
|
||||
|
||||
* 该插件的官网早就有说明:“标签侧边栏(Tagbar)并非是管理标签(tags)文件而设计,它只是在动态内存中创建所需的标签,而非创建任何文件。标签(tags)文件的管理有其他插件提供支持。”
|
||||
* 低于 7.0.167 版本的 Vim 和标签侧边栏(Tagbar)插件存在着一个兼容性问题。根据官网:“如果你受到此问题的影响,请使用体代替版:[下载 zip 压缩包][18]。这是 2.2 版本的标准,但由于依赖变更的数量,它可能不会再升级。”
|
||||
* 如果你再加载该插件是遇到这样的错误:未找到足够的样式!(Exuberant ctags not found!)。你可以从 [此处][17] 下载并安装 ctags 来修复错误。
|
||||
* 该插件的官网早就有说明:“标签侧边栏(Tagbar)并非是管理标签(tags)文件而设计,它只是在内存中动态创建所需的标签,而非创建任何文件。标签(tags)文件的管理有其他插件提供支持。”
|
||||
* 低于 7.0.167 版本的 Vim 和标签侧边栏(Tagbar)插件存在着一个兼容性问题。根据官网:“如果你受到此问题的影响,请使用代替版:[下载 zip 压缩包][18]。这对应到 2.2 版本,但由于大量的依赖变更,它可能不会再升级。”
|
||||
* 如果你在加载该插件时遇到这样的错误:未找到 ctags!(Tagbar: Exuberant ctags not found!)。你可以从 [此处][17]下载并安装 ctags 来修复错误。
|
||||
* 获取更多信息请访问 [这里][16]。
|
||||
|
||||
### Vim 符号自动补齐(delimitMate)插件
|
||||
### Vim 界定符自动补齐(delimitMate)插件
|
||||
|
||||
下一个要介绍的插件就是符号自动补齐(delimitMate)。该插件在 Vim 插入模式下提供引号、圆括号和方括号等符号自动补齐功能。
|
||||
下一个要介绍的插件就是界定符自动补齐(delimitMate)。该插件在 Vim 插入模式下提供引号、圆括号和方括号等界定符自动补齐功能。
|
||||
|
||||
[该插件官网][23]:“它同时也提供一些相关的特性让你在输入模式下变得更加辩解,比如语法纠错(在注释区或者其他的可配置区不会自动插入界限符)、扩展名识别(默认关闭)等。”
|
||||
[该插件官网][23]说:“它同时也提供一些相关的特性让你在输入模式下变得更加便捷,比如语法纠错(在注释区或者其他的可配置区不会自动插入结束界定符)、回车和空格填充(默认关闭)等。”
|
||||
|
||||
安装步骤与之前介绍的相似:
|
||||
|
||||
@ -89,11 +90,11 @@ git clone git://github.com/Raimondi/delimitMate.git
|
||||
|
||||
至此,在你使用 Vim 的任何时候,只要你输入一个双引号、单引号、单号、圆括号、方括号,它们都会自动补齐。
|
||||
|
||||
你可以自己配置 符号自动补齐(delimitMate)。比如,你可以添加需要自动补齐的符号列表,阻止自动加载插件,对指定类型文件关闭插件等。想来接如何配置这些(或者其他更多的配置),请阅读该插件的详细文档——运行 :help delimitMate 即可。
|
||||
你可以自己配置界定符自动补齐(delimitMate)。比如,你可以添加需要自动补齐的符号列表,阻止自动加载该插件,对指定类型文件关闭该插件等。想了解如何配置这些(或者其他更多的配置),请阅读该插件的详细文档——运行 `:help delimitMate` 即可。
|
||||
|
||||
上述命令会将你的 Vim 窗口水平分割成两个,上边一个包含我们所说的文档。
|
||||
|
||||
[][22]
|
||||

|
||||
|
||||
### 结论
|
||||
|
||||
@ -108,10 +109,8 @@ git clone git://github.com/Raimondi/delimitMate.git
|
||||
via: https://www.howtoforge.com/tutorial/vim-editor-plugins-for-software-developers/
|
||||
|
||||
作者:[Ansh][a]
|
||||
|
||||
译者:[GHLandy](https://github.com/GHLandy)
|
||||
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
@ -0,0 +1,121 @@
|
||||
开发者的实用 Vim 插件(二)
|
||||
============
|
||||
|
||||
毫无疑问,Vim 是一个开箱即用并能够胜任编程任务的编辑器,但实际上是该编辑器中的插件帮你实现这些方便的功能。在 [开发者的实用 Vim 插件(一)][39],我们已经讨论两个编程相关的 Vim 插件——标签侧边栏(Tagbar)和定界符自动补齐(delimitMate)。作为相同系列,我们在本文讨论另一个非常有用、专门为软件开发正定制的插件——语法高亮插件。
|
||||
|
||||
请注意:本教程中列举的所有例示、命令和说明都是在 Ubuntu 16.04 环境下进行测试的,并且,我们使用的 Vim 版本是 7.4。
|
||||
|
||||
### 语法高亮(Syntastic)插件
|
||||
|
||||
假如你的软件开发工作涉及到 C/C++ 语言,毫无疑问的说,遇到编译错误也是你每天工作中的一部分。很多时候,编译错误是由源代码之中的语法不正确造成的,因为开发者在浏览源码的时候很少能够一眼就看出所有这些错误。
|
||||
|
||||
那么 Vim 中是否存在一种插件可以让你不经编译源码就可以显示出语法错误呢?当然是有这样一种插件的,其名字就是 Syntastic。
|
||||
|
||||
“Syntastic 是 Vim 用来检验语法的插件,通过外部语法校验器校验文件并将错误呈现给用户。该过程可以在需要时进行,或者在文件保存的时候自动进行。”该插件 [官方文档][37] 如是说。“如果检测到语法错误就会提示用户,因为不用编译代码或者执行脚本就可以知道语法错误,用户也就乐享与此了。”
|
||||
|
||||
安装过程和第一部分提到的方法类似,你只需要运行下列命令即可:
|
||||
|
||||
```
|
||||
cd ~/.vim/bundle/
|
||||
|
||||
git clone https://github.com/scrooloose/syntastic.git
|
||||
```
|
||||
一旦你成功安装这个插件(即上述命令执行成功),你就不需要进行任何配置了——当 Vim 启动时会自动加载这个插件。
|
||||
|
||||
现在,打开一个源码文件并用 `:w` Vim 命令保存即可使用这个插件了。等待片刻之后,如果在源码中有语法错误的好,就会高亮显示出来。比如,看看一下截图你就会明白该插件是如何高亮显示语法错误的:
|
||||
|
||||

|
||||
|
||||
在每行之前的 `>>` 表示该行中有语法错误。了解确切的错误或者想知道是什么东西错了,将光标移到该行——错误描述就会展示在 Vim 窗口的最底下。
|
||||
|
||||
[][35]
|
||||
|
||||
这样,不用进行编译你就能够修复大多数语法相关的错误。
|
||||
|
||||
再往下,如果你运行 `:Errors` 命令,就会展现当前源文件中所有语法相关错误的描述。比如,我运行 `:Errors` 命令就是下图的效果:
|
||||
|
||||
[][34]
|
||||
|
||||
请记住,`:Errors` 展现的语法错误是不会自动更新的,这意味着在你修复错误之后,你需要重新运行 `:Errors` 命令,编辑器底部的错误描述才会消除。
|
||||
|
||||
值得一提的是,还有 [许多配置选项][33] 能够使得 Syntastic 插件使用起来更加友好。比如,你可以在你的 `.vimrc` 中添加下列内容,然后 `:Errors` 就可以在修复错误之后自动更新它的底部描述。
|
||||
|
||||
```
|
||||
let g:syntastic_always_populate_loc_list = 1
|
||||
```
|
||||
添加以下内容,以确保在你打开文件时 Syntastic 插件自动高亮显示错误。
|
||||
|
||||
```
|
||||
let g:syntastic_check_on_open = 1
|
||||
```
|
||||
类似的,你也可以在保存或打开文件时让光标跳转到检测到的第一个问题处,将下列行放到你的 `.vimrc` 文件之中:
|
||||
```
|
||||
let g:syntastic_auto_jump = 1
|
||||
```
|
||||
这个值也可以指定为其它两个值: 2 和 3,其官方文档的解释如下:
|
||||
|
||||
“如果设置为 2 的话,光标就会跳到检测到的第一个问题,当然,只有这个问题是一个错误的时候才跳转;设置为 3 的话,如果存在错误,则会跳到第一个错误。所有检测到的问题都会有警告,但光标不会跳转。”
|
||||
|
||||
以下信息可能对你有帮助:
|
||||
|
||||
“使用 `:SyntasticCheck` 来手动检测错误。使用 `:Errors` 打开错误位置列表并使用 `:lclose` 来关闭。使用 `:SyntasticReset` 可以清除掉错误列表,使用 `:SyntasticToggleMode` 来切换激活(在写到 buffer 时检测)和被动(即手动检测)检测错误。”
|
||||
|
||||
注意:Syntastic 并不局限于 C/C++ 所写的代码,它同时也支持很多的编程语言——点击 [此处][32] 了解更多相关信息。
|
||||
|
||||
### 结论
|
||||
|
||||
毫无疑问的,Syntastic 是一个非常有用的 Vim 插件,因为在出现语法相关错误时候,它至少能够让免去频繁编译的麻烦,而且不用说,同时也节约了你不少的时间。
|
||||
|
||||
正如你所看到的一样,配置好几个主要选项之后,Syntastic 变得非常好用了。为了帮助你了解这些设置,官方文档中包含了一份“推荐设置”——跟着文档进行设置即可。加入你遇到一些错误、有些疑问或者问题,你也可以查询一下 FAQ。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.howtoforge.com/tutorial/vim-editor-plugins-for-software-developers-2-syntastic/
|
||||
|
||||
作者:[Ansh][a]
|
||||
译者:[GHLandy](https://github.com/GHLandy)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://www.howtoforge.com/tutorial/vim-editor-plugins-for-software-developers-2-syntastic/
|
||||
[1]:https://www.youtube.com/channel/UCOfXyFkINXf_e9XNosTJZDw
|
||||
[2]:https://www.youtube.com/user/desainew
|
||||
[3]:https://www.youtube.com/channel/UCEQXp_fcqwPcqrzNtWJ1w9w
|
||||
[4]:http://www.facebook.com/sharer/sharer.php?u=https%3A%2F%2Ffreedompenguin.com%2Farticles%2Fopinion%2Fopen-source-design-thing%2F
|
||||
[5]:http://twitter.com/intent/tweet/?text=Is+Open+Source+Design+a+Thing%3F&url=https%3A%2F%2Ffreedompenguin.com%2Farticles%2Fopinion%2Fopen-source-design-thing%2F
|
||||
[6]:https://plus.google.com/share?url=https%3A%2F%2Ffreedompenguin.com%2Farticles%2Fopinion%2Fopen-source-design-thing%2F
|
||||
[7]:https://atom.io/
|
||||
[8]:http://froont.com/
|
||||
[9]:https://webflow.com/
|
||||
[10]:https://gravit.io/
|
||||
[11]:http://getbootstrap.com/
|
||||
[12]:https://inkscape.org/en/
|
||||
[13]:https://www.gimp.org/
|
||||
[14]:https://en.wikipedia.org/wiki/Free_and_open-source_software
|
||||
[15]:https://medium.com/dawn-capital/why-leverage-the-power-of-open-source-to-build-a-successful-software-business-8aba6f665bc4#.ggmn2ojxp
|
||||
[16]:https://github.com/majutsushi/tagbar
|
||||
[17]:http://ctags.sourceforge.net/
|
||||
[18]:https://github.com/majutsushi/tagbar/zipball/70fix
|
||||
[19]:https://raw.githubusercontent.com/tpope/vim-pathogen/master/autoload/pathogen.vim
|
||||
[20]:http://www.vim.org/scripts/script.php?script_id=2332
|
||||
[21]:https://www.howtoforge.com/tutorial/vim-editor-plugins-for-software-developers-2-syntastic/
|
||||
[22]:https://www.howtoforge.com/images/vim-editor-plugins-for-software-developers/big/vimplugins-delimitmate-help.png
|
||||
[23]:https://github.com/Raimondi/delimitMate
|
||||
[24]:https://www.howtoforge.com/images/vim-editor-plugins-for-software-developers/big/vimplugins-tagbar-visibility.png
|
||||
[25]:https://www.howtoforge.com/images/vim-editor-plugins-for-software-developers/big/vimplugins-tagbar-ex2.png
|
||||
[26]:https://www.howtoforge.com/images/vim-editor-plugins-for-software-developers/big/vimplugins-tagbar-example.png
|
||||
[27]:http://www.tldp.org/LDP/intro-linux/html/sect_06_02.html
|
||||
[28]:http://majutsushi.github.io/tagbar/
|
||||
[29]:http://vi.stackexchange.com/questions/388/what-is-the-difference-between-the-vim-plugin-managers
|
||||
[30]:https://www.howtoforge.com/images/vim-editor-plugins-for-software-developers/big/vimplugins-vimrc.png
|
||||
[31]:http://www.vim.org/
|
||||
[32]:https://github.com/scrooloose/syntastic
|
||||
[33]:https://github.com/scrooloose/syntastic/blob/master/doc/syntastic.txt
|
||||
[34]:https://www.howtoforge.com/images/3337/big/syntastic-error-all-descr.png
|
||||
[35]:https://www.howtoforge.com/images/3337/big/syntastic-error-descr.png
|
||||
[36]:https://www.howtoforge.com/images/3337/big/syntastic-error-highlight.png
|
||||
[37]:https://github.com/scrooloose/syntastic
|
||||
[38]:http://www.vim.org/
|
||||
[39]:https://www.howtoforge.com/tutorial/vim-editor-plugins-for-software-developers/
|
||||
|
@ -0,0 +1,27 @@
|
||||
白宫开源聊天机器人代码
|
||||
===================
|
||||
|
||||
争先部署那种可以响应用户请求的机器人的潮流也步入到了奥巴马总统的家——美国白宫。白宫在 10 月 14 号宣布开源其机器人代码,目的是为了使增加更加开放的合作与交流。
|
||||
|
||||

|
||||
|
||||
“具体地说,我们开源了一个 Drupal 模块,只需要一些简单的步骤和样板化代码就可以搞定,” 白宫首席数码执行官 Jason Goldman 在他的博客的[文章][1]中这样写到,“这可以让 Drupal 8 开发者迅速推出 Facebook Messenger 机器人。”
|
||||
|
||||
白宫早在 2009 年就率先用开源的 Drupal 内容管理系统(CMS)[部署][2]了它自己的网站。从那时起白宫就已经成为了 Drupal 的积极贡献者,并以许多不同的方式做着贡献,包括将用在其网站上的代码以开源方式发布。在白宫过去发布的那些项目中有完整的 Drupal 主题,被称作“fourtyfour”,目前用于 WhiteHouse.gov 网站。
|
||||
|
||||
现在,白宫新发布 Facebook Messenger 机器人的完整代码可以从 [GitHub][3] 上获取,包括完整的安装指导和项目蓝图。在蓝图中最大的项目(列在 ‘Enhancements and hopes’ 一节下面)是切实使项目更加独立,通过重构代码使项目模块化,从而让它在 Drupal 内容管理系统(CMS)之外也可以使用。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: http://www.internetnews.com/blog/skerner/white-house-open-sources-bot-code.html
|
||||
|
||||
作者:[Michael Kerner][a]
|
||||
译者:[ucasFL](https://github.com/ucasFL)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: http://www.internetnews.com/blog/skerner/white-house-open-sources-bot-code.html
|
||||
[1]:https://www.whitehouse.gov/blog/2016/10/13/removing-barriers-constituent-conversations
|
||||
[2]:http://www.internetnews.com/skerner/2009/10/white-house-goes-open-source-w.html
|
||||
[3]: https://github.com/WhiteHouse/fb_messenger_bot
|
@ -0,0 +1,849 @@
|
||||
构建你的数据科学作品集:机器学习项目
|
||||
===========================================================
|
||||
|
||||
> 这是[这个系列][3]发布的第三篇关于如何构建数据科学作品集(Data Science Portfolio)的文章。如果你喜欢这个系列并且想继续关注,你可以在订阅页面的底部找到[链接][1]。
|
||||
|
||||
数据科学公司在决定雇佣时越来越关注你在数据科学方面的作品集(Portfolio)。这其中的一个原因是,这样的作品集是判断某人的实际技能的最好的方法。好消息是构建这样的作品集完全要看你自己。只要你在这方面付出了努力,你一定可以取得让这些公司钦佩的作品集。
|
||||
|
||||
构建高质量的作品集的第一步就是知道需要什么技能。公司想要在数据科学方面拥有的、他们希望你能够运用的主要技能有:
|
||||
|
||||
- 沟通能力
|
||||
- 协作能力
|
||||
- 技术能力
|
||||
- 数据推理能力
|
||||
- 动机和主动性
|
||||
|
||||
任何好的作品集都由多个项目表现出来,其中每个都能够表现出以上一到两点。这是本系列的第三篇,本系列我们主要讲包括如何打造面面俱到的数据科学作品集。在这一篇中,我们主要涵盖了如何构建组成你的作品集的第二个项目,以及如何创建一个端对端的机器学习项目。在最后,我们将拥有一个展示你的数据推理能力和技术能力的项目。如果你想看一下的话,[这里][2]有一个完整的例子。
|
||||
|
||||
### 一个端到端的项目
|
||||
|
||||
作为一个数据科学家,有时候你会拿到一个数据集并被问如何[用它来讲故事][3]。在这个时候,沟通就是非常重要的,你需要用它来完成这个事情。像我们在前一篇文章中用过的,类似 Jupyter notebook 这样的工具,将对你非常有帮助。在这里你能找到一些可以用的报告或者总结文档。
|
||||
|
||||
不管怎样,有时候你会被要求创建一个具有操作价值的项目。具有操作价值的项目将直接影响到公司的日常业务,它会使用不止一次,经常是许多人使用。这个任务可能像这样 “创建一个算法来预测周转率”或者“创建一个模型来自动对我们的文章打标签”。在这种情况下,技术能力比讲故事更重要。你必须能够得到一个数据集,并且理解它,然后创建脚本处理该数据。这个脚本要运行的很快,占用系统资源很小。通常它可能要运行很多次,脚本的可使用性也很重要,并不仅仅是一个演示版。可使用性是指整合进操作流程,并且甚至是是面向用户的。
|
||||
|
||||
端对端项目的主要组成部分:
|
||||
|
||||
- 理解背景
|
||||
- 浏览数据并找出细微差别
|
||||
- 创建结构化项目,那样比较容易整合进操作流程
|
||||
- 运行速度快、占用系统资源小的高性能代码
|
||||
- 写好安装和使用文档以便其他人用
|
||||
|
||||
为了有效的创建这种类型的项目,我们可能需要处理多个文件。强烈推荐使用 [Atom][4] 这样的文本编辑器或者 [PyCharm][5] 这样的 IDE。这些工具允许你在文件间跳转,编辑不同类型的文件,例如 markdown 文件,Python 文件,和 csv 文件等等。结构化你的项目还利于版本控制,并上传一个类似 [Github][6] 这样的协作开发工具上也很有用。
|
||||
|
||||

|
||||
|
||||
*Github 上的这个项目*
|
||||
|
||||
在这一节中我们将使用 [Pandas][7] 和 [scikit-learn][8] 这样的库,我们还将大量用到 Pandas [DataFrames][9],它使得 python 读取和处理表格数据更加方便。
|
||||
|
||||
### 找到好的数据集
|
||||
|
||||
为一个端到端的作品集项目的找到好的数据集很难。在内存和性能的限制下,数据集需要尽量的大。它还需要是实际有用的。例如,[这个数据集][10],它包含有美国院校的录取标准、毕业率以及毕业以后的收入,是个很好的可以讲故事的数据集。但是,不管你如何看待这个数据,很显然它不适合创建端到端的项目。比如,你能告诉人们他们去了这些大学以后的未来收入,但是这个快速检索却并不足够呈现出你的技术能力。你还能找出院校的招生标准和更高的收入相关,但是这更像是常理而不是你的技术结论。
|
||||
|
||||
这里还有内存和性能约束的问题,比如你有几千兆的数据,而且当你需要找到一些差异时,就需要对数据集一遍遍运行算法。
|
||||
|
||||
一个好的可操作的数据集可以让你构建一系列脚本来转换数据、动态地回答问题。一个很好的例子是股票价格数据集,当股市关闭时,就会给算法提供新的数据。这可以让你预测明天的股价,甚至预测收益。这不是讲故事,它带来的是真金白银。
|
||||
|
||||
一些找到数据集的好地方:
|
||||
|
||||
- [/r/datasets][11] – 有上百的有趣数据的 subreddit(Reddit 是国外一个社交新闻站点,subreddit 指该论坛下的各不同版块)。
|
||||
- [Google Public Datasets][12] – 通过 Google BigQuery 使用的公开数据集。
|
||||
- [Awesome datasets][13] – 一个数据集列表,放在 Github 上。
|
||||
|
||||
当你查看这些数据集时,想一下人们想要在这些数据集中得到什么答案,哪怕这些问题只想过一次(“房价是如何与标准普尔 500 指数关联的?”),或者更进一步(“你能预测股市吗?”)。这里的关键是更进一步地找出问题,并且用相同的代码在不同输入(不同的数据)上运行多次。
|
||||
|
||||
对于本文的目标,我们来看一下 [房利美(Fannie Mae)贷款数据][14]。房利美是一家在美国的政府赞助的企业抵押贷款公司,它从其他银行购买按揭贷款,然后捆绑这些贷款为贷款证券来转卖它们。这使得贷款机构可以提供更多的抵押贷款,在市场上创造更多的流动性。这在理论上会带来更多的住房和更好的贷款期限。从借款人的角度来说,它们大体上差不多,话虽这样说。
|
||||
|
||||
房利美发布了两种类型的数据 – 它获得的贷款的数据,和贷款偿还情况的数据。在理想的情况下,有人向贷款人借钱,然后还款直到还清。不管怎样,有些人多次不还,从而丧失了抵押品赎回权。抵押品赎回权是指没钱还了被银行把房子给收走了。房利美会追踪谁没还钱,并且哪个贷款需要收回抵押的房屋(取消赎回权)。每个季度会发布此数据,发布的是滞后一年的数据。当前可用是 2015 年第一季度数据。
|
||||
|
||||
“贷款数据”是由房利美发布的贷款发放的数据,它包含借款人的信息、信用评分,和他们的家庭贷款信息。“执行数据”,贷款发放后的每一个季度公布,包含借贷人的还款信息和是否丧失抵押品赎回权的状态,一个“贷款数据”的“执行数据”可能有十几行。可以这样理解,“贷款数据”告诉你房利美所控制的贷款,“执行数据”包含该贷款一系列的状态更新。其中一个状态更新可以告诉我们一笔贷款在某个季度被取消赎回权了。
|
||||
|
||||

|
||||
|
||||
*一个没有及时还贷的房子就这样的被卖了*
|
||||
|
||||
### 选择一个角度
|
||||
|
||||
这里有几个我们可以去分析房利美数据集的方向。我们可以:
|
||||
|
||||
- 预测房屋的销售价格。
|
||||
- 预测借款人还款历史。
|
||||
- 在获得贷款时为每一笔贷款打分。
|
||||
|
||||
最重要的事情是坚持单一的角度。同时关注太多的事情很难做出效果。选择一个有着足够细节的角度也很重要。下面的角度就没有太多细节:
|
||||
|
||||
- 找出哪些银行将贷款出售给房利美的多数被取消赎回权。
|
||||
- 计算贷款人的信用评分趋势。
|
||||
- 找到哪些类型的家庭没有偿还贷款的能力。
|
||||
- 找到贷款金额和抵押品价格之间的关系。
|
||||
|
||||
上面的想法非常有趣,如果我们关注于讲故事,那是一个不错的角度,但是不是很适合一个操作性项目。
|
||||
|
||||
在房利美数据集中,我们将仅使用申请贷款时有的那些信息来预测贷款是否将来会被取消赎回权。实际上, 我们将为每一笔贷款建立“分数”来告诉房利美买还是不买。这将给我们打下良好的基础,并将组成这个漂亮的作品集的一部分。
|
||||
|
||||
### 理解数据
|
||||
|
||||
我们来简单看一下原始数据文件。下面是 2012 年 1 季度前几行的贷款数据:
|
||||
|
||||
```
|
||||
100000853384|R|OTHER|4.625|280000|360|02/2012|04/2012|31|31|1|23|801|N|C|SF|1|I|CA|945||FRM|
|
||||
100003735682|R|SUNTRUST MORTGAGE INC.|3.99|466000|360|01/2012|03/2012|80|80|2|30|794|N|P|SF|1|P|MD|208||FRM|788
|
||||
100006367485|C|PHH MORTGAGE CORPORATION|4|229000|360|02/2012|04/2012|67|67|2|36|802|N|R|SF|1|P|CA|959||FRM|794
|
||||
```
|
||||
|
||||
下面是 2012 年 1 季度的前几行执行数据:
|
||||
|
||||
```
|
||||
100000853384|03/01/2012|OTHER|4.625||0|360|359|03/2042|41860|0|N||||||||||||||||
|
||||
100000853384|04/01/2012||4.625||1|359|358|03/2042|41860|0|N||||||||||||||||
|
||||
100000853384|05/01/2012||4.625||2|358|357|03/2042|41860|0|N||||||||||||||||
|
||||
```
|
||||
|
||||
在开始编码之前,花些时间真正理解数据是值得的。这对于操作性项目优为重要,因为我们没有交互式探索数据,将很难察觉到细微的差别,除非我们在前期发现他们。在这种情况下,第一个步骤是阅读房利美站点的资料:
|
||||
|
||||
- [概述][15]
|
||||
- [有用的术语表][16]
|
||||
- [常见问答][17]
|
||||
- [贷款和执行文件中的列][18]
|
||||
- [贷款数据文件样本][19]
|
||||
- [执行数据文件样本][20]
|
||||
|
||||
在看完这些文件后后,我们了解到一些能帮助我们的关键点:
|
||||
|
||||
- 从 2000 年到现在,每季度都有一个贷款和执行文件,因数据是滞后一年的,所以到目前为止最新数据是 2015 年的。
|
||||
- 这些文件是文本格式的,采用管道符号`|`进行分割。
|
||||
- 这些文件是没有表头的,但我们有个文件列明了各列的名称。
|
||||
- 所有一起,文件包含 2200 万个贷款的数据。
|
||||
- 由于执行数据的文件包含过去几年获得的贷款的信息,在早些年获得的贷款将有更多的执行数据(即在 2014 获得的贷款没有多少历史执行数据)。
|
||||
|
||||
这些小小的信息将会为我们节省很多时间,因为这样我们就知道如何构造我们的项目和利用这些数据了。
|
||||
|
||||
### 构造项目
|
||||
|
||||
在我们开始下载和探索数据之前,先想一想将如何构造项目是很重要的。当建立端到端项目时,我们的主要目标是:
|
||||
|
||||
- 创建一个可行解决方案
|
||||
- 有一个快速运行且占用最小资源的解决方案
|
||||
- 容易可扩展
|
||||
- 写容易理解的代码
|
||||
- 写尽量少的代码
|
||||
|
||||
为了实现这些目标,需要对我们的项目进行良好的构造。一个结构良好的项目遵循几个原则:
|
||||
|
||||
- 分离数据文件和代码文件
|
||||
- 从原始数据中分离生成的数据。
|
||||
- 有一个 `README.md` 文件帮助人们安装和使用该项目。
|
||||
- 有一个 `requirements.txt` 文件列明项目运行所需的所有包。
|
||||
- 有一个单独的 `settings.py` 文件列明其它文件中使用的所有的设置
|
||||
- 例如,如果从多个 `Python` 脚本读取同一个文件,让它们全部 `import` 设置并从一个集中的地方获得文件名是有用的。
|
||||
- 有一个 `.gitignore` 文件,防止大的或密码文件被提交。
|
||||
- 分解任务中每一步可以单独执行的步骤到单独的文件中。
|
||||
- 例如,我们将有一个文件用于读取数据,一个用于创建特征,一个用于做出预测。
|
||||
- 保存中间结果,例如,一个脚本可以输出下一个脚本可读取的文件。
|
||||
- 这使我们无需重新计算就可以在数据处理流程中进行更改。
|
||||
|
||||
|
||||
我们的文件结构大体如下:
|
||||
|
||||
```
|
||||
loan-prediction
|
||||
├── data
|
||||
├── processed
|
||||
├── .gitignore
|
||||
├── README.md
|
||||
├── requirements.txt
|
||||
├── settings.py
|
||||
```
|
||||
|
||||
### 创建初始文件
|
||||
|
||||
首先,我们需要创建一个 `loan-prediction` 文件夹,在此文件夹下面,再创建一个 `data` 文件夹和一个 `processed` 文件夹。`data` 文件夹存放原始数据,`processed` 文件夹存放所有的中间计算结果。
|
||||
|
||||
其次,创建 `.gitignore` 文件,`.gitignore` 文件将保证某些文件被 git 忽略而不会被推送至 GitHub。关于这个文件的一个好的例子是由 OSX 在每一个文件夹都会创建的 `.DS_Store` 文件,`.gitignore` 文件一个很好的范本在[这里](https://github.com/github/gitignore/blob/master/Python.gitignore)。我们还想忽略数据文件,因为它们实在是太大了,同时房利美的条文禁止我们重新分发该数据文件,所以我们应该在我们的文件后面添加以下 2 行:
|
||||
|
||||
```
|
||||
data
|
||||
processed
|
||||
```
|
||||
|
||||
[这里](https://github.com/dataquestio/loan-prediction/blob/master/.gitignore)是该项目的一个关于 .gitignore 文件的例子。
|
||||
|
||||
再次,我们需要创建 `README.md` 文件,它将帮助人们理解该项目。后缀 .md 表示这个文件采用 markdown 格式。Markdown 使你能够写纯文本文件,同时还可以添加你想要的神奇的格式。[这里](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet)是关于 markdown 的导引。如果你上传一个叫 `README.md` 的文件至 Github,Github 会自动处理该 markdown,同时展示给浏览该项目的人。例子在[这里](https://github.com/dataquestio/loan-prediction)。
|
||||
|
||||
至此,我们仅需在 `README.md` 文件中添加简单的描述:
|
||||
|
||||
```
|
||||
Loan Prediction
|
||||
-----------------------
|
||||
|
||||
Predict whether or not loans acquired by Fannie Mae will go into foreclosure. Fannie Mae acquires loans from other lenders as a way of inducing them to lend more. Fannie Mae releases data on the loans it has acquired and their performance afterwards [here](http://www.fanniemae.com/portal/funding-the-market/data/loan-performance-data.html).
|
||||
```
|
||||
|
||||
现在,我们可以创建 `requirements.txt` 文件了。这会帮助其它人可以很方便地安装我们的项目。我们还不知道我们将会具体用到哪些库,但是以下几个库是需要的:
|
||||
|
||||
```
|
||||
pandas
|
||||
matplotlib
|
||||
scikit-learn
|
||||
numpy
|
||||
ipython
|
||||
scipy
|
||||
```
|
||||
|
||||
以上几个是在 python 数据分析任务中最常用到的库。可以认为我们将会用到大部分这些库。[这里][24]是该项目 `requirements.txt` 文件的一个例子。
|
||||
|
||||
创建 `requirements.txt` 文件之后,你应该安装这些包了。我们将会使用 python3。如果你没有安装 python,你应该考虑使用 [Anaconda][25],它是一个 python 安装程序,同时安装了上面列出的所有包。
|
||||
|
||||
最后,我们可以建立一个空白的 `settings.py` 文件,因为我们的项目还没有任何设置。
|
||||
|
||||
### 获取数据
|
||||
|
||||
一旦我们有了项目的基本架构,我们就可以去获得原始数据。
|
||||
|
||||
房利美对获取数据有一些限制,所以你需要去注册一个账户。在创建完账户之后,你可以找到[在这里][26]的下载页面,你可以按照你所需要的下载或多或少的贷款数据文件。文件格式是 zip,在解压后当然是非常大的。
|
||||
|
||||
为了达到我们这个文章的目的,我们将要下载从 2012 年 1 季度到 2015 年 1 季度的所有数据。接着我们需要解压所有的文件。解压过后,删掉原来的 .zip 格式的文件。最后,loan-prediction 文件夹看起来应该像下面的一样:
|
||||
|
||||
```
|
||||
loan-prediction
|
||||
├── data
|
||||
│ ├── Acquisition_2012Q1.txt
|
||||
│ ├── Acquisition_2012Q2.txt
|
||||
│ ├── Performance_2012Q1.txt
|
||||
│ ├── Performance_2012Q2.txt
|
||||
│ └── ...
|
||||
├── processed
|
||||
├── .gitignore
|
||||
├── README.md
|
||||
├── requirements.txt
|
||||
├── settings.py
|
||||
```
|
||||
|
||||
在下载完数据后,你可以在 shell 命令行中使用 `head` 和 `tail` 命令去查看文件中的行数据,你看到任何的不需要的数据列了吗?在做这件事的同时查阅[列名称的 pdf 文件][27]可能有帮助。
|
||||
|
||||
### 读入数据
|
||||
|
||||
有两个问题让我们的数据难以现在就使用:
|
||||
|
||||
- 贷款数据和执行数据被分割在多个文件中
|
||||
- 每个文件都缺少列名标题
|
||||
|
||||
在我们开始使用数据之前,我们需要首先明白我们要在哪里去存一个贷款数据的文件,同时到哪里去存储一个执行数据的文件。每个文件仅仅需要包括我们关注的那些数据列,同时拥有正确的列名标题。这里有一个小问题是执行数据非常大,因此我们需要尝试去修剪一些数据列。
|
||||
|
||||
第一步是向 `settings.py` 文件中增加一些变量,这个文件中同时也包括了我们原始数据的存放路径和处理出的数据存放路径。我们同时也将添加其他一些可能在接下来会用到的设置数据:
|
||||
|
||||
```
|
||||
DATA_DIR = "data"
|
||||
PROCESSED_DIR = "processed"
|
||||
MINIMUM_TRACKING_QUARTERS = 4
|
||||
TARGET = "foreclosure_status"
|
||||
NON_PREDICTORS = [TARGET, "id"]
|
||||
CV_FOLDS = 3
|
||||
```
|
||||
|
||||
把路径设置在 `settings.py` 中使它们放在一个集中的地方,同时使其修改更加的容易。当在多个文件中用到相同的变量时,你想改变它的话,把他们放在一个地方比分散放在每一个文件时更加容易。[这里的][28]是一个这个工程的示例 `settings.py` 文件
|
||||
|
||||
第二步是创建一个文件名为 `assemble.py`,它将所有的数据分为 2 个文件。当我们运行 `Python assemble.py`,我们在处理数据文件的目录会获得 2 个数据文件。
|
||||
|
||||
接下来我们开始写 `assemble.py` 文件中的代码。首先我们需要为每个文件定义相应的列名标题,因此我们需要查看[列名称的 pdf 文件][29],同时创建在每一个贷款数据和执行数据的文件的数据列的列表:
|
||||
|
||||
```
|
||||
HEADERS = {
|
||||
"Acquisition": [
|
||||
"id",
|
||||
"channel",
|
||||
"seller",
|
||||
"interest_rate",
|
||||
"balance",
|
||||
"loan_term",
|
||||
"origination_date",
|
||||
"first_payment_date",
|
||||
"ltv",
|
||||
"cltv",
|
||||
"borrower_count",
|
||||
"dti",
|
||||
"borrower_credit_score",
|
||||
"first_time_homebuyer",
|
||||
"loan_purpose",
|
||||
"property_type",
|
||||
"unit_count",
|
||||
"occupancy_status",
|
||||
"property_state",
|
||||
"zip",
|
||||
"insurance_percentage",
|
||||
"product_type",
|
||||
"co_borrower_credit_score"
|
||||
],
|
||||
"Performance": [
|
||||
"id",
|
||||
"reporting_period",
|
||||
"servicer_name",
|
||||
"interest_rate",
|
||||
"balance",
|
||||
"loan_age",
|
||||
"months_to_maturity",
|
||||
"maturity_date",
|
||||
"msa",
|
||||
"delinquency_status",
|
||||
"modification_flag",
|
||||
"zero_balance_code",
|
||||
"zero_balance_date",
|
||||
"last_paid_installment_date",
|
||||
"foreclosure_date",
|
||||
"disposition_date",
|
||||
"foreclosure_costs",
|
||||
"property_repair_costs",
|
||||
"recovery_costs",
|
||||
"misc_costs",
|
||||
"tax_costs",
|
||||
"sale_proceeds",
|
||||
"credit_enhancement_proceeds",
|
||||
"repurchase_proceeds",
|
||||
"other_foreclosure_proceeds",
|
||||
"non_interest_bearing_balance",
|
||||
"principal_forgiveness_balance"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
接下来一步是定义我们想要保留的数据列。因为我们要预测一个贷款是否会被撤回,我们可以丢弃执行数据中的许多列。我们将需要保留贷款数据中的所有数据列,因为我们需要尽量多的了解贷款发放时的信息(毕竟我们是在预测贷款发放时这笔贷款将来是否会被撤回)。丢弃数据列将会使我们节省下内存和硬盘空间,同时也会加速我们的代码。
|
||||
|
||||
```
|
||||
SELECT = {
|
||||
"Acquisition": HEADERS["Acquisition"],
|
||||
"Performance": [
|
||||
"id",
|
||||
"foreclosure_date"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
下一步,我们将编写一个函数来连接数据集。下面的代码将:
|
||||
|
||||
- 引用一些需要的库,包括 `settings`。
|
||||
- 定义一个函数 `concatenate`,目的是:
|
||||
- 获取到所有 `data` 目录中的文件名。
|
||||
- 遍历每个文件。
|
||||
- 如果文件不是正确的格式 (不是以我们需要的格式作为开头),我们将忽略它。
|
||||
- 通过使用 Pandas 的 [read_csv][31]函数及正确的设置把文件读入一个[数据帧][30]。
|
||||
- 设置分隔符为`|`,以便所有的字段能被正确读出。
|
||||
- 数据没有标题行,因此设置 `header` 为 `None` 来进行标示。
|
||||
- 从 `HEADERS` 字典中设置正确的标题名称 – 这将会是我们的数据帧中的数据列名称。
|
||||
- 仅选择我们加在 `SELECT` 中的数据帧的列。
|
||||
- 把所有的数据帧共同连接在一起。
|
||||
- 把已经连接好的数据帧写回一个文件。
|
||||
|
||||
```
|
||||
import os
|
||||
import settings
|
||||
import pandas as pd
|
||||
|
||||
def concatenate(prefix="Acquisition"):
|
||||
files = os.listdir(settings.DATA_DIR)
|
||||
full = []
|
||||
for f in files:
|
||||
if not f.startswith(prefix):
|
||||
continue
|
||||
|
||||
data = pd.read_csv(os.path.join(settings.DATA_DIR, f), sep="|", header=None, names=HEADERS[prefix], index_col=False)
|
||||
data = data[SELECT[prefix]]
|
||||
full.append(data)
|
||||
|
||||
full = pd.concat(full, axis=0)
|
||||
|
||||
full.to_csv(os.path.join(settings.PROCESSED_DIR, "{}.txt".format(prefix)), sep="|", header=SELECT[prefix], index=False)
|
||||
```
|
||||
|
||||
我们可以通过调用上面的函数,通过传递的参数 `Acquisition` 和 `Performance` 两次以将所有的贷款和执行文件连接在一起。下面的代码将:
|
||||
|
||||
- 仅在命令行中运行 `python assemble.py` 时执行。
|
||||
- 将所有的数据连接在一起,并且产生 2 个文件:
|
||||
- `processed/Acquisition.txt`
|
||||
- `processed/Performance.txt`
|
||||
|
||||
```
|
||||
if __name__ == "__main__":
|
||||
concatenate("Acquisition")
|
||||
concatenate("Performance")
|
||||
```
|
||||
|
||||
我们现在拥有了一个漂亮的,划分过的 `assemble.py` 文件,它很容易执行,也容易建立。通过像这样把问题分解为一块一块的,我们构建工程就会变的容易许多。不用一个可以做所有工作的凌乱脚本,我们定义的数据将会在多个脚本间传递,同时使脚本间完全的彼此隔离。当你正在一个大的项目中工作时,这样做是一个好的想法,因为这样可以更加容易修改其中的某一部分而不会引起其他项目中不关联部分产生预料之外的结果。
|
||||
|
||||
一旦我们完成 `assemble.py` 脚本文件,我们可以运行 `python assemble.py` 命令。你可以[在这里][32]查看完整的 `assemble.py` 文件。
|
||||
|
||||
这将会在 `processed` 目录下产生 2 个文件:
|
||||
|
||||
```
|
||||
loan-prediction
|
||||
├── data
|
||||
│ ├── Acquisition_2012Q1.txt
|
||||
│ ├── Acquisition_2012Q2.txt
|
||||
│ ├── Performance_2012Q1.txt
|
||||
│ ├── Performance_2012Q2.txt
|
||||
│ └── ...
|
||||
├── processed
|
||||
│ ├── Acquisition.txt
|
||||
│ ├── Performance.txt
|
||||
├── .gitignore
|
||||
├── assemble.py
|
||||
├── README.md
|
||||
├── requirements.txt
|
||||
├── settings.py
|
||||
```
|
||||
|
||||
|
||||
### 计算来自执行数据的值
|
||||
|
||||
接下来我们会计算来自 `processed/Performance.txt` 中的值。我们要做的就是推测这些资产是否被取消赎回权。如果能够计算出来,我们只要看一下关联到贷款的执行数据的参数 `foreclosure_date` 就可以了。如果这个参数的值是 `None`,那么这些资产肯定没有收回。为了避免我们的样例中只有少量的执行数据,我们会为每个贷款计算出执行数据文件中的行数。这样我们就能够从我们的训练数据中筛选出贷款数据,排除了一些执行数据。
|
||||
|
||||
下面是我认为贷款数据和执行数据的关系:
|
||||
|
||||

|
||||
|
||||
在上面的表格中,贷款数据中的每一行数据都关联到执行数据中的多行数据。在执行数据中,在取消赎回权的时候 `foreclosure_date` 就会出现在该季度,而之前它是空的。一些贷款还没有被取消赎回权,所以与执行数据中的贷款数据有关的行在 `foreclosure_date` 列都是空格。
|
||||
|
||||
我们需要计算 `foreclosure_status` 的值,它的值是布尔类型,可以表示一个特殊的贷款数据 `id` 是否被取消赎回权过,还有一个参数 `performance_count` ,它记录了执行数据中每个贷款 `id` 出现的行数。
|
||||
|
||||
计算这些行数有多种不同的方法:
|
||||
|
||||
- 我们能够读取所有的执行数据,然后我们用 Pandas 的 [groupby](http://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.groupby.html) 方法在 DataFrame 中计算出与每个贷款 `id` 有关的行的行数,然后就可以查看贷款 `id` 的 `foreclosure_date` 值是否为 `None` 。
|
||||
- 这种方法的优点是从语法上来说容易执行。
|
||||
- 它的缺点需要读取所有的 129236094 行数据,这样就会占用大量内存,并且运行起来极慢。
|
||||
- 我们可以读取所有的执行数据,然后在贷款 DataFrame 上使用 [apply](http://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.apply.html) 去计算每个贷款 `id` 出现的次数。
|
||||
- 这种方法的优点是容易理解。
|
||||
- 缺点是需要读取所有的 129236094 行数据。这样会占用大量内存,并且运行起来极慢。
|
||||
- 我们可以在迭代访问执行数据中的每一行数据,而且会建立一个单独的计数字典。
|
||||
- 这种方法的优点是数据不需要被加载到内存中,所以运行起来会很快且不需要占用内存。
|
||||
- 缺点是这样的话理解和执行上可能有点耗费时间,我们需要对每一行数据进行语法分析。
|
||||
|
||||
加载所有的数据会非常耗费内存,所以我们采用第三种方法。我们要做的就是迭代执行数据中的每一行数据,然后为每一个贷款 `id` 在字典中保留一个计数。在这个字典中,我们会计算出贷款 `id` 在执行数据中出现的次数,而且看看 `foreclosure_date` 是否是 `None` 。我们可以查看 `foreclosure_status` 和 `performance_count` 的值 。
|
||||
|
||||
我们会新建一个 `annotate.py` 文件,文件中的代码可以计算这些值。我们会使用下面的代码:
|
||||
|
||||
- 导入需要的库
|
||||
- 定义一个函数 `count_performance_rows` 。
|
||||
- 打开 `processed/Performance.txt` 文件。这不是在内存中读取文件而是打开了一个文件标识符,这个标识符可以用来以行为单位读取文件。
|
||||
- 迭代文件的每一行数据。
|
||||
- 使用分隔符`|`分开每行的不同数据。
|
||||
- 检查 `loan_id` 是否在计数字典中。
|
||||
- 如果不存在,把它加进去。
|
||||
- `loan_id` 的 `performance_count` 参数自增 1 次,因为我们这次迭代也包含其中。
|
||||
- 如果 `date` 不是 `None ,我们就会知道贷款被取消赎回权了,然后为 `foreclosure_status` 设置合适的值。
|
||||
|
||||
```
|
||||
import os
|
||||
import settings
|
||||
import pandas as pd
|
||||
|
||||
def count_performance_rows():
|
||||
counts = {}
|
||||
with open(os.path.join(settings.PROCESSED_DIR, "Performance.txt"), 'r') as f:
|
||||
for i, line in enumerate(f):
|
||||
if i == 0:
|
||||
# Skip header row
|
||||
continue
|
||||
loan_id, date = line.split("|")
|
||||
loan_id = int(loan_id)
|
||||
if loan_id not in counts:
|
||||
counts[loan_id] = {
|
||||
"foreclosure_status": False,
|
||||
"performance_count": 0
|
||||
}
|
||||
counts[loan_id]["performance_count"] += 1
|
||||
if len(date.strip()) > 0:
|
||||
counts[loan_id]["foreclosure_status"] = True
|
||||
return counts
|
||||
```
|
||||
|
||||
### 获取值
|
||||
|
||||
只要我们创建了计数字典,我们就可以使用一个函数通过一个 `loan_id` 和一个 `key` 从字典中提取到需要的参数的值:
|
||||
|
||||
```
|
||||
def get_performance_summary_value(loan_id, key, counts):
|
||||
value = counts.get(loan_id, {
|
||||
"foreclosure_status": False,
|
||||
"performance_count": 0
|
||||
})
|
||||
return value[key]
|
||||
```
|
||||
|
||||
上面的函数会从 `counts` 字典中返回合适的值,我们也能够为贷款数据中的每一行赋一个 `foreclosure_status` 值和一个 `performance_count` 值。如果键不存在,字典的 [get][33] 方法会返回一个默认值,所以在字典中不存在键的时候我们就可以得到一个可知的默认值。
|
||||
|
||||
### 转换数据
|
||||
|
||||
我们已经在 `annotate.py` 中添加了一些功能,现在我们来看一看数据文件。我们需要将贷款到的数据转换到训练数据集来进行机器学习算法的训练。这涉及到以下几件事情:
|
||||
|
||||
- 转换所有列为数字。
|
||||
- 填充缺失值。
|
||||
- 为每一行分配 `performance_count` 和 `foreclosure_status`。
|
||||
- 移除出现执行数据很少的行(`performance_count` 计数低)。
|
||||
|
||||
我们有几个列是文本类型的,看起来对于机器学习算法来说并不是很有用。然而,它们实际上是分类变量,其中有很多不同的类别代码,例如 `R`,`S` 等等. 我们可以把这些类别标签转换为数值:
|
||||
|
||||

|
||||
|
||||
通过这种方法转换的列我们可以应用到机器学习算法中。
|
||||
|
||||
还有一些包含日期的列 (`first_payment_date` 和 `origination_date`)。我们可以将这些日期放到两个列中:
|
||||
|
||||

|
||||
|
||||
在下面的代码中,我们将转换贷款数据。我们将定义一个函数如下:
|
||||
|
||||
- 在 `acquisition` 中创建 `foreclosure_status` 列,并从 `counts` 字典中得到值。
|
||||
- 在 `acquisition` 中创建 `performance_count` 列,并从 `counts` 字典中得到值。
|
||||
- 将下面的列从字符串转换为整数:
|
||||
- `channel`
|
||||
- `seller`
|
||||
- `first_time_homebuyer`
|
||||
- `loan_purpose`
|
||||
- `property_type`
|
||||
- `occupancy_status`
|
||||
- `property_state`
|
||||
- `product_type`
|
||||
- 将 `first_payment_date` 和 `origination_date` 分别转换为两列:
|
||||
- 通过斜杠分离列。
|
||||
- 将第一部分分离成 `month` 列。
|
||||
- 将第二部分分离成 `year` 列。
|
||||
- 删除该列。
|
||||
- 最后,我们得到 `first_payment_month`、`first_payment_year`、`rigination_month` 和 `origination_year`。
|
||||
- 所有缺失值填充为 `-1`。
|
||||
|
||||
```
|
||||
def annotate(acquisition, counts):
|
||||
acquisition["foreclosure_status"] = acquisition["id"].apply(lambda x: get_performance_summary_value(x, "foreclosure_status", counts))
|
||||
acquisition["performance_count"] = acquisition["id"].apply(lambda x: get_performance_summary_value(x, "performance_count", counts))
|
||||
for column in [
|
||||
"channel",
|
||||
"seller",
|
||||
"first_time_homebuyer",
|
||||
"loan_purpose",
|
||||
"property_type",
|
||||
"occupancy_status",
|
||||
"property_state",
|
||||
"product_type"
|
||||
]:
|
||||
acquisition[column] = acquisition[column].astype('category').cat.codes
|
||||
|
||||
for start in ["first_payment", "origination"]:
|
||||
column = "{}_date".format(start)
|
||||
acquisition["{}_year".format(start)] = pd.to_numeric(acquisition[column].str.split('/').str.get(1))
|
||||
acquisition["{}_month".format(start)] = pd.to_numeric(acquisition[column].str.split('/').str.get(0))
|
||||
del acquisition[column]
|
||||
|
||||
acquisition = acquisition.fillna(-1)
|
||||
acquisition = acquisition[acquisition["performance_count"] > settings.MINIMUM_TRACKING_QUARTERS]
|
||||
return acquisition
|
||||
```
|
||||
|
||||
### 聚合到一起
|
||||
|
||||
我们差不多准备就绪了,我们只需要再在 `annotate.py` 添加一点点代码。在下面代码中,我们将:
|
||||
|
||||
- 定义一个函数来读取贷款的数据。
|
||||
- 定义一个函数来写入处理过的数据到 `processed/train.csv`。
|
||||
- 如果该文件在命令行以 `python annotate.py` 的方式运行:
|
||||
- 读取贷款数据。
|
||||
- 计算执行数据的计数,并将其赋予 `counts`。
|
||||
- 转换 `acquisition` DataFrame。
|
||||
- 将` acquisition` DataFrame 写入到 `train.csv`。
|
||||
|
||||
```
|
||||
def read():
|
||||
acquisition = pd.read_csv(os.path.join(settings.PROCESSED_DIR, "Acquisition.txt"), sep="|")
|
||||
return acquisition
|
||||
|
||||
def write(acquisition):
|
||||
acquisition.to_csv(os.path.join(settings.PROCESSED_DIR, "train.csv"), index=False)
|
||||
|
||||
if __name__ == "__main__":
|
||||
acquisition = read()
|
||||
counts = count_performance_rows()
|
||||
acquisition = annotate(acquisition, counts)
|
||||
write(acquisition)
|
||||
```
|
||||
|
||||
修改完成以后,确保运行 `python annotate.py` 来生成 `train.csv` 文件。 你可以在[这里][34]找到完整的 `annotate.py` 文件。
|
||||
|
||||
现在文件夹看起来应该像这样:
|
||||
|
||||
```
|
||||
loan-prediction
|
||||
├── data
|
||||
│ ├── Acquisition_2012Q1.txt
|
||||
│ ├── Acquisition_2012Q2.txt
|
||||
│ ├── Performance_2012Q1.txt
|
||||
│ ├── Performance_2012Q2.txt
|
||||
│ └── ...
|
||||
├── processed
|
||||
│ ├── Acquisition.txt
|
||||
│ ├── Performance.txt
|
||||
│ ├── train.csv
|
||||
├── .gitignore
|
||||
├── annotate.py
|
||||
├── assemble.py
|
||||
├── README.md
|
||||
├── requirements.txt
|
||||
├── settings.py
|
||||
```
|
||||
|
||||
### 找到误差标准
|
||||
|
||||
我们已经完成了训练数据表的生成,现在我们需要最后一步,生成预测。我们需要找到误差的标准,以及该如何评估我们的数据。在这种情况下,因为有很多的贷款没有被取消赎回权,所以根本不可能做到精确的计算。
|
||||
|
||||
我们需要读取训练数据,并且计算 `foreclosure_status` 列的计数,我们将得到如下信息:
|
||||
|
||||
```
|
||||
import pandas as pd
|
||||
import settings
|
||||
|
||||
train = pd.read_csv(os.path.join(settings.PROCESSED_DIR, "train.csv"))
|
||||
train["foreclosure_status"].value_counts()
|
||||
```
|
||||
|
||||
```
|
||||
False 4635982
|
||||
True 1585
|
||||
Name: foreclosure_status, dtype: int64
|
||||
```
|
||||
|
||||
因为只有很少的贷款被取消赎回权,只需要检查正确预测的标签的百分比就意味着我们可以创建一个机器学习模型,来为每一行预测 `False`,并能取得很高的精确度。相反,我们想要使用一个度量来考虑分类的不平衡,确保我们可以准确预测。我们要避免太多的误报率(预测贷款被取消赎回权,但是实际没有),也要避免太多的漏报率(预测贷款没有别取消赎回权,但是实际被取消了)。对于这两个来说,漏报率对于房利美来说成本更高,因为他们买的贷款可能是他们无法收回投资的贷款。
|
||||
|
||||
所以我们将定义一个漏报率,就是模型预测没有取消赎回权但是实际上取消了,这个数除以总的取消赎回权数。这是“缺失的”实际取消赎回权百分比的模型。下面看这个图表:
|
||||
|
||||

|
||||
|
||||
通过上面的图表,有 1 个贷款预测不会取消赎回权,但是实际上取消了。如果我们将这个数除以实际取消赎回权的总数 2,我们将得到漏报率 50%。 我们将使用这个误差标准,因此我们可以评估一下模型的行为。
|
||||
|
||||
### 设置机器学习分类器
|
||||
|
||||
我们使用交叉验证预测。通过交叉验证法,我们将数据分为3组。按照下面的方法来做:
|
||||
|
||||
- 用组 1 和组 2 训练模型,然后用该模型来预测组 3
|
||||
- 用组 1 和组 3 训练模型,然后用该模型来预测组 2
|
||||
- 用组 2 和组 3 训练模型,然后用该模型来预测组 1
|
||||
|
||||
将它们分割到不同的组,这意味着我们永远不会用相同的数据来为其预测训练模型。这样就避免了过拟合。如果过拟合,我们将错误地拉低了漏报率,这使得我们难以改进算法或者应用到现实生活中。
|
||||
|
||||
[Scikit-learn][35] 有一个叫做 [cross_val_predict][36] ,它可以帮助我们理解交叉算法.
|
||||
|
||||
我们还需要一种算法来帮我们预测。我们还需要一个分类器来做[二元分类][37]。目标变量 `foreclosure_status` 只有两个值, `True` 和 `False`。
|
||||
|
||||
这里我们用 [逻辑回归算法][38],因为它能很好的进行二元分类,并且运行很快,占用内存很小。我们来说一下它是如何工作的:不使用像随机森林一样多树结构,也不像支持向量机一样做复杂的转换,逻辑回归算法涉及更少的步骤和更少的矩阵。
|
||||
|
||||
我们可以使用 scikit-learn 实现的[逻辑回归分类器][39]算法。我们唯一需要注意的是每个类的权重。如果我们使用等权重的类,算法将会预测每行都为 `false`,因为它总是试图最小化误差。不管怎样,我们重视有多少贷款要被取消赎回权而不是有多少不能被取消。因此,我们给[逻辑回归][40]类的 `class_weight` 关键字传递 `balanced` 参数,让算法可以为不同 counts 的每个类考虑不同的取消赎回权的权重。这将使我们的算法不会为每一行都预测 `false`,而是两个类的误差水平一致。
|
||||
|
||||
### 做出预测
|
||||
|
||||
既然完成了前期准备,我们可以开始准备做出预测了。我将创建一个名为 `predict.py` 的新文件,它会使用我们在最后一步创建的 `train.csv` 文件。下面的代码:
|
||||
|
||||
- 导入所需的库
|
||||
- 创建一个名为 `cross_validate` 的函数:
|
||||
- 使用正确的关键词参数创建逻辑回归分类器
|
||||
- 创建用于训练模型的数据列的列表,移除 `id` 和 `foreclosure_status` 列
|
||||
- 交叉验证 `train` DataFrame
|
||||
- 返回预测结果
|
||||
|
||||
```python
|
||||
import os
|
||||
import settings
|
||||
import pandas as pd
|
||||
from sklearn import cross_validation
|
||||
from sklearn.linear_model import LogisticRegression
|
||||
from sklearn import metrics
|
||||
|
||||
def cross_validate(train):
|
||||
clf = LogisticRegression(random_state=1, class_weight="balanced")
|
||||
|
||||
predictors = train.columns.tolist()
|
||||
predictors = [p for p in predictors if p not in settings.NON_PREDICTORS]
|
||||
|
||||
predictions = cross_validation.cross_val_predict(clf, train[predictors], train[settings.TARGET], cv=settings.CV_FOLDS)
|
||||
return predictions
|
||||
```
|
||||
|
||||
### 预测误差
|
||||
|
||||
现在,我们仅仅需要写一些函数来计算误差。下面的代码:
|
||||
|
||||
- 创建函数 `compute_error`:
|
||||
- 使用 scikit-learn 计算一个简单的精确分数(与实际 `foreclosure_status` 值匹配的预测百分比)
|
||||
- 创建函数 `compute_false_negatives`:
|
||||
- 为了方便,将目标和预测结果合并到一个 DataFrame
|
||||
- 查找漏报率
|
||||
- 找到原本应被预测模型取消赎回权,但实际没有取消的贷款数目
|
||||
- 除以没被取消赎回权的贷款总数目
|
||||
|
||||
```python
|
||||
def compute_error(target, predictions):
|
||||
return metrics.accuracy_score(target, predictions)
|
||||
|
||||
def compute_false_negatives(target, predictions):
|
||||
df = pd.DataFrame({"target": target, "predictions": predictions})
|
||||
return df[(df["target"] == 1) & (df["predictions"] == 0)].shape[0] / (df[(df["target"] == 1)].shape[0] + 1)
|
||||
|
||||
def compute_false_positives(target, predictions):
|
||||
df = pd.DataFrame({"target": target, "predictions": predictions})
|
||||
return df[(df["target"] == 0) & (df["predictions"] == 1)].shape[0] / (df[(df["target"] == 0)].shape[0] + 1)
|
||||
```
|
||||
|
||||
### 聚合到一起
|
||||
|
||||
现在,我们可以把函数都放在 `predict.py`。下面的代码:
|
||||
|
||||
- 读取数据集
|
||||
- 计算交叉验证预测
|
||||
- 计算上面的 3 个误差
|
||||
- 打印误差
|
||||
|
||||
```python
|
||||
def read():
|
||||
train = pd.read_csv(os.path.join(settings.PROCESSED_DIR, "train.csv"))
|
||||
return train
|
||||
|
||||
if __name__ == "__main__":
|
||||
train = read()
|
||||
predictions = cross_validate(train)
|
||||
error = compute_error(train[settings.TARGET], predictions)
|
||||
fn = compute_false_negatives(train[settings.TARGET], predictions)
|
||||
fp = compute_false_positives(train[settings.TARGET], predictions)
|
||||
print("Accuracy Score: {}".format(error))
|
||||
print("False Negatives: {}".format(fn))
|
||||
print("False Positives: {}".format(fp))
|
||||
```
|
||||
|
||||
一旦你添加完代码,你可以运行 `python predict.py` 来产生预测结果。运行结果向我们展示漏报率为 `.26`,这意味着我们没能预测 `26%` 的取消贷款。这是一个好的开始,但仍有很多改善的地方!
|
||||
|
||||
你可以在[这里][41]找到完整的 `predict.py` 文件。
|
||||
|
||||
你的文件树现在看起来像下面这样:
|
||||
|
||||
```
|
||||
loan-prediction
|
||||
├── data
|
||||
│ ├── Acquisition_2012Q1.txt
|
||||
│ ├── Acquisition_2012Q2.txt
|
||||
│ ├── Performance_2012Q1.txt
|
||||
│ ├── Performance_2012Q2.txt
|
||||
│ └── ...
|
||||
├── processed
|
||||
│ ├── Acquisition.txt
|
||||
│ ├── Performance.txt
|
||||
│ ├── train.csv
|
||||
├── .gitignore
|
||||
├── annotate.py
|
||||
├── assemble.py
|
||||
├── predict.py
|
||||
├── README.md
|
||||
├── requirements.txt
|
||||
├── settings.py
|
||||
```
|
||||
|
||||
### 撰写 README
|
||||
|
||||
既然我们完成了端到端的项目,那么我们可以撰写 `README.md` 文件了,这样其他人便可以知道我们做的事,以及如何复制它。一个项目典型的 `README.md` 应该包括这些部分:
|
||||
|
||||
- 一个高水准的项目概览,并介绍项目目的
|
||||
- 任何必需的数据和材料的下载地址
|
||||
- 安装命令
|
||||
- 如何安装要求依赖
|
||||
- 使用命令
|
||||
- 如何运行项目
|
||||
- 每一步之后会看到的结果
|
||||
- 如何为这个项目作贡献
|
||||
- 扩展项目的下一步计划
|
||||
|
||||
[这里][42] 是这个项目的一个 `README.md` 样例。
|
||||
|
||||
### 下一步
|
||||
|
||||
恭喜你完成了端到端的机器学习项目!你可以在[这里][43]找到一个完整的示例项目。一旦你完成了项目,把它上传到 [Github][44] 是一个不错的主意,这样其他人也可以看到你的文件夹的部分项目。
|
||||
|
||||
这里仍有一些留待探索数据的角度。总的来说,我们可以把它们分割为 3 类: 扩展这个项目并使它更加精确,发现其他可以预测的列,并探索数据。这是其中一些想法:
|
||||
|
||||
- 在 `annotate.py` 中生成更多的特性
|
||||
- 切换 `predict.py` 中的算法
|
||||
- 尝试使用比我们发表在这里的更多的房利美数据
|
||||
- 添加对未来数据进行预测的方法。如果我们添加更多数据,我们所写的代码仍然可以起作用,这样我们可以添加更多过去和未来的数据。
|
||||
- 尝试看看是否你能预测一个银行原本是否应该发放贷款(相对地,房利美是否应该获得贷款)
|
||||
- 移除 `train` 中银行在发放贷款时间的不知道的任何列
|
||||
- 当房利美购买贷款时,一些列是已知的,但之前是不知道的
|
||||
- 做出预测
|
||||
- 探索是否你可以预测除了 `foreclosure_status` 的其他列
|
||||
- 你可以预测在销售时资产值是多少?
|
||||
- 探索探索执行数据更新之间的细微差别
|
||||
- 你能否预测借款人会逾期还款多少次?
|
||||
- 你能否标出的典型贷款周期?
|
||||
- 将数据按州或邮政编码标出
|
||||
- 你看到一些有趣的模式了吗?
|
||||
|
||||
如果你建立了任何有趣的东西,请在评论中让我们知道!
|
||||
|
||||
如果你喜欢这篇文章,或许你也会喜欢阅读“构建你的数据科学作品集”系列的其他文章:
|
||||
|
||||
- [用数据讲故事][45]
|
||||
- [如何搭建一个数据科学博客][46]
|
||||
- [构建一个可以帮你找到工作的数据科学作品集的关键][47]
|
||||
- [找到数据科学用的数据集的 17 个地方][48]
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.dataquest.io/blog/data-science-portfolio-machine-learning/
|
||||
|
||||
作者:[Vik Paruchuri][a]
|
||||
译者:[kokialoves](https://github.com/kokialoves), [zky001](https://github.com/zky001), [vim-kakali](https://github.com/vim-kakali), [cposture](https://github.com/cposture), [ideas4u](https://github.com/ideas4u)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://www.dataquest.io/blog
|
||||
[1]: https://www.dataquest.io/blog/data-science-portfolio-machine-learning/#email-signup
|
||||
[2]: https://github.com/dataquestio/loan-prediction
|
||||
[3]: https://www.dataquest.io/blog/data-science-portfolio-project/
|
||||
[4]: https://atom.io/
|
||||
[5]: https://www.jetbrains.com/pycharm/
|
||||
[6]: https://github.com/
|
||||
[7]: http://pandas.pydata.org/
|
||||
[8]: http://scikit-learn.org/
|
||||
[9]: http://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.html
|
||||
[10]: https://collegescorecard.ed.gov/data/
|
||||
[11]: https://reddit.com/r/datasets
|
||||
[12]: https://cloud.google.com/bigquery/public-data/#usa-names
|
||||
[13]: https://github.com/caesar0301/awesome-public-datasets
|
||||
[14]: http://www.fanniemae.com/portal/funding-the-market/data/loan-performance-data.html
|
||||
[15]: http://www.fanniemae.com/portal/funding-the-market/data/loan-performance-data.html
|
||||
[16]: https://loanperformancedata.fanniemae.com/lppub-docs/lppub_glossary.pdf
|
||||
[17]: https://loanperformancedata.fanniemae.com/lppub-docs/lppub_faq.pdf
|
||||
[18]: https://loanperformancedata.fanniemae.com/lppub-docs/lppub_file_layout.pdf
|
||||
[19]: https://loanperformancedata.fanniemae.com/lppub-docs/acquisition-sample-file.txt
|
||||
[20]: https://loanperformancedata.fanniemae.com/lppub-docs/performance-sample-file.txt
|
||||
[21]: https://github.com/dataquestio/loan-prediction/blob/master/.gitignore
|
||||
[22]: https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet
|
||||
[23]: https://github.com/dataquestio/loan-prediction
|
||||
[24]: https://github.com/dataquestio/loan-prediction/blob/master/requirements.txt
|
||||
[25]: https://www.continuum.io/downloads
|
||||
[26]: https://loanperformancedata.fanniemae.com/lppub/index.html
|
||||
[27]: https://loanperformancedata.fanniemae.com/lppub-docs/lppub_file_layout.pdf
|
||||
[28]: https://github.com/dataquestio/loan-prediction/blob/master/settings.py
|
||||
[29]: https://loanperformancedata.fanniemae.com/lppub-docs/lppub_file_layout.pdf
|
||||
[30]: http://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.html
|
||||
[31]: http://pandas.pydata.org/pandas-docs/stable/generated/pandas.read_csv.html
|
||||
[32]: https://github.com/dataquestio/loan-prediction/blob/master/assemble.py
|
||||
[33]: https://docs.python.org/3/library/stdtypes.html#dict.get
|
||||
[34]: https://github.com/dataquestio/loan-prediction/blob/master/annotate.py
|
||||
[35]: http://scikit-learn.org/
|
||||
[36]: http://scikit-learn.org/stable/modules/generated/sklearn.cross_validation.cross_val_predict.html
|
||||
[37]: https://en.wikipedia.org/wiki/Binary_classification
|
||||
[38]: https://en.wikipedia.org/wiki/Logistic_regression
|
||||
[39]: http://scikit-learn.org/stable/modules/generated/sklearn.linear_model.LogisticRegression.html
|
||||
[40]: http://scikit-learn.org/stable/modules/generated/sklearn.linear_model.LogisticRegression.html
|
||||
[41]: https://github.com/dataquestio/loan-prediction/blob/master/predict.py
|
||||
[42]: https://github.com/dataquestio/loan-prediction/blob/master/README.md
|
||||
[43]: https://github.com/dataquestio/loan-prediction
|
||||
[44]: https://www.github.com/
|
||||
[45]: https://www.dataquest.io/blog/data-science-portfolio-project/
|
||||
[46]: https://www.dataquest.io/blog/how-to-setup-a-data-science-blog/
|
||||
[47]: https://www.dataquest.io/blog/build-a-data-science-portfolio/
|
||||
[48]: https://www.dataquest.io/blog/free-datasets-for-projects
|
@ -0,0 +1,66 @@
|
||||
保持 Linux 容器的安全和稳定
|
||||
============
|
||||
|
||||

|
||||
|
||||
> 图片来源: [Lucarelli](http://commons.wikimedia.org/wiki/User:Lucarelli) 基于 [Wikimedia Commons](http://commons.wikimedia.org/wiki/File:Containers_Livorno.jpg). CC-BY-SA 3.0
|
||||
|
||||
Linux 容器正在改变 IT 从业者的工作方式。相比于庞大、沉重的虚拟机,一些组织发现把他们的应用部署在容器中更有效,可以提供更快的速度,更加密集,提升他们操作的敏捷性。
|
||||
|
||||
从安全的角度看,容器带来了一些优势,但是也面临着它们自己的一些安全挑战。和传统的基础设施一样,为了避免安全缺陷,确保运行在一个容器内的组件和系统库的定期更新是至关重要的。但是你如何知道什么东西运行在你的容器内?为了帮助你应对这些的安全挑战,一个名为 [Anchore](https://anchore.com)的初创公司正在开发一个[同名的开源项目](https://github.com/anchore/anchore),它用来帮助展示 Linux 容器中的内容。
|
||||
|
||||
为了了解更多关于 Anchore,我找到了 Anchore 的市场和产品的发言人 Andrew Cathrow,来了解更多关于这个开源项目背后的公司。
|
||||
|
||||

|
||||
|
||||
### 简而言之 Anchore 是什么? 它如何工作?
|
||||
|
||||
Anchore 的目标是提供一套工具,允许开发人员、运营团队、安全团队在容器的整个开发周期中保持对“监管链(Chain of Custody)”的全程可见,并提供生产部署所需的可见性、可预测性和控制性。Anchore 的引擎通过插件可以进行分析(通过提取镜像数据和元数据)、查询(允许对容器进行分析)、以及策略评估(这里的策略指可以被指定的管理的图像)。
|
||||
|
||||
虽然市场上有很多扫描工具,但是大部分不开源。我们认为安全合规的产品应该是开源的,否则你怎么才能信任他们。
|
||||
|
||||
Anchore 除了开源以外,还有两大优势,使它可以区别于市场中的商业产品。
|
||||
|
||||
首先,我们看的不止是操作系统的镜像。如今的扫描工具专注于操作系统的软件包,比如“你的 RPM 或 DEB 包中有CVE(安全漏洞)么?”这虽然是很重要的,你不希望你的镜像中有不安全的包,但是操作系统包只是镜像的基础。其他的层次都需要进行验证,包括配置文件、语言模块、中间件等等。你可以用的全是最新的软件包,但是可能一个配置文件配置出现错误,不安全就出现在里面。第二个不同就是允许用户添加自己的数据、查询或策略来扩展这个引擎。
|
||||
|
||||
### 什么推动了容器的校验和分析工具的需求出现?这个工具可以解决运营面临的什么问题呢?
|
||||
|
||||
企业使用 Docker 首要关注的就是安全,特别是他们正在部署的容器的分配和合规性。在生产环境中,从公共镜像库拉取一个镜像,运行它,并在几秒钟部署,是非常简单的,甚至不知道下面可能发生什么。终端用户在部署应用时,必须信任他们所部署的是安全、高效和易于维护的。
|
||||
|
||||
容器是不透明的,它们是一个包含应用程序的可部署的“黑盒”。虽然非常容易把这些镜像看作“打包的应用程序”,但是它们包括了系统的镜像和多达数百个包和成千上万个文件。如同所有在物理服务器、虚拟机或者云上的操作系统一样,镜像也需要维护。镜像或许包含了未补丁的安全缺陷、带有 bug 和错误配置的过期软件。
|
||||
|
||||
要对您的容器部署有信心,你需要知道底层是什么,并基于容器镜像的内容来做出决定。
|
||||
|
||||
### 如今容器的创新基本上都是开源的,你认为是为什么呢?是什么促使了它们开源呢?
|
||||
|
||||
在过去的 20 年中,各个组织已经经历了开源带来的优势,节省成本,减少锁定,提高了安全性和更快的创新。容器,特别是 Docker,都是非常好的例子。Docker 公司的团队不能在专有系统上创建一个新的软件部署模式,他们不能要求在修改专有系统的代码,而是与行业领导者比如谷歌、IBM、英特尔、红帽合作,朝着一个共同的目标。开源和 Linux 总是开启创新和激励产业困境。在过去,实现一个大的想法需要一个大的团队和很多资源。在开源世界,一个有着很大的创意的小公司可以工作在一个更大的社区中,通过知识共享的力量来协作,提供真正的企业创新。
|
||||
|
||||
为了深入的说明开源的使用,Anchroe 团队最近刚从多伦多的 LinuxCon 回来,在哪里,令人难以相信的是,微软作为钻石级的赞助商,展示了他们用在 Linux 上的产品投入的增长。Linus Toravlds 曾说过,“如果微软为 Linux 开发应用就意味着我赢了”。我要把这句话改为“开源赢了”。
|
||||
|
||||
### 容器领域的通用标准的创建还需要时间,在容器的几乎所有部分,仍有许多挑战。在这个领域,创业公司有哪些挑战?
|
||||
|
||||
这里有个很重要的点,就是没有开放的标准和开源,我们不可能看到快速推动容器的采用和改变行业格局的创新。开放容器倡议(OCI)由 Linux 和容器行业的行业领导者组成,正在为运行环境和镜像格式创造标准,这将使我们能够看到更多的创新。Anchore 很自豪能成为 OCI 的新成员,我们期待帮助形成标准。
|
||||
|
||||
###你将如何围绕 Anchor 项目建立一个开源社区?
|
||||
|
||||
Anchore 团队来自 Ansible、Eucalyptus Systems 和 Red Hat 的领导团队,在开源社区中拥有丰富的工作经验。从一开始,Anchore 就准备创建一个强大的开源社区,我们正在应用我们在开源世界中学到的经验和教训。第一课,当然,发布要尽早尽快。我们在 6 月开源我们的检测和分析引擎,远远早于我们的商用产品,以便了确保开源项目能够独立运行,使更多的直接用户能够使用它,而无需购买 Anchore 的商用产品。通过支持、服务和增强型的数据源,有很多机会给商用产品创造更多价值,但是如果开源引擎本身没有用,我们将看不到活跃的社区。
|
||||
|
||||
我们将 Anchore 模块化,允许添加分析、报告和策略插件,而不需要更改核心的引擎。我们希望保证任何人都可以创建插件,所以我们选择了 Python 作为项目的基本语言,因为 Python 被开发者和系统管理员广泛应用。但是,即使你不熟悉 Python,你仍然可以使用任何你喜欢的语言或者脚本环境创建插件。如果你可以创建一个 Bash 脚本,那么你也可以创建一个 Anchore 插件。我们的目标是最大化的吸引社区的参与。虽然我们鼓励用户将贡献回馈给社区,但是我们也为这个项目构建并进行了授权,来确保可以独立创建和维护私有的插件和模块。
|
||||
|
||||
### 容器的用途不止是在服务器上更大密度的部署应用程序或者技术层面更快的速度,而且还有不同工具的组合,这些工具提供了一种不同的方式来拉近开发者和操作者共同工作。作为在这个领域工作的公司,你们希望提供一个什么样的消息来让开发者和运营产生共鸣?
|
||||
|
||||
随着越来越多的运行环境、编排、监控和集成产品,容器的生态系统正在快速发展。所以,我们的架构中的第一个考虑因素不是限定 Anchore 的部署和使用。我们需要确保我们可以适应任何 CI/CD 工作流,无论是私有部署还是云端部署。一个经常问到我们的问题是,Anchore 是否将提供一个包含了镜像扫描和分析的容器仓库。虽然这将大大简化我们的工作,但是这会迫使用户进入特定的部署架构,并限制了用户部署他们自己最好的组件的能力。我们已经确保 Anchore 可以和所有领先的仓库、运行环境平台、 CI/CD 平台和编排工具配合使用。
|
||||
|
||||
一些开发者掌握了运营技能,并转换为 DevOps 角色,我们看到系统管理员/运营团队也在更多的了解开发,转换成 DevOps 角色。我们也看到了具有混合能力的团队。我们设计了可供开发运营和安全团队使用的 Anchore ,以便他们共同定义规则和策略来评估开发周期中的任何一个环节。另外一个例子是插件/模块的架构,使任何人都可以在他们喜欢的环境中轻松创建一个模块 —— 无论是以 Python、Go、Perl、C 甚至是一个 Bash 脚本。
|
||||
|
||||
------
|
||||
|
||||
via: https://opensource.com/business/16/10/interview-andy-cathrow-anchore
|
||||
|
||||
作者:[Jason Baker][a]
|
||||
译者:[Bestony](https://github.co/Bestony)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/jason-baker
|
600
published/20161005 GETTING STARTED WITH ANSIBLE.md
Normal file
600
published/20161005 GETTING STARTED WITH ANSIBLE.md
Normal file
@ -0,0 +1,600 @@
|
||||
Ansible 起步指南
|
||||
==========
|
||||
|
||||
这是一篇关于 Ansible 的速成课程,你可以用作小项目的模板,或者帮你深入了解这个神奇的工具。阅读了本指南之后,你将对自动化服务器配置、部署等有足够的了解。
|
||||
|
||||
### Ansible 是什么,为什么你该了解?
|
||||
|
||||
Ansible 简单的说是一个配置管理系统(configuration management system)。你只需要可以使用 ssh 访问你的服务器或设备就行。它也不同于其他工具,因为它使用推送的方式,而不是像 puppet 或 chef 那样使用拉取的方式。你可以将代码部署到任意数量的服务器上,配置网络设备或在基础架构中自动执行任何操作。
|
||||
|
||||
### 前置要求
|
||||
|
||||
假设你使用 Mac 或 Linux 作为你的工作站,Ubuntu Trusty 作为你的服务器,并有一些安装软件包的经验。此外,你的计算机上将需要以下软件。所以,如果你还没有它们,请先安装:
|
||||
|
||||
- [Virtualbox](https://www.virtualbox.org/)
|
||||
- [Vagrant](https://www.vagrantup.com/downloads.html)
|
||||
- Mac 用户:[Homebrew](http://brew.sh/)
|
||||
|
||||
### 情景
|
||||
|
||||
我们将模拟 2 个连接到 MySQL 数据库的 Web 应用程序服务器。Web 应用程序使用 Rails 5 和 Puma。
|
||||
|
||||
### 准备
|
||||
|
||||
#### Vagrantfile
|
||||
|
||||
为这个项目创建一个文件夹,并将下面的内容保存到名为 `Vagrantfile` 的文件。
|
||||
|
||||
```
|
||||
VMs = [
|
||||
[ "web1", "10.1.1.11"],
|
||||
[ "web2", "10.1.1.12"],
|
||||
[ "dbserver", "10.1.1.21"],
|
||||
]
|
||||
|
||||
Vagrant.configure(2) do |config|
|
||||
VMs.each { |vm|
|
||||
config.vm.define vm[0] do |box|
|
||||
box.vm.box = "ubuntu/trusty64"
|
||||
box.vm.network "private_network", ip: vm[1]
|
||||
box.vm.hostname = vm[0]
|
||||
box.vm.provider "virtualbox" do |vb|
|
||||
vb.memory = "512"
|
||||
end
|
||||
end
|
||||
}
|
||||
end
|
||||
```
|
||||
|
||||
#### 配置你的虚拟网络
|
||||
|
||||
我们希望我们的虚拟机能互相交互,但不要让流量流出到真实的网络,所以我们将在 Virtualbox 中创建一个仅主机(HOST-Only)的网络适配器。
|
||||
|
||||
1. 打开 Virtualbox
|
||||
2. 转到 Preferences
|
||||
3. 转到 Network
|
||||
4. 单击 Host-Only
|
||||
5. 单击添加网络
|
||||
6. 单击 Adapter
|
||||
7. 将 IPv4 设置为 `10.1.1.1`,IPv4 网络掩码:`255.255.255.0`
|
||||
8. 单击 “OK”
|
||||
|
||||
#### 测试虚拟机及虚拟网络
|
||||
|
||||
在终端中,在存放 `Vagrantfile` 的项目目录中,输入下面的命令:
|
||||
|
||||
```
|
||||
vagrant up
|
||||
```
|
||||
|
||||
它会创建你的虚拟机,因此会花费一会时间。输入下面的命令并验证输出内容以检查是否已经工作:
|
||||
|
||||
```
|
||||
$ vagrant status
|
||||
Current machine states:
|
||||
|
||||
web1 running (virtualbox)
|
||||
web2 running (virtualbox)
|
||||
master running (virtualbox)
|
||||
|
||||
This environment represents multiple VMs. The VMs are all listed
|
||||
above with their current state. For more information about a specific
|
||||
VM, run `vagrant status NAME`.
|
||||
```
|
||||
|
||||
现在使用 `vagrant` 的用户名和密码 ,按 `Vagrantfile` 中的 IP 登录其中一台虚拟机,这将验证虚拟机并将它们的密钥添加到你的已知主机(`known_hosts`)文件中。
|
||||
|
||||
```
|
||||
ssh vagrant@10.1.1.11 # password is `vagrant`
|
||||
ssh vagrant@10.1.1.12
|
||||
ssh vagrant@10.1.1.21
|
||||
```
|
||||
|
||||
恭喜你!现在你已经有可以实验的服务器了。下面的剩下的部分!
|
||||
|
||||
### 安装 Ansible
|
||||
|
||||
对于 Mac 用户:
|
||||
|
||||
```
|
||||
$ brew install ansible
|
||||
```
|
||||
|
||||
对于 Ubuntu 用户:
|
||||
|
||||
```
|
||||
$ sudo apt install ansible
|
||||
```
|
||||
|
||||
确保你使用了ansible 最近的版本 2.1 或者更高的版本:
|
||||
|
||||
```
|
||||
$ ansible --version
|
||||
ansible 2.1.1.0
|
||||
```
|
||||
|
||||
### 清单
|
||||
|
||||
Ansible 使用清单文件来了解要使用的服务器,以及如何将它们分组以并行执行任务。让我们为这个项目创建我们的清单文件 `inventory`,并将它放在与 `Vagrantfile` 相同的文件夹中:
|
||||
|
||||
```
|
||||
[all:children]
|
||||
webs
|
||||
db
|
||||
|
||||
[all:vars]
|
||||
ansible_user=vagrant
|
||||
ansible_ssh_pass=vagrant
|
||||
|
||||
[webs]
|
||||
web1 ansible_host=10.1.1.11
|
||||
web2 ansible_host=10.1.1.12
|
||||
|
||||
[db]
|
||||
dbserver ansible_host=10.1.1.21
|
||||
```
|
||||
|
||||
- `[all:children]` 定义一个组的组(`all`)
|
||||
- `[all:vars]` 定义属于组 `all` 的变量
|
||||
- `[webs]` 定义一个组,就像 `[db]` 一样
|
||||
- 文件的其余部分只是主机的声明,带有它们的名称和 IP
|
||||
- 空行表示声明结束
|
||||
|
||||
现在我们有了一个清单,我们可以从命令行开始使用 ansible,指定一个主机或一个组来执行命令。以下是检查与服务器的连接的命令示例:
|
||||
|
||||
```
|
||||
$ ansible -i inventory all -m ping
|
||||
```
|
||||
- `-i` 指定清单文件
|
||||
- `all` 指定要操作的服务器或服务器组
|
||||
- `-m' 指定一个 ansible 模块,在这种情况下为 `ping`
|
||||
|
||||
下面是命令输出:
|
||||
|
||||
```
|
||||
dbserver | SUCCESS => {
|
||||
"changed": false,
|
||||
"ping": "pong"
|
||||
}
|
||||
web1 | SUCCESS => {
|
||||
"changed": false,
|
||||
"ping": "pong"
|
||||
}
|
||||
web2 | SUCCESS => {
|
||||
"changed": false,
|
||||
"ping": "pong"
|
||||
}
|
||||
```
|
||||
|
||||
服务器以不同的顺序响应,这只取决于谁先响应,但是这个没有关系,因为 ansible 独立保持每台服务器的状态。
|
||||
|
||||
你也可以使用另外一个选项来运行任何命令:
|
||||
|
||||
- `-a <command>`
|
||||
|
||||
```
|
||||
$ ansible -i inventory all -a uptime
|
||||
web1 | SUCCESS | rc=0 >>
|
||||
21:43:27 up 25 min, 1 user, load average: 0.00, 0.01, 0.05
|
||||
|
||||
dbserver | SUCCESS | rc=0 >>
|
||||
21:43:27 up 24 min, 1 user, load average: 0.00, 0.01, 0.05
|
||||
|
||||
web2 | SUCCESS | rc=0 >>
|
||||
21:43:27 up 25 min, 1 user, load average: 0.00, 0.01, 0.05
|
||||
```
|
||||
|
||||
这是只有一台服务器的另外一个例子:
|
||||
|
||||
```
|
||||
$ ansible -i inventory dbserver -a "df -h /"
|
||||
dbserver | SUCCESS | rc=0 >>
|
||||
Filesystem Size Used Avail Use% Mounted on
|
||||
/dev/sda1 40G 1.4G 37G 4% /
|
||||
```
|
||||
|
||||
### 剧本
|
||||
|
||||
剧本(playbook)只是个 YAML 文件,它将清单文件中的服务器组与命令关联。在 ansible 中的对于关键字是 `tasks`,它可以是一个预期的状态、shell 命令或许多其它的选项。有关 ansible 可做的所有事情列表,可以查看[所有模块的列表](http://docs.ansible.com/ansible/list_of_all_modules.html)。
|
||||
|
||||
下面是一个运行 shell 命令的剧本示例,将其保存为 `playbook1.yml`:
|
||||
|
||||
```
|
||||
---
|
||||
- hosts: all
|
||||
tasks:
|
||||
- shell: uptime
|
||||
```
|
||||
|
||||
- `---` 是 YAML 文件的开始
|
||||
- ` - hosts`:指定要使用的组
|
||||
- `tasks`:标记任务列表的开始
|
||||
- ` - shell`:指定第一个任务使用 [shell] (http://docs.ansible.com/ansible/shell_module.html) 模块
|
||||
- **记住:YAML 需要缩进结构,确保你始终遵循剧本中的正确结构**
|
||||
|
||||
用下面的命令运行它:
|
||||
|
||||
```
|
||||
$ ansible-playbook -i inventory playbook1.yml
|
||||
|
||||
PLAY [all] *********************************************************************
|
||||
|
||||
TASK [setup] *******************************************************************
|
||||
ok: [web1]
|
||||
ok: [web2]
|
||||
ok: [dbmaster]
|
||||
|
||||
TASK [command] *****************************************************************
|
||||
changed: [web1]
|
||||
changed: [web2]
|
||||
changed: [dbmaster]
|
||||
|
||||
PLAY RECAP *********************************************************************
|
||||
dbmaster : ok=2 changed=1 unreachable=0 failed=0
|
||||
web1 : ok=2 changed=1 unreachable=0 failed=0
|
||||
web2 : ok=2 changed=1 unreachable=0 failed=0
|
||||
```
|
||||
|
||||
正如你所见,ansible 运行了 2 个任务,而不是只有剧本中的一个。`TASK [setup]` 是一个隐式任务,它会首先运行以捕获服务器的信息,如主机名、IP、发行版和更多详细信息,然后可以使用这些信息运行条件任务。
|
||||
|
||||
还有最后的 `PLAY RECAP`,其中 ansible 显示了运行了多少个任务以及每个对应的状态。在我们的例子中,因为我们运行了一个 shell 命令,ansible 不知道结果的状态,它被认为是 `changed`。
|
||||
|
||||
#### 安装软件
|
||||
|
||||
我们将使用 [apt](http://docs.ansible.com/ansible/apt_module.html) 在我们的服务器上安装软件,因为我们需要 root 权限,所以我们必须使用 `become` 语句,将这个内容保存在 `playbook2.yml` 中并运行它(`ansible-playbook playbook2.yml`):
|
||||
|
||||
```
|
||||
---
|
||||
- hosts: webs
|
||||
become_user: root
|
||||
become: true
|
||||
tasks:
|
||||
- apt: name=git state=present
|
||||
```
|
||||
|
||||
有一些语句可以应用于 ansible 中所有模块;一个是 `name` 语句,可以让我们输出关于正在执行的任务的更具描述性的文本。要使用它,保持任务内容一样,但是添加 `name :描述性文本` 作为第一行,所以我们以前的文本将改成:
|
||||
|
||||
```
|
||||
---
|
||||
- hosts: webs
|
||||
become_user: root
|
||||
become: true
|
||||
tasks:
|
||||
- name: This task will make sure git is present on the system
|
||||
apt: name=git state=present
|
||||
```
|
||||
|
||||
#### 使用 `with_items`
|
||||
|
||||
当你要处理一个列表时,比如要安装的项目和软件包、要创建的文件,可以用 ansible 提供的 `with_items`。下面是我们如何在 `playbook3.yml` 中使用它,同时添加一些我们已经知道的其他语句:
|
||||
|
||||
```
|
||||
---
|
||||
- hosts: all
|
||||
become_user: root
|
||||
become: true
|
||||
tasks:
|
||||
- name: Installing dependencies
|
||||
apt: name={{item}} state=present
|
||||
with_items:
|
||||
- git
|
||||
- mysql-client
|
||||
- libmysqlclient-dev
|
||||
- build-essential
|
||||
- python-software-properties
|
||||
```
|
||||
|
||||
#### 使用 `template` 和 `vars`
|
||||
|
||||
`vars` 是一个定义变量语句,可以在 `task` 语句或 `template` 文件中使用。 [Jinja2](http://jinja.pocoo.org/docs/dev/) 是 Ansible 中使用的模板引擎,但是关于它你不需要学习很多。在你的剧本中定义变量,如下所示:
|
||||
|
||||
```
|
||||
---
|
||||
- hosts: all
|
||||
vars:
|
||||
- secret_key: VqnzCLdCV9a3jK
|
||||
- path_to_vault: /opt/very/deep/path
|
||||
tasks:
|
||||
- name: Setting a configuration file using template
|
||||
template: src=myconfig.j2 dest={{path_to_vault}}/app.conf
|
||||
```
|
||||
|
||||
正如你看到的,我可以使用 `{{path_to_vault}}` 作为剧本的一部分,但也因为我使用了 `template`语句,我可以使用 `myconfig.j2` 中的任何变量,该文件必须存在一个名为 `templates` 的子文件夹中。你项目树应该如下所示:
|
||||
|
||||
```
|
||||
├── Vagrantfile
|
||||
├── inventory
|
||||
├── playbook1.yml
|
||||
├── playbook2.yml
|
||||
└── templates
|
||||
└── myconfig.j2
|
||||
```
|
||||
|
||||
当 ansible 找到一个 `template` 语句后它会在 `templates` 文件夹内查找,并将把被 `{{` 和 `}}` 括起来的变量展开来。
|
||||
|
||||
示例模板:
|
||||
|
||||
```
|
||||
this is just an example vault_dir: {{path_to_vault}} secret_password: {{secret_key}}
|
||||
```
|
||||
|
||||
即使你不扩展变量你也可以使用 `template`。考虑到将来会添加所以我先做了。比如创建一个 `hosts.j2` 模板并加入主机名和 IP。
|
||||
|
||||
```
|
||||
10.1.1.11 web1
|
||||
10.1.1.12 web2
|
||||
10.1.1.21 dbserver
|
||||
```
|
||||
|
||||
这里要用像这样的语句:
|
||||
|
||||
```
|
||||
- name: Installing the hosts file in all servers
|
||||
template: src=hosts.j2 dest=/etc/hosts mode=644
|
||||
```
|
||||
|
||||
#### shell 命令
|
||||
|
||||
你应该尽量使用模块,因为 Ansible 可以跟踪任务的状态,并避免不必要的重复,但有时 shell 命令是不可避免的。 对于这些情况,Ansible 提供两个选项:
|
||||
|
||||
- [command](http://docs.ansible.com/ansible/command_module.html):直接运行一个命令,没有环境变量或重定向(`|`,`<`,`>` 等)
|
||||
- [shell](http://docs.ansible.com/ansible/shell_module.html):运行 `/bin/sh` 并展开变量和支持重定向
|
||||
|
||||
#### 其他有用的模块
|
||||
|
||||
- [apt_repository](http://docs.ansible.com/ansible/apt_repository_module.html) - 在 Debian 系的发行版中添加/删除包仓库
|
||||
- [yum_repository](https://docs.ansible.com/ansible/yum_repository_module.html) - 在 RedHat 系的发行版中添加/删除包仓库
|
||||
- [service](http://docs.ansible.com/ansible/service_module.html) - 启动/停止/重新启动/启用/禁用服务
|
||||
- [git](http://docs.ansible.com/ansible/git_module.html) - 从 git 服务器部署代码
|
||||
- [unarchive](http://docs.ansible.com/ansible/unarchive_module.html) - 从 Web 或本地源解开软件包
|
||||
|
||||
#### 只在一台服务器中运行任务
|
||||
|
||||
Rails 使用 [migrations](http://edgeguides.rubyonrails.org/active_record_migrations.html) 来逐步更改数据库,但由于你有多个应用程序服务器,因此这些迁移任务不能被分配为组任务,而我们只需要一个服务器来运行迁移。在这种情况下,当使用 `run_once` 时,`run_once` 将分派任务到一个服务器,并直到这个任务完成继续下一个任务。你只需要在你的任务中设置 `run_once:true`。
|
||||
|
||||
```
|
||||
- name: 'Run db:migrate'
|
||||
shell: cd {{appdir}};rails db:migrate
|
||||
run_once: true
|
||||
```
|
||||
|
||||
#### 会失败的任务
|
||||
|
||||
通过指定 `ignore_errors:true`,你可以运行可能会失败的任务,但不会影响剧本中剩余的任务完成。这是非常有用的,例如,当删除最初并不存在的日志文件时。
|
||||
|
||||
```
|
||||
- name: 'Delete logs'
|
||||
shell: rm -f /var/log/nginx/errors.log
|
||||
ignore_errors: true
|
||||
```
|
||||
|
||||
### 放到一起
|
||||
|
||||
现在用我们先前学到的,这里是每个文件的最终版:
|
||||
|
||||
`Vagrantfile`:
|
||||
|
||||
```
|
||||
VMs = [
|
||||
[ "web1", "10.1.1.11"],
|
||||
[ "web2", "10.1.1.12"],
|
||||
[ "dbserver", "10.1.1.21"],
|
||||
]
|
||||
|
||||
Vagrant.configure(2) do |config|
|
||||
VMs.each { |vm|
|
||||
config.vm.define vm[0] do |box|
|
||||
box.vm.box = "ubuntu/trusty64"
|
||||
box.vm.network "private_network", ip: vm[1]
|
||||
box.vm.hostname = vm[0]
|
||||
box.vm.provider "virtualbox" do |vb|
|
||||
vb.memory = "512"
|
||||
end
|
||||
end
|
||||
}
|
||||
end
|
||||
```
|
||||
|
||||
`inventory`:
|
||||
|
||||
```
|
||||
[all:children]
|
||||
webs
|
||||
db
|
||||
|
||||
[all:vars]
|
||||
ansible_user=vagrant
|
||||
ansible_ssh_pass=vagrant
|
||||
|
||||
[webs]
|
||||
web1 ansible_host=10.1.1.11
|
||||
web2 ansible_host=10.1.1.12
|
||||
|
||||
[db]
|
||||
dbserver ansible_host=10.1.1.21
|
||||
```
|
||||
|
||||
`templates/hosts.j2`:
|
||||
|
||||
```
|
||||
10.1.1.11 web1
|
||||
10.1.1.12 web2
|
||||
10.1.1.21 dbserver
|
||||
```
|
||||
|
||||
`templates/my.cnf.j2`:
|
||||
|
||||
```
|
||||
[client]
|
||||
port = 3306
|
||||
socket = /var/run/mysqld/mysqld.sock
|
||||
|
||||
[mysqld_safe]
|
||||
socket = /var/run/mysqld/mysqld.sock
|
||||
nice = 0
|
||||
|
||||
[mysqld]
|
||||
server-id = 1
|
||||
user = mysql
|
||||
pid-file = /var/run/mysqld/mysqld.pid
|
||||
socket = /var/run/mysqld/mysqld.sock
|
||||
port = 3306
|
||||
basedir = /usr
|
||||
datadir = /var/lib/mysql
|
||||
tmpdir = /tmp
|
||||
lc-messages-dir = /usr/share/mysql
|
||||
skip-external-locking
|
||||
bind-address = 0.0.0.0
|
||||
key_buffer = 16M
|
||||
max_allowed_packet = 16M
|
||||
thread_stack = 192K
|
||||
thread_cache_size = 8
|
||||
myisam-recover = BACKUP
|
||||
query_cache_limit = 1M
|
||||
query_cache_size = 16M
|
||||
log_error = /var/log/mysql/error.log
|
||||
expire_logs_days = 10
|
||||
max_binlog_size = 100M
|
||||
|
||||
[mysqldump]
|
||||
quick
|
||||
quote-names
|
||||
max_allowed_packet = 16M
|
||||
|
||||
[mysql]
|
||||
|
||||
[isamchk]
|
||||
key_buffer = 16M
|
||||
|
||||
!includedir /etc/mysql/conf.d/
|
||||
```
|
||||
|
||||
`final-playbook.yml`:
|
||||
|
||||
```
|
||||
- hosts: all
|
||||
become_user: root
|
||||
become: true
|
||||
tasks:
|
||||
- name: 'Install common software on all servers'
|
||||
apt: name={{item}} state=present
|
||||
with_items:
|
||||
- git
|
||||
- mysql-client
|
||||
- libmysqlclient-dev
|
||||
- build-essential
|
||||
- python-software-properties
|
||||
- name: 'Install hosts file'
|
||||
template: src=hosts.j2 dest=/etc/hosts mode=644
|
||||
|
||||
- hosts: db
|
||||
become_user: root
|
||||
become: true
|
||||
tasks:
|
||||
- name: 'Software for DB server'
|
||||
apt: name={{item}} state=present
|
||||
with_items:
|
||||
- mysql-server
|
||||
- percona-xtrabackup
|
||||
- mytop
|
||||
- mysql-utilities
|
||||
- name: 'MySQL config file'
|
||||
template: src=my.cnf.j2 dest=/etc/mysql/my.cnf
|
||||
- name: 'Restart MySQL'
|
||||
service: name=mysql state=restarted
|
||||
- name: 'Grant access to web app servers'
|
||||
shell: echo 'GRANT ALL PRIVILEGES ON *.* TO "root"@"%" WITH GRANT OPTION;FLUSH PRIVILEGES;'|mysql -u root mysql
|
||||
|
||||
- hosts: webs
|
||||
vars:
|
||||
- appdir: /opt/dummyapp
|
||||
become_user: root
|
||||
become: true
|
||||
tasks:
|
||||
- name: 'Add ruby-ng repo'
|
||||
apt_repository: repo='ppa:brightbox/ruby-ng'
|
||||
- name: 'Install rails software'
|
||||
apt: name={{item}} state=present
|
||||
with_items:
|
||||
- ruby-dev
|
||||
- ruby-all-dev
|
||||
- ruby2.2
|
||||
- ruby2.2-dev
|
||||
- ruby-switch
|
||||
- libcurl4-openssl-dev
|
||||
- libssl-dev
|
||||
- zlib1g-dev
|
||||
- nodejs
|
||||
- name: 'Set ruby to 2.2'
|
||||
shell: ruby-switch --set ruby2.2
|
||||
- name: 'Install gems'
|
||||
shell: gem install bundler rails
|
||||
- name: 'Kill puma if running'
|
||||
shell: file /run/puma.pid >/dev/null && kill `cat /run/puma.pid` 2>/dev/null
|
||||
ignore_errors: True
|
||||
- name: 'Clone app repo'
|
||||
git:
|
||||
repo=https://github.com/c0d5x/rails_dummyapp.git
|
||||
dest={{appdir}}
|
||||
version=staging
|
||||
force=yes
|
||||
- name: 'Run bundler'
|
||||
shell: cd {{appdir}};bundler
|
||||
- name: 'Run db:setup'
|
||||
shell: cd {{appdir}};rails db:setup
|
||||
run_once: true
|
||||
- name: 'Run db:migrate'
|
||||
shell: cd {{appdir}};rails db:migrate
|
||||
run_once: true
|
||||
- name: 'Run rails server'
|
||||
shell: cd {{appdir}};rails server -b 0.0.0.0 -p 80 --pid /run/puma.pid -d
|
||||
```
|
||||
|
||||
### 放在你的环境中
|
||||
|
||||
将这些文件放在相同的目录,运行下面的命令打开你的开发环境:
|
||||
|
||||
```
|
||||
vagrant up
|
||||
ansible-playbook -i inventory final-playbook.yml
|
||||
```
|
||||
|
||||
### 部署新的代码
|
||||
|
||||
确保修改了代码并推送到了仓库中。接下来,确保你 git 语句中使用了正确的分支:
|
||||
|
||||
```
|
||||
- name: 'Clone app repo'
|
||||
git:
|
||||
repo=https://github.com/c0d5x/rails_dummyapp.git
|
||||
dest={{appdir}}
|
||||
version=staging
|
||||
force=yes
|
||||
```
|
||||
|
||||
作为一个例子,你可以修改 `version` 字段为 `master`,再次运行剧本:
|
||||
|
||||
```
|
||||
ansible-playbook -i inventory final-playbook.yml
|
||||
```
|
||||
|
||||
检查所有的 web 服务器上的页面是否已更改:`http://10.1.1.11` 或 `http://10.1.1.12`。将其更改为 `version = staging` 并重新运行剧本并再次检查页面。
|
||||
|
||||
你还可以创建只包含与部署相关的任务的替代剧本,以便其运行更快。
|
||||
|
||||
### 接下来是什么 ?!
|
||||
|
||||
这只是可以做的很小一部分。我们没有接触角色(role)、过滤器(filter)、调试等许多其他很棒的功能,但我希望它给了你一个良好的开始!所以,请继续学习并使用它。如果你有任何问题,你可以在 [twitter](https://twitter.com/c0d5x) 或评论栏联系我,让我知道你还想知道哪些关于 ansible 的东西!
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://gorillalogic.com/blog/getting-started-with-ansible/?utm_source=webopsweekly&utm_medium=email
|
||||
|
||||
作者:[JOSE HIDALGO][a]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 组织编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://gorillalogic.com/author/josehidalgo/
|
347
published/20161012 Introduction to FirewallD on CentOS.md
Normal file
347
published/20161012 Introduction to FirewallD on CentOS.md
Normal file
@ -0,0 +1,347 @@
|
||||
CentOS 上的 FirewallD 简明指南
|
||||
============================================================
|
||||
|
||||
[FirewallD][4] 是 iptables 的前端控制器,用于实现持久的网络流量规则。它提供命令行和图形界面,在大多数 Linux 发行版的仓库中都有。与直接控制 iptables 相比,使用 FirewallD 有两个主要区别:
|
||||
|
||||
1. FirewallD 使用区域和服务而不是链式规则。
|
||||
2. 它动态管理规则集,允许更新规则而不破坏现有会话和连接。
|
||||
|
||||
> FirewallD 是 iptables 的一个封装,可以让你更容易地管理 iptables 规则 - 它并*不是* iptables 的替代品。虽然 iptables 命令仍可用于 FirewallD,但建议使用 FirewallD 时仅使用 FirewallD 命令。
|
||||
|
||||
本指南将向您介绍 FirewallD 的区域和服务的概念,以及一些基本的配置步骤。
|
||||
|
||||
### 安装与管理 FirewallD
|
||||
|
||||
CentOS 7 和 Fedora 20+ 已经包含了 FirewallD,但是默认没有激活。可以像其它的 systemd 单元那样控制它。
|
||||
|
||||
1、 启动服务,并在系统引导时启动该服务:
|
||||
|
||||
```
|
||||
sudo systemctl start firewalld
|
||||
sudo systemctl enable firewalld
|
||||
```
|
||||
|
||||
要停止并禁用:
|
||||
|
||||
```
|
||||
sudo systemctl stop firewalld
|
||||
sudo systemctl disable firewalld
|
||||
```
|
||||
|
||||
2、 检查防火墙状态。输出应该是 `running` 或者 `not running`。
|
||||
|
||||
```
|
||||
sudo firewall-cmd --state
|
||||
```
|
||||
|
||||
3、 要查看 FirewallD 守护进程的状态:
|
||||
|
||||
```
|
||||
sudo systemctl status firewalld
|
||||
```
|
||||
|
||||
示例输出
|
||||
|
||||
```
|
||||
firewalld.service - firewalld - dynamic firewall daemon
|
||||
Loaded: loaded (/usr/lib/systemd/system/firewalld.service; disabled)
|
||||
Active: active (running) since Wed 2015-09-02 18:03:22 UTC; 1min 12s ago
|
||||
Main PID: 11954 (firewalld)
|
||||
CGroup: /system.slice/firewalld.service
|
||||
└─11954 /usr/bin/python -Es /usr/sbin/firewalld --nofork --nopid
|
||||
```
|
||||
|
||||
4、 重新加载 FirewallD 配置:
|
||||
|
||||
```
|
||||
sudo firewall-cmd --reload
|
||||
```
|
||||
|
||||
### 配置 FirewallD
|
||||
|
||||
FirewallD 使用 XML 进行配置。除非是非常特殊的配置,你不必处理它们,而应该使用 `firewall-cmd`。
|
||||
|
||||
配置文件位于两个目录中:
|
||||
|
||||
* `/usr/lib/FirewallD` 下保存默认配置,如默认区域和公用服务。 避免修改它们,因为每次 firewall 软件包更新时都会覆盖这些文件。
|
||||
* `/etc/firewalld` 下保存系统配置文件。 这些文件将覆盖默认配置。
|
||||
|
||||
#### 配置集
|
||||
|
||||
FirewallD 使用两个_配置集_:“运行时”和“持久”。 在系统重新启动或重新启动 FirewallD 时,不会保留运行时的配置更改,而对持久配置集的更改不会应用于正在运行的系统。
|
||||
|
||||
默认情况下,`firewall-cmd` 命令适用于运行时配置,但使用 `--permanent` 标志将保存到持久配置中。要添加和激活持久性规则,你可以使用两种方法之一。
|
||||
|
||||
1、 将规则同时添加到持久规则集和运行时规则集中。
|
||||
|
||||
```
|
||||
sudo firewall-cmd --zone=public --add-service=http --permanent
|
||||
sudo firewall-cmd --zone=public --add-service=http
|
||||
```
|
||||
|
||||
2、 将规则添加到持久规则集中并重新加载 FirewallD。
|
||||
|
||||
```
|
||||
sudo firewall-cmd --zone=public --add-service=http --permanent
|
||||
sudo firewall-cmd --reload
|
||||
```
|
||||
|
||||
> `reload` 命令会删除所有运行时配置并应用永久配置。因为 firewalld 动态管理规则集,所以它不会破坏现有的连接和会话。
|
||||
|
||||
### 防火墙的区域
|
||||
|
||||
“区域”是针对给定位置或场景(例如家庭、公共、受信任等)可能具有的各种信任级别的预构建规则集。不同的区域允许不同的网络服务和入站流量类型,而拒绝其他任何流量。 首次启用 FirewallD 后,`public` 将是默认区域。
|
||||
|
||||
区域也可以用于不同的网络接口。例如,要分离内部网络和互联网的接口,你可以在 `internal` 区域上允许 DHCP,但在`external` 区域仅允许 HTTP 和 SSH。未明确设置为特定区域的任何接口将添加到默认区域。
|
||||
|
||||
要找到默认区域:
|
||||
|
||||
```
|
||||
sudo firewall-cmd --get-default-zone
|
||||
```
|
||||
|
||||
要修改默认区域:
|
||||
|
||||
```
|
||||
sudo firewall-cmd --set-default-zone=internal
|
||||
```
|
||||
|
||||
要查看你网络接口使用的区域:
|
||||
|
||||
```
|
||||
sudo firewall-cmd --get-active-zones
|
||||
```
|
||||
|
||||
示例输出:
|
||||
|
||||
```
|
||||
public
|
||||
interfaces: eth0
|
||||
```
|
||||
|
||||
要得到特定区域的所有配置:
|
||||
|
||||
```
|
||||
sudo firewall-cmd --zone=public --list-all
|
||||
```
|
||||
|
||||
示例输出:
|
||||
|
||||
```
|
||||
public (default, active)
|
||||
interfaces: ens160
|
||||
sources:
|
||||
services: dhcpv6-client http ssh
|
||||
ports: 12345/tcp
|
||||
masquerade: no
|
||||
forward-ports:
|
||||
icmp-blocks:
|
||||
rich rules:
|
||||
```
|
||||
|
||||
要得到所有区域的配置:
|
||||
|
||||
```
|
||||
sudo firewall-cmd --list-all-zones
|
||||
```
|
||||
|
||||
示例输出:
|
||||
|
||||
```
|
||||
block
|
||||
interfaces:
|
||||
sources:
|
||||
services:
|
||||
ports:
|
||||
masquerade: no
|
||||
forward-ports:
|
||||
icmp-blocks:
|
||||
rich rules:
|
||||
|
||||
...
|
||||
|
||||
work
|
||||
interfaces:
|
||||
sources:
|
||||
services: dhcpv6-client ipp-client ssh
|
||||
ports:
|
||||
masquerade: no
|
||||
forward-ports:
|
||||
icmp-blocks:
|
||||
rich rules:
|
||||
```
|
||||
|
||||
|
||||
#### 与服务一起使用
|
||||
|
||||
FirewallD 可以根据特定网络服务的预定义规则来允许相关流量。你可以创建自己的自定义系统规则,并将它们添加到任何区域。 默认支持的服务的配置文件位于 `/usr/lib /firewalld/services`,用户创建的服务文件在 `/etc/firewalld/services` 中。
|
||||
|
||||
要查看默认的可用服务:
|
||||
|
||||
```
|
||||
sudo firewall-cmd --get-services
|
||||
```
|
||||
|
||||
比如,要启用或禁用 HTTP 服务:
|
||||
|
||||
```
|
||||
sudo firewall-cmd --zone=public --add-service=http --permanent
|
||||
sudo firewall-cmd --zone=public --remove-service=http --permanent
|
||||
```
|
||||
|
||||
#### 允许或者拒绝任意端口/协议
|
||||
|
||||
比如:允许或者禁用 12345 端口的 TCP 流量。
|
||||
|
||||
```
|
||||
sudo firewall-cmd --zone=public --add-port=12345/tcp --permanent
|
||||
sudo firewall-cmd --zone=public --remove-port=12345/tcp --permanent
|
||||
```
|
||||
|
||||
#### 端口转发
|
||||
|
||||
下面是**在同一台服务器上**将 80 端口的流量转发到 12345 端口。
|
||||
|
||||
```
|
||||
sudo firewall-cmd --zone="public" --add-forward-port=port=80:proto=tcp:toport=12345
|
||||
```
|
||||
|
||||
要将端口转发到**另外一台服务器上**:
|
||||
|
||||
1、 在需要的区域中激活 masquerade。
|
||||
|
||||
```
|
||||
sudo firewall-cmd --zone=public --add-masquerade
|
||||
```
|
||||
|
||||
2、 添加转发规则。例子中是将 IP 地址为 :123.456.78.9 的_远程服务器上_ 80 端口的流量转发到 8080 上。
|
||||
|
||||
|
||||
```
|
||||
sudo firewall-cmd --zone="public" --add-forward-port=port=80:proto=tcp:toport=8080:toaddr=123.456.78.9
|
||||
```
|
||||
|
||||
要删除规则,用 `--remove` 替换 `--add`。比如:
|
||||
|
||||
```
|
||||
sudo firewall-cmd --zone=public --remove-masquerade
|
||||
```
|
||||
|
||||
### 用 FirewallD 构建规则集
|
||||
|
||||
例如,以下是如何使用 FirewallD 为你的服务器配置基本规则(如果您正在运行 web 服务器)。
|
||||
|
||||
1. 将 `eth0` 的默认区域设置为 `dmz`。 在所提供的默认区域中,dmz(非军事区)是最适合于这个程序的,因为它只允许 SSH 和 ICMP。
|
||||
|
||||
```
|
||||
sudo firewall-cmd --set-default-zone=dmz
|
||||
sudo firewall-cmd --zone=dmz --add-interface=eth0
|
||||
```
|
||||
|
||||
2、 把 HTTP 和 HTTPS 添加永久的服务规则到 dmz 区域中:
|
||||
|
||||
```
|
||||
sudo firewall-cmd --zone=dmz --add-service=http --permanent
|
||||
sudo firewall-cmd --zone=dmz --add-service=https --permanent
|
||||
```
|
||||
|
||||
3、 重新加载 FirewallD 让规则立即生效:
|
||||
|
||||
```
|
||||
sudo firewall-cmd --reload
|
||||
```
|
||||
|
||||
如果你运行 `firewall-cmd --zone=dmz --list-all`, 会有下面的输出:
|
||||
|
||||
```
|
||||
dmz (default)
|
||||
interfaces: eth0
|
||||
sources:
|
||||
services: http https ssh
|
||||
ports:
|
||||
masquerade: no
|
||||
forward-ports:
|
||||
icmp-blocks:
|
||||
rich rules:
|
||||
```
|
||||
|
||||
这告诉我们,`dmz` 区域是我们的**默认**区域,它被用于 `eth0` 接口**中所有网络的**源地址**和**端口**。 允许传入 HTTP(端口 80)、HTTPS(端口 443)和 SSH(端口 22)的流量,并且由于没有 IP 版本控制的限制,这些适用于 IPv4 和 IPv6。 不允许**IP 伪装**以及**端口转发**。 我们没有 **ICMP 块**,所以 ICMP 流量是完全允许的。没有**丰富(Rich)规则**,允许所有出站流量。
|
||||
|
||||
### 高级配置
|
||||
|
||||
服务和端口适用于基本配置,但对于高级情景可能会限制较多。 丰富(Rich)规则和直接(Direct)接口允许你为任何端口、协议、地址和操作向任何区域 添加完全自定义的防火墙规则。
|
||||
|
||||
#### 丰富规则
|
||||
|
||||
丰富规则的语法有很多,但都完整地记录在 [firewalld.richlanguage(5)][5] 的手册页中(或在终端中 `man firewalld.richlanguage`)。 使用 `--add-rich-rule`、`--list-rich-rules` 、 `--remove-rich-rule` 和 firewall-cmd 命令来管理它们。
|
||||
|
||||
这里有一些常见的例子:
|
||||
|
||||
允许来自主机 192.168.0.14 的所有 IPv4 流量。
|
||||
|
||||
```
|
||||
sudo firewall-cmd --zone=public --add-rich-rule 'rule family="ipv4" source address=192.168.0.14 accept'
|
||||
```
|
||||
|
||||
拒绝来自主机 192.168.1.10 到 22 端口的 IPv4 的 TCP 流量。
|
||||
|
||||
```
|
||||
sudo firewall-cmd --zone=public --add-rich-rule 'rule family="ipv4" source address="192.168.1.10" port port=22 protocol=tcp reject'
|
||||
```
|
||||
|
||||
允许来自主机 10.1.0.3 到 80 端口的 IPv4 的 TCP 流量,并将流量转发到 6532 端口上。
|
||||
|
||||
```
|
||||
sudo firewall-cmd --zone=public --add-rich-rule 'rule family=ipv4 source address=10.1.0.3 forward-port port=80 protocol=tcp to-port=6532'
|
||||
```
|
||||
|
||||
将主机 172.31.4.2 上 80 端口的 IPv4 流量转发到 8080 端口(需要在区域上激活 masquerade)。
|
||||
|
||||
```
|
||||
sudo firewall-cmd --zone=public --add-rich-rule 'rule family=ipv4 forward-port port=80 protocol=tcp to-port=8080 to-addr=172.31.4.2'
|
||||
```
|
||||
|
||||
列出你目前的丰富规则:
|
||||
|
||||
```
|
||||
sudo firewall-cmd --list-rich-rules
|
||||
```
|
||||
|
||||
### iptables 的直接接口
|
||||
|
||||
对于最高级的使用,或对于 iptables 专家,FirewallD 提供了一个直接(Direct)接口,允许你给它传递原始 iptables 命令。 直接接口规则不是持久的,除非使用 `--permanent`。
|
||||
|
||||
要查看添加到 FirewallD 的所有自定义链或规则:
|
||||
|
||||
```
|
||||
firewall-cmd --direct --get-all-chains
|
||||
firewall-cmd --direct --get-all-rules
|
||||
```
|
||||
|
||||
讨论 iptables 的具体语法已经超出了这篇文章的范围。如果你想学习更多,你可以查看我们的 [iptables 指南][6]。
|
||||
|
||||
### 更多信息
|
||||
|
||||
你可以查阅以下资源以获取有关此主题的更多信息。虽然我们希望我们提供的是有效的,但是请注意,我们不能保证外部材料的准确性或及时性。
|
||||
|
||||
* [FirewallD 官方网站][1]
|
||||
* [RHEL 7 安全指南:FirewallD 简介][2]
|
||||
* [Fedora Wiki:FirewallD][3]
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.linode.com/docs/security/firewalls/introduction-to-firewalld-on-centos
|
||||
|
||||
作者:[Linode][a]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://www.linode.com/docs/security/firewalls/introduction-to-firewalld-on-centos
|
||||
[1]:http://www.firewalld.org/
|
||||
[2]:https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/7/html/Security_Guide/sec-Using_Firewalls.html#sec-Introduction_to_firewalld
|
||||
[3]:https://fedoraproject.org/wiki/FirewallD
|
||||
[4]:http://www.firewalld.org/
|
||||
[5]:https://jpopelka.fedorapeople.org/firewalld/doc/firewalld.richlanguage.html
|
||||
[6]:https://www.linode.com/docs/networking/firewalls/control-network-traffic-with-iptables
|
@ -0,0 +1,72 @@
|
||||
如何在 Ubuntu 16.10 的 Unity 8 上运行老式 Xorg 程序
|
||||
====
|
||||
|
||||

|
||||
|
||||
随着 Ubuntu 16.10 的发布,Unity 8 越来越吸引到了更多人的关注。这是因为在这个大家最爱的 Linux 发行版的最新版本中可以体验其带有的试验性桌面。桌面发行版是人们最熟悉的 Unity 环境,但有一点点不同。它不再使用 X11 图形技术,Ubuntu 的开发者选择了另一种截然不同的方式。
|
||||
|
||||
原来,Unity 8 用的是 Mir,这是 Ubuntu 为了在 Linux 上提供显示服务而做出的努力。这项技术已经在 Ubuntu phone 和平板上大量使用,但是这次新版是我们在桌面环境上第一次见到 Mir 。
|
||||
|
||||
这项技术相当新颖,结果是没多少 Linux 程序能运行在它之上。不是所有,那也是大部分的程序设计在 Xorg 和 X11 之上运行。如果你想要试试在 Unity 8 上运行这些程序,你肯定会为在 Unity 8上确实能够运行之前的 Xorg 程序而高兴。接下来是如何做!
|
||||
|
||||
### 登录进 Unity 8
|
||||
|
||||

|
||||
|
||||
Unity 8 在 Ubuntu 16.10 上是一个可选会话。在使用之前只须牢记一件事情:它不会加载 AMD 的图形驱动,Intel 的同样不会加载。唯一支持的图形驱动是 Nvidia 的开源驱动。要用 Unity 8 的话,只要像往常那样启动 Ubuntu,然后,在登录进去之前,点击用户名上面的 Ubuntu 图标,选择 Unity8 选项。如果万事顺利的话,这个新的、试验性的桌面环境将会加载。
|
||||
|
||||
**注意**: Unity 8 非常新而且不稳定,自行承担使用风险。
|
||||
|
||||
### 安装 Libertine
|
||||
|
||||
Xorg 程序(例如 Firefox 等)确实能在 Unity 8 上使用,在使用之前需要一点小调整。在 Mir 桌面上用终端打开 Libertine ,在 Scopes 窗口中点击终端图标就能完成。一旦打开,输入你的密码。接下来,输入以下的命令:
|
||||
|
||||

|
||||
|
||||
```
|
||||
sudo apt install libertine-tools libertine-scope libertine
|
||||
```
|
||||
|
||||
当这些程序完成安装后,点击并拖动 Scopes 窗口以刷新内容。然后,在面板上点击来启动 libertine。
|
||||
|
||||
### 新建 Xorg 容器
|
||||
|
||||
打开 Libertine,就可以新建一些(应用)容器了。这些容器很特别,因为它们能让基于 X11 的 Linux 程序在 Mir/Unity 8 桌面上的容器之中运行。另外,如果需要支持 32 位应用,勾选“i386 multiarch support”复选框。否则,什么都不要动(或者输入名字和密码),点击“OK”。
|
||||
|
||||

|
||||
|
||||
在这之后,这个 Xorg 容器就准备好,可以使用了。在 Libertine 找到它并启动。删除也很容易,右键点击容器,选择“删除”选项。
|
||||
|
||||
**注意**:每一个 Xorg 容器有 500 MB的最大内存限制。所以多个容器是有必要的。
|
||||
|
||||
### 安装软件
|
||||
|
||||

|
||||
|
||||
在 Libertine 容器中安装软件有两个方法。第一种是允许用户启动容器后选择“输入包名或者 Debian 文件”,这意味着用户可以在软件中心或者终端找到一个软件的名字,然后在 Libertine 中输入它来安装。也可以指定特定的 DEB 文件来安装,可以在Libertine LXC 容器中直接搜索安装包。
|
||||
|
||||
**注意**:Unity 8 非常新,一些程序或许不能在 Libertine 里加载或者完全安装。
|
||||
|
||||
### 结论
|
||||
|
||||
Unity 8 展现了不少的新特性,它现代、时髦,而且比之前任何一个 Unity 迭代版本都快。唯一限制它的就是使用率。事实是大部分用户更乐意选择实用的应用程序,而不是一个别致新颖的桌面环境。某种程度上来说,使用 Libertine 能解决这个问题,但它不会永久有效。早晚有一天,Canonical 都需要自行移植这些程序或者向社区求助来彻底解决这个问题。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.maketecheasier.com/use-old-xorg-apps-unity-8/
|
||||
|
||||
作者:[Derrik Diener][a]
|
||||
译者:[ypingcn](https://github.com/ypingcn)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 组织编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://www.maketecheasier.com/author/derrikdiener/
|
||||
[1]:https://www.maketecheasier.com/use-old-xorg-apps-unity-8/#respond
|
||||
|
||||
[3]:https://www.maketecheasier.com/shimo-vpn-client-for-mac/
|
||||
[4]:https://www.maketecheasier.com/schedule-windows-empty-recycle-bin/
|
||||
[5]:mailto:?subject=How%20to%20Use%20Old%20Xorg%20Apps%20in%20Unity%208%20on%20Ubuntu%2016.10&body=https%3A%2F%2Fwww.maketecheasier.com%2Fuse-old-xorg-apps-unity-8%2F
|
||||
[6]:http://twitter.com/share?url=https%3A%2F%2Fwww.maketecheasier.com%2Fuse-old-xorg-apps-unity-8%2F&text=How+to+Use+Old+Xorg+Apps+in+Unity+8+on+Ubuntu+16.10
|
||||
[7]:http://www.facebook.com/sharer.php?u=https%3A%2F%2Fwww.maketecheasier.com%2Fuse-old-xorg-apps-unity-8%2F
|
||||
[8]:https://www.maketecheasier.com/category/linux-tips/
|
50
published/20161028 Inkscape: Adding some colour.md
Normal file
50
published/20161028 Inkscape: Adding some colour.md
Normal file
@ -0,0 +1,50 @@
|
||||
使用 Inkscape:添加颜色
|
||||
=========
|
||||
|
||||

|
||||
|
||||
在我们先前的 Inkscape 文章中,[我们介绍了 Inkscape 的基础][2] - 安装,以及如何创建基本形状及操作它们。我们还介绍了使用 Palette 更改 inkscape 对象的颜色。 虽然 Palette 对于从预定义列表快速更改对象颜色非常有用,但大多数情况下,你需要更好地控制对象的颜色。这时我们使用 Inkscape 中最重要的对话框之一 - <ruby>填充和轮廓<rt>Fill and Stroke</rt></ruby> 对话框。
|
||||
|
||||
**关于文章中的动画的说明:**动画中的一些颜色看起来有条纹。这只是动画创建导致的。当你在 Inkscape 尝试时,你会看到很好的平滑渐变的颜色。
|
||||
|
||||
### 使用 Fill/Stroke 对话框
|
||||
|
||||
要在 Inkscape 中打开 “Fill and Stroke” 对话框,请从主菜单中选择 `Object`>`Fill and Stroke`。打开后,此对话框中的三个选项卡允许你检查和更改当前选定对象的填充颜色、描边颜色和描边样式。
|
||||
|
||||

|
||||
|
||||
在 Inkscape 中,Fill 用来给予对象主体颜色。对象的轮廓是你的对象的可选择外框,可在<ruby>轮廓样式<rt>Stroke style</rt></ruby>选项卡中进行配置,它允许您更改轮廓的粗细,创建虚线轮廓或为轮廓添加圆角。 在下面的动画中,我会改变星形的填充颜色,然后改变轮廓颜色,并调整轮廓的粗细:
|
||||
|
||||

|
||||
|
||||
### 添加并编辑渐变效果
|
||||
|
||||
对象的填充(或者轮廓)也可以是渐变的。要从 “Fill and Stroke” 对话框快速设置渐变填充,请先选择 “Fill” 选项卡,然后选择<ruby>线性渐变<rt>linear gradient </rt></ruby> 选项:
|
||||
|
||||

|
||||
|
||||
要进一步编辑我们的渐变,我们需要使用专门的<ruby>渐变工具<rt>Gradient Tool</rt></ruby>。 从工具栏中选择“Gradient Tool”,会有一些渐变编辑锚点出现在你选择的形状上。 **移动锚点**将改变渐变的位置。 如果你**单击一个锚点**,您还可以在“Fill and Stroke”对话框中更改该锚点的颜色。 要**在渐变中添加新的锚点**,请双击连接锚点的线,然后会出现一个新的锚点。
|
||||
|
||||

|
||||
|
||||
* * *
|
||||
|
||||
这篇文章介绍了在 Inkscape 图纸中添加一些颜色和渐变的基础知识。 **“Fill and Stroke”** 对话框还有许多其他选项可供探索,如图案填充、不同的渐变样式和许多不同的轮廓样式。另外,查看**<ruby>工具控制栏<rt>Tools control bar</rt></ruby>** 的 **Gradient Tool** 中的其他选项,看看如何以不同的方式调整渐变。
|
||||
|
||||
-----------------------
|
||||
|
||||
作者简介:Ryan 是一名 Fedora 设计师。他使用 Fedora Workstation 作为他的主要桌面,还有来自 Libre Graphics 世界的最好的工具,尤其是矢量图形编辑器 Inkscape。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://fedoramagazine.org/inkscape-adding-colour/
|
||||
|
||||
作者:[Ryan Lerch][a]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[jasminepeng](https://github.com/jasminepeng)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: http://ryanlerch.id.fedoraproject.org/
|
||||
[1]:https://fedoramagazine.org/inkscape-adding-colour/
|
||||
[2]:https://linux.cn/article-8079-1.html
|
@ -0,0 +1,245 @@
|
||||
用 dpkg 命令在 Debian 系的 Linux 系统中管理软件包
|
||||
==================
|
||||
|
||||
[dpkg][7] 意即 Debian 包管理器(Debian PacKaGe manager)。dpkg 是一个可以安装、构建、删除及管理 Debian 软件包的命令行工具。dpkg 将 Aptitude(首选而更用户友好)作为执行所有操作的前端界面。
|
||||
|
||||
其它的一些工具如 dpkg-deb 和 dpkg-query 等也使用 dpkg 作为执行某些操作的前端。
|
||||
|
||||
现在大多数系统管理员使用 Apt、[Apt-Get][6] 及 Aptitude 等工具,不用费心就可以轻松地管理软件。
|
||||
|
||||
尽管如此,必要的时候还是需要用 dpkg 来安装某些软件。其它的一些在 Linux 系统上广泛使用的包管理工具还有 [yum][5]、[dnf][4]、[apt-get][3]、dpkg、[rpm][2]、[Zypper][1]、pacman、urpmi 等等。
|
||||
|
||||
现在,我要在装有 Ubuntu 15.10 的机器上用一些实例讲解最常用的 dpkg 命令。
|
||||
|
||||
### 1) dpkg 常见命令的语法及 dpkg 文件位置
|
||||
|
||||
下面是 dpkg 常见命令的语法及 dpkg 相关文件的位置,如果想深入了解,这些对你肯定大有益处。
|
||||
|
||||
```
|
||||
### dpkg 命令的语法
|
||||
$ dpkg -[command] [.deb package name]
|
||||
|
||||
$ dpkg -[command] [package name]
|
||||
|
||||
### dpkg 相关文件的位置
|
||||
$ /var/lib/dpkg
|
||||
|
||||
### 这个文件包含了被 dpkg 命令(install、remove 等)所修改的包的信息
|
||||
$ /var/lib/dpkg/status
|
||||
|
||||
### 这个文件包含了可用包的列表
|
||||
$ /var/lib/dpkg/status
|
||||
|
||||
```
|
||||
|
||||
### 2) 安装/升级软件
|
||||
|
||||
在基于 Debian 的系统里,比如 Debian、Mint、Ubuntu 和 elementryOS,用以下命令来安装/升级 .deb 软件包。这里我要用 `atom-amd64.deb` 文件安装 Atom。要是已经安装了 Atom,就会升级它。要么就会安装一个新的 Atom。
|
||||
|
||||
```
|
||||
### 安装或升级 dpkg 软件包
|
||||
$ sudo dpkg -i atom-amd64.deb
|
||||
Selecting previously unselected package atom.
|
||||
(Reading database ... 426102 files and directories currently installed.)
|
||||
Preparing to unpack atom-amd64.deb ...
|
||||
Unpacking atom (1.5.3) over (1.5.3) ...
|
||||
Setting up atom (1.5.3) ...
|
||||
Processing triggers for gnome-menus (3.13.3-6ubuntu1) ...
|
||||
Processing triggers for bamfdaemon (0.5.2~bzr0+15.10.20150627.1-0ubuntu1) ...
|
||||
Rebuilding /usr/share/applications/bamf-2.index...
|
||||
Processing triggers for desktop-file-utils (0.22-1ubuntu3) ...
|
||||
Processing triggers for mime-support (3.58ubuntu1) ...
|
||||
|
||||
```
|
||||
|
||||
### 3) 从文件夹里安装软件
|
||||
|
||||
在基于 Debian 的系统里,用下列命令从目录中逐个安装软件。这会安装 `/opt/software` 目录下的所有以 .deb 为后缀的软件。
|
||||
|
||||
```
|
||||
$ sudo dpkg -iR /opt/software
|
||||
Selecting previously unselected package atom.
|
||||
(Reading database ... 423303 files and directories currently installed.)
|
||||
Preparing to unpack /opt/software/atom-amd64.deb ...
|
||||
Unpacking atom (1.5.3) ...
|
||||
Setting up atom (1.5.3) ...
|
||||
Processing triggers for gnome-menus (3.13.3-6ubuntu1) ...
|
||||
Processing triggers for bamfdaemon (0.5.2~bzr0+15.10.20150627.1-0ubuntu1) ...
|
||||
Rebuilding /usr/share/applications/bamf-2.index...
|
||||
Processing triggers for desktop-file-utils (0.22-1ubuntu3) ...
|
||||
Processing triggers for mime-support (3.58ubuntu1) ...
|
||||
```
|
||||
|
||||
### 4) 显示已安装软件列表
|
||||
|
||||
以下命令可以列出 Debian 系的系统中所有已安装的软件,同时会显示软件版本和描述信息。
|
||||
|
||||
```
|
||||
$ dpkg -l
|
||||
Desired=Unknown/Install/Remove/Purge/Hold
|
||||
| Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend
|
||||
|/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad)
|
||||
||/ Name Version Architecture Description
|
||||
+++-===========================-==================================-============-================================================================
|
||||
ii account-plugin-aim 3.12.10-0ubuntu2 amd64 Messaging account plugin for AIM
|
||||
ii account-plugin-facebook 0.12+15.10.20150723-0ubuntu1 all GNOME Control Center account plugin for single signon - facebook
|
||||
ii account-plugin-flickr 0.12+15.10.20150723-0ubuntu1 all GNOME Control Center account plugin for single signon - flickr
|
||||
ii account-plugin-google 0.12+15.10.20150723-0ubuntu1 all GNOME Control Center account plugin for single signon
|
||||
ii account-plugin-jabber 3.12.10-0ubuntu2 amd64 Messaging account plugin for Jabber/XMPP
|
||||
ii account-plugin-salut 3.12.10-0ubuntu2 amd64 Messaging account plugin for Local XMPP (Salut)
|
||||
.
|
||||
.
|
||||
|
||||
```
|
||||
|
||||
### 5) 查看指定的已安装软件
|
||||
|
||||
用以下命令列出指定的一个已安装软件,同时会显示软件版本和描述信息。
|
||||
|
||||
```
|
||||
$ dpkg -l atom
|
||||
Desired=Unknown/Install/Remove/Purge/Hold
|
||||
| Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend
|
||||
|/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad)
|
||||
||/ Name Version Architecture Description
|
||||
+++-==========-=========-===================-============================================
|
||||
ii atom 1.5.3 amd64 A hackable text editor for the 21st Century.
|
||||
|
||||
```
|
||||
|
||||
### 6) 查看软件安装目录
|
||||
|
||||
以下命令可以在基于 Debian 的系统上查看软件的安装路径。
|
||||
|
||||
```
|
||||
$ dpkg -L atom
|
||||
/.
|
||||
/usr
|
||||
/usr/bin
|
||||
/usr/bin/atom
|
||||
/usr/share
|
||||
/usr/share/lintian
|
||||
/usr/share/lintian/overrides
|
||||
/usr/share/lintian/overrides/atom
|
||||
/usr/share/pixmaps
|
||||
/usr/share/pixmaps/atom.png
|
||||
/usr/share/doc
|
||||
|
||||
```
|
||||
|
||||
### 7) 查看 deb 包内容
|
||||
|
||||
下列命令可以查看 deb 包内容。它会显示 .deb 包中的一系列文件。
|
||||
|
||||
```
|
||||
$ dpkg -c atom-amd64.deb
|
||||
drwxr-xr-x root/root 0 2016-02-13 02:13 ./
|
||||
drwxr-xr-x root/root 0 2016-02-13 02:13 ./usr/
|
||||
drwxr-xr-x root/root 0 2016-02-13 02:13 ./usr/bin/
|
||||
-rwxr-xr-x root/root 3067 2016-02-13 02:13 ./usr/bin/atom
|
||||
drwxr-xr-x root/root 0 2016-02-13 02:13 ./usr/share/
|
||||
drwxr-xr-x root/root 0 2016-02-13 02:13 ./usr/share/lintian/
|
||||
drwxr-xr-x root/root 0 2016-02-13 02:13 ./usr/share/lintian/overrides/
|
||||
-rw-r--r-- root/root 299 2016-02-13 02:13 ./usr/share/lintian/overrides/atom
|
||||
drwxr-xr-x root/root 0 2016-02-13 02:13 ./usr/share/pixmaps/
|
||||
-rw-r--r-- root/root 643183 2016-02-13 02:13 ./usr/share/pixmaps/atom.png
|
||||
drwxr-xr-x root/root 0 2016-02-13 02:13 ./usr/share/doc/
|
||||
.
|
||||
.
|
||||
```
|
||||
|
||||
### 8) 显示软件的详细信息
|
||||
|
||||
以下命令可以显示软件的详细信息,如软件名、软件类别、版本、维护者、软件架构、依赖的软件、软件描述等等。
|
||||
|
||||
```
|
||||
$ dpkg -s atom
|
||||
Package: atom
|
||||
Status: install ok installed
|
||||
Priority: optional
|
||||
Section: devel
|
||||
Installed-Size: 213496
|
||||
Maintainer: GitHub <atom@github.com>Architecture: amd64
|
||||
Version: 1.5.3
|
||||
Depends: git, gconf2, gconf-service, libgtk2.0-0, libudev0 | libudev1, libgcrypt11 | libgcrypt20, libnotify4, libxtst6, libnss3, python, gvfs-bin, xdg-utils, libcap2
|
||||
Recommends: lsb-release
|
||||
Suggests: libgnome-keyring0, gir1.2-gnomekeyring-1.0
|
||||
Description: A hackable text editor for the 21st Century.
|
||||
Atom is a free and open source text editor that is modern, approachable, and hackable to the core.</atom@github.com>
|
||||
```
|
||||
|
||||
### 9) 查看文件属于哪个软件
|
||||
|
||||
用以下命令来查看文件属于哪个软件。
|
||||
|
||||
```
|
||||
$ dpkg -S /usr/bin/atom
|
||||
atom: /usr/bin/atom
|
||||
|
||||
```
|
||||
|
||||
### 10) 移除/删除软件
|
||||
|
||||
以下命令可以用来移除/删除一个已经安装的软件,但不删除配置文件。
|
||||
|
||||
|
||||
```
|
||||
$ sudo dpkg -r atom
|
||||
(Reading database ... 426404 files and directories currently installed.)
|
||||
Removing atom (1.5.3) ...
|
||||
Processing triggers for gnome-menus (3.13.3-6ubuntu1) ...
|
||||
Processing triggers for bamfdaemon (0.5.2~bzr0+15.10.20150627.1-0ubuntu1) ...
|
||||
Rebuilding /usr/share/applications/bamf-2.index...
|
||||
Processing triggers for desktop-file-utils (0.22-1ubuntu3) ...
|
||||
Processing triggers for mime-support (3.58ubuntu1) ...
|
||||
|
||||
```
|
||||
|
||||
### 11) 清除软件
|
||||
|
||||
以下命令可以用来移除/删除包括配置文件在内的所有文件。
|
||||
|
||||
```
|
||||
$ sudo dpkg -P atom
|
||||
(Reading database ... 426404 files and directories currently installed.)
|
||||
Removing atom (1.5.3) ...
|
||||
Processing triggers for gnome-menus (3.13.3-6ubuntu1) ...
|
||||
Processing triggers for bamfdaemon (0.5.2~bzr0+15.10.20150627.1-0ubuntu1) ...
|
||||
Rebuilding /usr/share/applications/bamf-2.index...
|
||||
Processing triggers for desktop-file-utils (0.22-1ubuntu3) ...
|
||||
Processing triggers for mime-support (3.58ubuntu1) ...
|
||||
|
||||
```
|
||||
|
||||
### 12) 了解更多
|
||||
|
||||
用以下命令来查看更多关于 dpkg 的信息。
|
||||
|
||||
```
|
||||
$ dpkg -help
|
||||
或
|
||||
$ man dpkg
|
||||
|
||||
```
|
||||
|
||||
开始体验 dpkg 吧。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: http://www.2daygeek.com/dpkg-command-examples/
|
||||
|
||||
作者:[MAGESH MARUTHAMUTHU][a]
|
||||
译者:[GitFuture](https://github.com/GitFuture)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:http://www.2daygeek.com/author/magesh/
|
||||
[1]:http://www.2daygeek.com/zypper-command-examples/
|
||||
[2]:http://www.2daygeek.com/rpm-command-examples/
|
||||
[3]:http://www.2daygeek.com/apt-get-apt-cache-command-examples/
|
||||
[4]:http://www.2daygeek.com/dnf-command-examples/
|
||||
[5]:http://www.2daygeek.com/yum-command-examples/
|
||||
[6]:http://www.2daygeek.com/apt-get-apt-cache-command-examples/
|
||||
[7]:https://wiki.debian.org/Teams/Dpkg
|
||||
[8]:http://www.2daygeek.com/author/magesh/
|
@ -0,0 +1,54 @@
|
||||
病毒过后,系统管理员投向了 Linux
|
||||
=======================================================
|
||||
|
||||

|
||||
|
||||
我开源事业的第一笔,是我在 2001 年作为一名兼职系统管理员,为大学工作的时候。成为了那个以教学为目的,不仅仅在大学中,还在学术界的其他领域建立商业案例研究的小组的一份子。
|
||||
|
||||
随着团队的发展,渐渐地开始需要一个由文件服务、intranet 应用,域登录等功能构建而成的健壮的局域网。 我们的 IT 基础设施主要由跑着 Windows 98 的计算机组成,这些计算机对于大学的 IT 实验室来说已经太老了,就重新分配给了我们部门。
|
||||
|
||||
### 初探 Linux
|
||||
|
||||
一天,作为大学IT采购计划的一部分,我们部门收到了一台 IBM 服务器。 我们计划将其用作 Internet 网关,域控制站,文件服务器和备份服务器,以及 intranet 应用程序主机。
|
||||
|
||||
拆封后,我们注意到它附带了红帽 Linux 的 CD。 我们的 22 人团队(包括我)对 Linux 一无所知。 经过几天的研究,我找到了一位朋友的朋友,一位以 Linux RTOS (Linux 的实时操作系统领域)编程为生的人,求助他如何安装。
|
||||
|
||||
光看着那朋友用 CD 驱动器载入第一张安装 CD 并进入 Anaconda 安装系统,我的头都晕了。 大约一个小时,我们完成了基本的安装,但仍然没有可用的 internet 连接。
|
||||
|
||||
又花了一个小时的折腾才使我们连接到互联网,但仍没有域登录或 Internet 网关功能。 经过一个周末的折腾,我们可以让我们的 Windows 98 机器作为 Linux PC 的代理,终于构出了一个正常工作的共享互联环境。 但域登录还需要一段时间。
|
||||
|
||||
我们用龟速的电话调制解调器下载了 [Samba][1],并手动配置它作为域控制站。文件服务也通过 NFS Kernel Server 开启了,随后为 Windows 98 的网络邻居创建了用户目录并进行了必要的调整和配置。
|
||||
|
||||
这个设置完美运行了一段时间,直到最终我们决定开始使用 Intranet 应用管理时间表和一些别的东西。 这个时候,我已经离开了该组织,并把大部分系统管理员的东西交给了接替我的人。
|
||||
|
||||
### 再遇 Linux
|
||||
|
||||
2004 年,我又重新装回了 Linux。我的妻子经营的一份独立员工安置业务,使用来自 Monster.com 等服务的数据来打通客户与求职者的交流渠道。
|
||||
|
||||
作为我们两人中的计算机好点的那个,在计算机和互联网出故障的时候,维修就成了我的分内之事。我们还需要用许多工具尝试,从堆积如山的简历中筛选出她每天必须看的。
|
||||
|
||||
Windows [BSoD][2](蓝屏) 早已司空见惯,但只要我们的付费数据是安全的,那就还算可以容忍。为此我将不得不每周花几个小时去做备份。
|
||||
|
||||
一天,我们的电脑中了毒,并且通过简单的方法无法清除。我们并不了解磁盘上的数据发生了些什么。当磁盘彻底挂掉后,我们插入了一周前的辅助备份磁盘,但是一周后它也挂了。我们的第二个备份直接拒绝启动。是时候寻求专业帮助了,所以我们把电脑送到一家靠谱的维修店。两天以后,我们被告知一些恶意软件或病毒已经将某些种类的文件擦除殆尽,其中包括我们的付费数据。
|
||||
|
||||
这是对我妻子的商业计划的一个巨大的打击,同时意味着丢失合同并耽误了账单。我曾短期出国工作,并在台湾的 [Computex 2004][3] 购买了我的第一台笔记本电脑。 预装的是 Windows XP,但我还是想换成 Linux。 我知道 Linux 已经为桌面端做好了准备,[Mandrake Linux][4] (曼德拉草) 是一个很不错的选择。 我第一次安装就很顺利。所有工作都执行的非常漂亮。我使用 [OpenOffice][5] 来满足我写作,演示文稿和电子表格的需求。
|
||||
|
||||
我们为我们的计算机买了新的硬盘驱动器,并为其安装了 Mandrake Linux。用 OpenOffice 替换了 Microsoft Office。 我们依靠 Web 邮件来满足邮件需求,并在 2004 年的 11 月迎来了 [Mozilla Firefox][6]。我的妻子马上从中看到了好处,因为没有崩溃或病毒/恶意软件感染!更重要的是,我们告别了困扰 Windows 98 和 XP 的频繁崩溃问题。 她一直使用这个发行版。
|
||||
|
||||
而我,开始尝试其他的发行版。 我爱上了 distro-hopping (LCTT 译注:指在不同版本的 Linux 发行版之间频繁切换的 Linux 用户)和第一时间尝试新发行版的感觉。我也经常会在 Apache 和 NGINX 上尝试和测试 Web 应用程序,如 Drupal、Joomla 和 WordPress。现在我们 2006 年出生的儿子,在 Linux 下成长。 也对 Tux Paint,Gcompris 和 SMPlayer 非常满意。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/life/16/3/my-linux-story-soumya-sarkar
|
||||
|
||||
作者:[Soumya Sarkar][a]
|
||||
译者:[martin2011qi](https://github.com/martin2011qi)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
[a]: https://opensource.com/users/ssarkarhyd
|
||||
[1]: https://www.samba.org/
|
||||
[2]: https://en.wikipedia.org/wiki/Blue_Screen_of_Death
|
||||
[3]: https://en.wikipedia.org/wiki/Computex_Taipei
|
||||
[4]: https://en.wikipedia.org/wiki/Mandriva_Linux
|
||||
[5]: http://www.openoffice.org/
|
||||
[6]: https://www.mozilla.org/en-US/firefox/new/
|
@ -0,0 +1,101 @@
|
||||
我成为软件工程师的原因和经历
|
||||
==========================================
|
||||
|
||||

|
||||
|
||||
1989 年乌干达首都,坎帕拉。
|
||||
|
||||
我明智的父母决定与其将我留在家里添麻烦,不如把我送到叔叔的办公室学学电脑。几天后,我和另外六、七个小孩,还有一台放置在课桌上的崭新电脑,一起置身于 21 层楼的一间狭小房屋中。很明显我们还不够格去碰那家伙。在长达三周无趣的 DOS 命令学习后,美好时光来到,终于轮到我来输 **copy doc.txt d:** 啦。
|
||||
|
||||
那将文件写入五英寸软盘的奇怪的声音,听起来却像音乐般美妙。那段时间,这块软盘简直成为了我的至宝。我把所有可以拷贝的东西都放在上面了。然而,1989 年的乌干达,人们的生活十分“正统”,相比较而言,捣鼓电脑、拷贝文件还有格式化磁盘就称不上“正统”。于是我不得不专注于自己接受的教育,远离计算机科学,走入建筑工程学。
|
||||
|
||||
之后几年里,我和同龄人一样,干过很多份工作也学到了许多技能。我教过幼儿园的小朋友,也教过大人如何使用软件,在服装店工作过,还在教堂中担任过引座员。在我获取堪萨斯大学的学位时,我正在技术管理员的手下做技术助理,听上去比较神气,其实也就是搞搞学生数据库而已。
|
||||
|
||||
当我 2007 年毕业时,计算机技术已经变得不可或缺。建筑工程学的方方面面都与计算机科学深深的交织在一起,所以我们不经意间学了些简单的编程知识。我对于这方面一直很着迷,但我不得不成为一位“正统”的工程师,由此我发展了一项秘密的私人爱好:写科幻小说。
|
||||
|
||||
在我的故事中,我以我笔下的女主角的形式存在。她们都是编程能力出众的科学家,总是卷入冒险,并用自己的技术发明战胜那些渣渣们,有时甚至要在现场发明新方法。我提到的这些“新技术”,有的是基于真实世界中的发明,也有些是从科幻小说中读到的。这就意味着我需要了解这些技术的原理,而且我的研究使我关注了许多有趣的 reddit 版块和电子杂志。
|
||||
|
||||
### 开源:巨大的宝库
|
||||
|
||||
那几周在 DOS 命令上花费的经历对我影响巨大,我在一些非专业的项目上耗费心血,并占据了宝贵的学习时间。Geocities 刚向所有 Yahoo! 用户开放时,我就创建了一个网站,用于发布一些用小型数码相机拍摄的个人图片。我建立多个免费网站,帮助家人和朋友解决一些他们所遇到的电脑问题,还为教堂搭建了一个图书馆数据库。
|
||||
|
||||
这意味着,我需要一直研究并尝试获取更多的信息,使它们变得更棒。互联网上帝保佑我,让开源进入我的视野。突然之间,30 天试用期和 license 限制对我而言就变成了过去式。我可以完全不受这些限制,继续使用 GIMP、Inkscape 和 OpenOffice。
|
||||
|
||||
### 是正经做些事情的时候了
|
||||
|
||||
我很幸运,有商业伙伴喜欢我的经历。她也是个想象力丰富的人,期待更高效、更便捷的互联世界。我们根据我们以往成功道路中经历的弱点制定了解决方案,但执行却成了一个问题。我们都缺乏给产品带来活力的能力,每当我们试图将想法带到投资人面前时,这表现的尤为突出。
|
||||
|
||||
我们需要学习编程。于是 2015 年夏末,我们来到 Holberton 学校。那是一所座落于旧金山,由社区推进,基于项目教学的学校。
|
||||
|
||||
一天早晨我的商业伙伴来找我,以她独有的方式(每当她有疯狂想法想要拉我入伙时),进行一场对话。
|
||||
|
||||
**Zee**: Gloria,我想和你说点事,在你说“不”前能先听我说完吗?
|
||||
|
||||
**Me**: 不行。
|
||||
|
||||
**Zee**: 为做全栈工程师,咱们申请上一所学校吧。
|
||||
|
||||
**Me**: 什么?
|
||||
|
||||
**Zee**: 就是这,看!就是这所学校,我们要申请这所学校来学习编程。
|
||||
|
||||
**Me**: 我不明白。我们不是正在网上学 Python 和…
|
||||
|
||||
**Zee**: 这不一样。相信我。
|
||||
|
||||
**Me**: 那…
|
||||
|
||||
**Zee**: 这就是不信任我了。
|
||||
|
||||
**Me**: 好吧 … 给我看看。
|
||||
|
||||
### 抛开偏见
|
||||
|
||||
我读到的和我们在网上看的的似乎很相似。这简直太棒了,以至于让人觉得不太真实,但我们还是决定尝试一下,全力以赴,看看结果如何。
|
||||
|
||||
要成为学生,我们需要经历四步选择,不过选择的依据仅仅是天赋和动机,而不是学历和编程经历。筛选便是课程的开始,通过它我们开始学习与合作。
|
||||
|
||||
根据我和我伙伴的经验, Holberton 学校的申请流程比其他的申请流程有趣太多了,就像场游戏。如果你完成了一项挑战,就能通往下一关,在那里有别的有趣的挑战正等着你。我们创建了 Twitter 账号,在 Medium 上写博客,为创建网站而学习 HTML 和 CSS, 打造了一个充满活力的在线社区,虽然在此之前我们并不知晓有谁会来。
|
||||
|
||||
在线社区最吸引人的就是大家有多种多样的使用电脑的经验,而背景和性别不是社区创始人(我们私下里称他们为“The Trinity”)做出选择的因素。大家只是喜欢聚在一块儿交流。我们都行进在通过学习编程来提升自己计算机技术的旅途上。
|
||||
|
||||
相较于其他的的申请流程,我们不需要泄露很多的身份信息。就像我的伙伴,她的名字里看不出她的性别和种族。直到最后一个步骤,在视频聊天的时候, The Trinity 才知道她是一位有色人种女性。迄今为止,促使她达到这个级别的只是她的热情和才华。肤色和性别并没有妨碍或者帮助到她。还有比这更酷的吗?
|
||||
|
||||
获得录取通知书的晚上,我们知道生活将向我们的梦想转变。2016 年 1 月 22 日,我们来到巴特瑞大街 98 号,去见我们的同学们 [Hippokampoiers][2],这是我们的初次见面。很明显,在见面之前,“The Trinity”已经做了很多工作,聚集了一批形形色色的人,他们充满激情与热情,致力于成长为全栈工程师。
|
||||
|
||||
这所学校有种与众不同的体验。每天都是向某一方面编程的一次竭力的冲锋。交给我们的工程,并不会有很多指导,我们需要使用一切可以使用的资源找出解决方案。[Holberton 学校][1] 认为信息来源相较于以前已经大大丰富了。MOOC(大型开放式课程)、教程、可用的开源软件和项目,以及线上社区等等,为我们完成项目提供了足够的知识。加之宝贵的导师团队来指导我们制定解决方案,这所学校变得并不仅仅是一所学校;我们已经成为了求学者的团体。任何对软件工程感兴趣并对这种学习方法感兴趣的人,我都强烈推荐这所学校。在这里的经历会让人有些悲喜交加,但是绝对值得。
|
||||
|
||||
### 开源问题
|
||||
|
||||
我最早使用的开源系统是 [Fedora][3],一个 [Red Hat][4] 赞助的项目。与 一名IRC 成员交流时,她推荐了这款免费的操作系统。 虽然在此之前,我还未独自安装过操作系统,但是这激起了我对开源的兴趣和日常使用计算机时对开源软件的依赖性。我们提倡为开源贡献代码,创造并使用开源的项目。我们的项目就在 Github 上,任何人都可以使用或是向它贡献出自己的力量。我们也会使用或以自己的方式为一些既存的开源项目做出贡献。在学校里,我们使用的大部分工具是开源的,例如 Fedora、[Vagrant][5]、[VirtualBox][6]、[GCC][7] 和 [Discourse][8],仅举几例。
|
||||
|
||||
在向软件工程师行进的路上,我始终憧憬着有朝一日能为开源社区做出一份贡献,能与他人分享我所掌握的知识。
|
||||
|
||||
### 多样性问题
|
||||
|
||||
站在教室里,和 29 位求学者交流心得,真是令人陶醉。学员中 40% 是女性, 44% 是有色人种。当你是一位有色人种且为女性,并身处于这个以缺乏多样性而著名的领域时,这些数字就变得非常重要了。这是高科技圣地麦加上的绿洲,我到达了。
|
||||
|
||||
想要成为一个全栈工程师是十分困难的,你甚至很难了解这意味着什么。这是一条充满挑战但又有丰富回报的旅途。科技推动着未来飞速发展,而你也是美好未来很重要的一部分。虽然媒体在持续的关注解决科技公司的多样化的问题,但是如果能认清自己,清楚自己的背景,知道自己为什么想成为一名全栈工程师,你便能在某一方面迅速成长。
|
||||
|
||||
不过可能最重要的是,告诉大家,女性在计算机的发展史上扮演过多么重要的角色,以帮助更多的女性回归到科技界,而且在给予就业机会时,不会因性别等因素而感到犹豫。女性的才能将会共同影响科技的未来,以及整个世界的未来。
|
||||
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/life/16/4/my-open-source-story-gloria-bwandungi
|
||||
|
||||
作者:[Gloria Bwandungi][a]
|
||||
译者:[martin2011qi](https://github.com/martin2011qi)
|
||||
校对:[jasminepeng](https://github.com/jasminepeng)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创翻译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://opensource.com/users/nappybrain
|
||||
[1]: https://www.holbertonschool.com/
|
||||
[2]: https://twitter.com/hippokampoiers
|
||||
[3]: https://en.wikipedia.org/wiki/Fedora_(operating_system)
|
||||
[4]: https://www.redhat.com/
|
||||
[5]: https://www.vagrantup.com/
|
||||
[6]: https://www.virtualbox.org/
|
||||
[7]: https://gcc.gnu.org/
|
||||
[8]: https://www.discourse.org/
|
@ -0,0 +1,140 @@
|
||||
通过 docker-compose 进行快速原型设计
|
||||
========================================
|
||||
|
||||
在这篇文章中,我们将考察一个 Node.js 开发原型,该原型用于从英国三个主要折扣网店查找“Raspberry PI Zero”的库存。
|
||||
|
||||
我写好了代码,然后经过一晚的鼓捣把它部署在 Aure 上的 Ubuntu 虚拟机上。Docker 和 docker-compose 工具使得部署和更新过程非常快。
|
||||
|
||||
### 还记得链接指令(link)吗?
|
||||
|
||||
如果你已经阅读过 [Hands-on Docker tutorial][1],那么你应该已经可以使用命令行链接 Docker 容器。通过命令行将 Node.js 的计数器链接到 Redis 服务器,其命令可能如下所示:
|
||||
|
||||
```
|
||||
$ docker run -d -P --name redis1
|
||||
$ docker run -d hit_counter -p 3000:3000 --link redis1:redis
|
||||
```
|
||||
|
||||
现在假设你的应用程序分为三层:
|
||||
|
||||
- Web 前端
|
||||
- 处理长时间运行任务的批处理层
|
||||
- Redis 或者 mongo 数据库
|
||||
|
||||
通过`--link`的显式链接只是管理几个容器是可以的,但是可能会因为我们向应用程序添加更多层或容器而失控。
|
||||
|
||||
### 加入 docker-compose
|
||||
|
||||

|
||||
|
||||
*Docker Compose logo*
|
||||
|
||||
docker-compose 工具是标准 Docker 工具箱的一部分,也可以单独下载。 它提供了一组丰富的功能,通过纯文本 YAML 文件配置所有应用程序的部件。
|
||||
|
||||
上面的例子看起来像这样:
|
||||
|
||||
```
|
||||
version: "2.0"
|
||||
services:
|
||||
redis1:
|
||||
image: redis
|
||||
hit_counter:
|
||||
build: ./hit_counter
|
||||
ports:
|
||||
- 3000:3000
|
||||
```
|
||||
|
||||
从 Docker 1.10 开始,我们可以利用网络覆盖(network overlays)来帮助我们在多个主机上进行扩展。 在此之前,链接仅能工作在单个主机上。 `docker-compose scale` 命令可以用来在需要时带来更多的计算能力。
|
||||
|
||||
> 查看 docker.com 上的 [docker-compose][2] 参考
|
||||
|
||||
### 真实工作示例:Raspberry PI 库存警示
|
||||
|
||||

|
||||
|
||||
*新的 Raspberry PI Zero v1.3 图片,由 Pimoroni 提供*
|
||||
|
||||
Raspberry PI Zero 嗡嗡作响 - 它是一个极小的微型计算机,具有 1GHz CPU 和 512MB RAM,可以运行完整的Linux、Docker、Node.js、Ruby 和其他许多流行的开源工具。 PI Zero 最好的优点之一就是它成本只有 5 美元。 这也意味着它销售的速度非常之快。
|
||||
|
||||
*如果你想在 PI 上尝试 Docker 和 Swarm,请查看下面的教程:[Docker Swarm on the PI Zero][3]*
|
||||
|
||||
### 原始网站:whereismypizero.com
|
||||
|
||||
我发现一个网页,它使用屏幕抓取以找出 4-5 个最受欢迎的折扣网店是否有库存。
|
||||
|
||||
- 网站包含静态 HTML 网页
|
||||
- 向每个折扣网店发出一个 XMLHttpRequest 访问 /public/api/
|
||||
- 服务器向每个网店发出 HTTP 请求并执行抓屏
|
||||
|
||||
每一次对 /public/api/ 的调用,其执行花 3 秒钟,而使用 Apache Bench(ab),我每秒只能完成 0.25 个请求。
|
||||
|
||||
### 重新发明轮子
|
||||
|
||||
零售商似乎并不介意 whereismypizero.com 抓取他们的网站的商品库存信息,所以我开始从头写一个类似的工具。 我尝试通过缓存和解耦 web 层来处理更多的抓取请求。 Redis 是执行这项工作的完美工具。 它允许我设置一个自动过期的键/值对(即一个简单的缓存),还可以通过 pub/sub 在 Node.js 进程之间传输消息。
|
||||
|
||||
> 复刻或者追踪放在 github 上的代码: [alexellis/pi_zero_stock][4]
|
||||
|
||||
如果之前使用过 Node.js,你肯定知道它是单线程的,并且任何 CPU 密集型任务,如解析 HTML 或 JSON 都可能导致速度放缓。一种缓解这种情况的方法是使用一个工作进程和 Redis 消息通道作为它和 web 层之间的连接组织。
|
||||
|
||||
- Web 层
|
||||
- 使用 200 代表缓冲命中(该商店的 Redis 键存在)
|
||||
- 使用 202 代表高速缓存未命中(该商店的 Redis 键不存在,因此发出消息)
|
||||
- 因为我们只是读一个 Redis 键,响应时间非常快。
|
||||
- 库存抓取器
|
||||
- 执行 HTTP 请求
|
||||
- 用于在不同类型的网店上抓屏
|
||||
- 更新 Redis 键的缓存失效时间为 60 秒
|
||||
- 另外,锁定一个 Redis 键,以防止对网店过多的 HTTP 请求。
|
||||
|
||||
```
|
||||
version: "2.0"
|
||||
services:
|
||||
web:
|
||||
build: ./web/
|
||||
ports:
|
||||
- "3000:3000"
|
||||
stock_fetch:
|
||||
build: ./stock_fetch/
|
||||
redis:
|
||||
image: redis
|
||||
```
|
||||
|
||||
*来自示例的 docker-compose.yml 文件*
|
||||
|
||||
一旦本地正常工作,再向 Azure 的 Ubuntu 16.04 镜像云部署就轻车熟路,只花了不到 5 分钟。 我登录、克隆仓库并键入`docker compose up -d`, 这就是所有的工作 - 快速实现整个系统的原型不会比这几个步骤更多。 任何人(包括 whereismypizero.com 的所有者)只需两行命令就可以部署新解决方案:
|
||||
|
||||
```
|
||||
$ git clone https://github.com/alexellis/pi_zero_stock
|
||||
$ docker-compose up -d
|
||||
```
|
||||
|
||||
更新网站很容易,只需要一个`git pull`命令,然后执行`docker-compose up -d`命令,该命令需要带上`--build`参数。
|
||||
|
||||
如果你仍然手动链接你的 Docker 容器,请自己或使用如下我的代码尝试 Docker Compose:
|
||||
|
||||
> 复刻或者追踪在 github 上的代码: [alexellis/pi_zero_stock][5]
|
||||
|
||||
### 一睹测试网站芳容
|
||||
|
||||
目前测试网站使用 docker-compose 部署:[stockalert.alexellis.io][6]
|
||||
|
||||

|
||||
|
||||
*预览于 2016 年 5 月 16 日*
|
||||
|
||||
----------
|
||||
via: http://blog.alexellis.io/rapid-prototype-docker-compose/
|
||||
|
||||
作者:[Alex Ellis][a]
|
||||
译者:[firstadream](https://github.com/firstadream)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创翻译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: http://blog.alexellis.io/author/alex/
|
||||
[1]: http://blog.alexellis.io/handsondocker
|
||||
[2]: https://docs.docker.com/compose/compose-file/
|
||||
[3]: http://blog.alexellis.io/dockerswarm-pizero/
|
||||
[4]: https://github.com/alexellis/pi_zero_stock
|
||||
[5]: https://github.com/alexellis/pi_zero_stock
|
||||
[6]: http://stockalert.alexellis.io/
|
||||
|
280
published/201611/20160513 aria2 (Command Line Downloader) command examples.md
Executable file
280
published/201611/20160513 aria2 (Command Line Downloader) command examples.md
Executable file
@ -0,0 +1,280 @@
|
||||
aria2 (命令行下载器)实例
|
||||
============
|
||||
|
||||
[aria2][4] 是一个自由、开源、轻量级多协议和多源的命令行下载工具。它支持 HTTP/HTTPS、FTP、SFTP、 BitTorrent 和 Metalink 协议。aria2 可以通过内建的 JSON-RPC 和 XML-RPC 接口来操纵。aria2 下载文件的时候,自动验证数据块。它可以通过多个来源或者多个协议下载一个文件,并且会尝试利用你的最大下载带宽。默认情况下,所有的 Linux 发行版都包括 aria2,所以我们可以从官方库中很容易的安装。一些 GUI 下载管理器例如 [uget][3] 使用 aria2 作为插件来提高下载速度。
|
||||
|
||||
### Aria2 特性
|
||||
|
||||
* 支持 HTTP/HTTPS GET
|
||||
* 支持 HTTP 代理
|
||||
* 支持 HTTP BASIC 认证
|
||||
* 支持 HTTP 代理认证
|
||||
* 支持 FTP (主动、被动模式)
|
||||
* 通过 HTTP 代理的 FTP(GET 命令行或者隧道)
|
||||
* 分段下载
|
||||
* 支持 Cookie
|
||||
* 可以作为守护进程运行。
|
||||
* 支持使用 fast 扩展的 BitTorrent 协议
|
||||
* 支持在多文件 torrent 中选择文件
|
||||
* 支持 Metalink 3.0 版本(HTTP/FTP/BitTorrent)
|
||||
* 限制下载、上传速度
|
||||
|
||||
### 1) Linux 下安装 aria2
|
||||
|
||||
我们可以很容易的在所有的 Linux 发行版上安装 aria2 命令行下载器,例如 Debian、 Ubuntu、 Mint、 RHEL、 CentOS、 Fedora、 suse、 openSUSE、 Arch Linux、 Manjaro、 Mageia 等等……只需要输入下面的命令安装即可。对于 CentOS、 RHEL 系统,我们需要开启 [uget][2] 或者 [RPMForge][1] 库的支持。
|
||||
|
||||
```
|
||||
[对于 Debian、 Ubuntu 和 Mint]
|
||||
$ sudo apt-get install aria2
|
||||
|
||||
[对于 CentOS、 RHEL、 Fedora 21 和更早些的操作系统]
|
||||
# yum install aria2
|
||||
|
||||
[Fedora 22 和 之后的系统]
|
||||
# dnf install aria2
|
||||
|
||||
[对于 suse 和 openSUSE]
|
||||
# zypper install wget
|
||||
|
||||
[Mageia]
|
||||
# urpmi aria2
|
||||
|
||||
[对于 Debian、 Ubuntu 和 Mint]
|
||||
$ sudo pacman -S aria2
|
||||
|
||||
```
|
||||
|
||||
### 2) 下载单个文件
|
||||
|
||||
下面的命令将会从指定的 URL 中下载一个文件,并且保存在当前目录,在下载文件的过程中,我们可以看到文件的(日期、时间、下载速度和下载进度)。
|
||||
|
||||
```
|
||||
# aria2c https://download.owncloud.org/community/owncloud-9.0.0.tar.bz2
|
||||
[#986c80 19MiB/21MiB(90%) CN:1 DL:3.0MiB]
|
||||
03/22 09:49:13 [NOTICE] Download complete: /opt/owncloud-9.0.0.tar.bz2
|
||||
|
||||
Download Results:
|
||||
gid |stat|avg speed |path/URI
|
||||
======+====+===========+=======================================================
|
||||
986c80|OK | 3.0MiB/s|/opt/owncloud-9.0.0.tar.bz2
|
||||
|
||||
Status Legend:
|
||||
(OK):download completed.
|
||||
|
||||
```
|
||||
|
||||
### 3) 使用不同的名字保存文件
|
||||
|
||||
在初始化下载的时候,我们可以使用 `-o`(小写)选项在保存文件的时候使用不同的名字。这儿我们将要使用 owncloud.zip 文件名来保存文件。
|
||||
|
||||
```
|
||||
# aria2c -o owncloud.zip https://download.owncloud.org/community/owncloud-9.0.0.tar.bz2
|
||||
[#d31304 16MiB/21MiB(74%) CN:1 DL:6.2MiB]
|
||||
03/22 09:51:02 [NOTICE] Download complete: /opt/owncloud.zip
|
||||
|
||||
Download Results:
|
||||
gid |stat|avg speed |path/URI
|
||||
======+====+===========+=======================================================
|
||||
d31304|OK | 7.3MiB/s|/opt/owncloud.zip
|
||||
|
||||
Status Legend:
|
||||
(OK):download completed.
|
||||
|
||||
```
|
||||
|
||||
### 4) 下载速度限制
|
||||
|
||||
默认情况下,aria2 会利用全部带宽来下载文件,在文件下载完成之前,我们在服务器就什么也做不了(这将会影响其他服务访问带宽)。所以在下载大文件时最好使用 `–max-download-limit` 选项来避免进一步的问题。
|
||||
|
||||
```
|
||||
# aria2c --max-download-limit=500k https://download.owncloud.org/community/owncloud-9.0.0.tar.bz2
|
||||
[#7f9fbf 21MiB/21MiB(99%) CN:1 DL:466KiB]
|
||||
03/22 09:54:51 [NOTICE] Download complete: /opt/owncloud-9.0.0.tar.bz2
|
||||
|
||||
Download Results:
|
||||
gid |stat|avg speed |path/URI
|
||||
======+====+===========+=======================================================
|
||||
7f9fbf|OK | 462KiB/s|/opt/owncloud-9.0.0.tar.bz2
|
||||
|
||||
Status Legend:
|
||||
(OK):download completed.
|
||||
|
||||
```
|
||||
|
||||
### 5) 下载多个文件
|
||||
|
||||
下面的命令将会从指定位置下载超过一个的文件并保存到当前目录,在下载文件的过程中,我们可以看到文件的(日期、时间、下载速度和下载进度)。
|
||||
|
||||
```
|
||||
# aria2c -Z https://download.owncloud.org/community/owncloud-9.0.0.tar.bz2 ftp://ftp.gnu.org/gnu/wget/wget-1.17.tar.gz
|
||||
[DL:1.7MiB][#53533c 272KiB/21MiB(1%)][#b52bb1 768KiB/3.6MiB(20%)]
|
||||
03/22 10:25:54 [NOTICE] Download complete: /opt/wget-1.17.tar.gz
|
||||
[#53533c 18MiB/21MiB(86%) CN:1 DL:3.2MiB]
|
||||
03/22 10:25:59 [NOTICE] Download complete: /opt/owncloud-9.0.0.tar.bz2
|
||||
|
||||
Download Results:
|
||||
gid |stat|avg speed |path/URI
|
||||
======+====+===========+=======================================================
|
||||
b52bb1|OK | 2.8MiB/s|/opt/wget-1.17.tar.gz
|
||||
53533c|OK | 3.4MiB/s|/opt/owncloud-9.0.0.tar.bz2
|
||||
|
||||
Status Legend:
|
||||
(OK):download completed.
|
||||
|
||||
```
|
||||
|
||||
### 6) 续传未完成的下载
|
||||
|
||||
当你遇到一些网络连接问题或者系统问题的时候,并将要下载一个大文件(例如: ISO 镜像文件),我建议你使用 `-c` 选项,它可以帮助我们从该状态续传未完成的下载,并且像往常一样完成。不然的话,当你再次下载,它将会初始化新的下载,并保存成一个不同的文件名(自动的在文件名后面添加 .1 )。注意:如果出现了任何中断,aria2 使用 .aria2 后缀保存(未完成的)文件。
|
||||
|
||||
```
|
||||
# aria2c -c https://download.owncloud.org/community/owncloud-9.0.0.tar.bz2
|
||||
[#db0b08 8.2MiB/21MiB(38%) CN:1 DL:3.1MiB ETA:4s]^C
|
||||
03/22 10:09:26 [NOTICE] Shutdown sequence commencing... Press Ctrl-C again for emergency shutdown.
|
||||
|
||||
03/22 10:09:26 [NOTICE] Download GID#db0b08bf55d5908d not complete: /opt/owncloud-9.0.0.tar.bz2
|
||||
|
||||
Download Results:
|
||||
gid |stat|avg speed |path/URI
|
||||
======+====+===========+=======================================================
|
||||
db0b08|INPR| 3.3MiB/s|/opt/owncloud-9.0.0.tar.bz2
|
||||
|
||||
Status Legend:
|
||||
(INPR):download in-progress.
|
||||
|
||||
如果重新启动传输,aria2 将会恢复下载。
|
||||
|
||||
# aria2c -c https://download.owncloud.org/community/owncloud-9.0.0.tar.bz2
|
||||
[#873d08 21MiB/21MiB(98%) CN:1 DL:2.7MiB]
|
||||
03/22 10:09:57 [NOTICE] Download complete: /opt/owncloud-9.0.0.tar.bz2
|
||||
|
||||
Download Results:
|
||||
gid |stat|avg speed |path/URI
|
||||
======+====+===========+=======================================================
|
||||
873d08|OK | 1.9MiB/s|/opt/owncloud-9.0.0.tar.bz2
|
||||
|
||||
Status Legend:
|
||||
(OK):download completed.
|
||||
|
||||
```
|
||||
|
||||
### 7) 从文件获取输入
|
||||
|
||||
就像 wget 可以从一个文件获取输入的 URL 列表来下载一样。我们需要创建一个文件,将每一个 URL 存储在单独的行中。ara2 命令行可以添加 `-i` 选项来执行此操作。
|
||||
|
||||
```
|
||||
# aria2c -i test-aria2.txt
|
||||
[DL:3.9MiB][#b97984 192KiB/21MiB(0%)][#673c8e 2.5MiB/3.6MiB(69%)]
|
||||
03/22 10:14:22 [NOTICE] Download complete: /opt/wget-1.17.tar.gz
|
||||
[#b97984 19MiB/21MiB(90%) CN:1 DL:2.5MiB]
|
||||
03/22 10:14:30 [NOTICE] Download complete: /opt/owncloud-9.0.0.tar.bz2
|
||||
|
||||
Download Results:
|
||||
gid |stat|avg speed |path/URI
|
||||
======+====+===========+=======================================================
|
||||
673c8e|OK | 4.3MiB/s|/opt/wget-1.17.tar.gz
|
||||
b97984|OK | 2.5MiB/s|/opt/owncloud-9.0.0.tar.bz2
|
||||
|
||||
Status Legend:
|
||||
(OK):download completed.
|
||||
|
||||
```
|
||||
|
||||
### 8) 每个主机使用两个连接来下载
|
||||
|
||||
默认情况,每次下载连接到一台服务器的最大数目,对于一条主机只能建立一条。我们可以通过 aria2 命令行添加 `-x2`(2 表示两个连接)来创建到每台主机的多个连接,以加快下载速度。
|
||||
|
||||
```
|
||||
# aria2c -x2 https://download.owncloud.org/community/owncloud-9.0.0.tar.bz2
|
||||
[#ddd4cd 18MiB/21MiB(83%) CN:1 DL:5.0MiB]
|
||||
03/22 10:16:27 [NOTICE] Download complete: /opt/owncloud-9.0.0.tar.bz2
|
||||
|
||||
Download Results:
|
||||
gid |stat|avg speed |path/URI
|
||||
======+====+===========+=======================================================
|
||||
ddd4cd|OK | 5.5MiB/s|/opt/owncloud-9.0.0.tar.bz2
|
||||
|
||||
Status Legend:
|
||||
(OK):download completed.
|
||||
|
||||
```
|
||||
|
||||
### 9) 下载 BitTorrent 种子文件
|
||||
|
||||
我们可以使用 aria2 命令行直接下载一个 BitTorrent 种子文件:
|
||||
|
||||
```
|
||||
# aria2c https://torcache.net/torrent/C86F4E743253E0EBF3090CCFFCC9B56FA38451A3.torrent?title=[kat.cr]irudhi.suttru.2015.official.teaser.full.hd.1080p.pathi.team.sr
|
||||
[#388321 0B/0B CN:1 DL:0B]
|
||||
03/22 20:06:14 [NOTICE] Download complete: /opt/[kat.cr]irudhi.suttru.2015.official.teaser.full.hd.1080p.pathi.team.sr.torrent
|
||||
|
||||
03/22 20:06:14 [ERROR] Exception caught
|
||||
Exception: [BtPostDownloadHandler.cc:98] errorCode=25 Could not parse BitTorrent metainfo
|
||||
|
||||
Download Results:
|
||||
gid |stat|avg speed |path/URI
|
||||
======+====+===========+=======================================================
|
||||
388321|OK | 11MiB/s|/opt/[kat.cr]irudhi.suttru.2015.official.teaser.full.hd.1080p.pathi.team.sr.torrent
|
||||
|
||||
Status Legend:
|
||||
(OK):download completed.
|
||||
|
||||
```
|
||||
|
||||
### 10) 下载 BitTorrent 磁力链接
|
||||
|
||||
使用 aria2 我们也可以通过 BitTorrent 磁力链接直接下载一个种子文件:
|
||||
|
||||
```
|
||||
# aria2c 'magnet:?xt=urn:btih:248D0A1CD08284299DE78D5C1ED359BB46717D8C'
|
||||
|
||||
```
|
||||
|
||||
### 11) 下载 BitTorrent Metalink 种子
|
||||
|
||||
我们也可以通过 aria2 命令行直接下载一个 Metalink 文件。
|
||||
|
||||
```
|
||||
# aria2c https://curl.haxx.se/metalink.cgi?curl=tar.bz2
|
||||
|
||||
```
|
||||
|
||||
### 12) 从密码保护的网站下载一个文件
|
||||
|
||||
或者,我们也可以从一个密码保护网站下载一个文件。下面的命令行将会从一个密码保护网站中下载文件。
|
||||
|
||||
```
|
||||
# aria2c --http-user=xxx --http-password=xxx https://download.owncloud.org/community/owncloud-9.0.0.tar.bz2
|
||||
|
||||
# aria2c --ftp-user=xxx --ftp-password=xxx ftp://ftp.gnu.org/gnu/wget/wget-1.17.tar.gz
|
||||
|
||||
```
|
||||
|
||||
### 13) 阅读更多关于 aria2
|
||||
|
||||
如果你希望了解了解更多选项 —— 它们同时适用于 wget,可以输入下面的命令行在你自己的终端获取详细信息:
|
||||
|
||||
```
|
||||
# man aria2c
|
||||
or
|
||||
# aria2c --help
|
||||
|
||||
```
|
||||
|
||||
谢谢欣赏 …)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: http://www.2daygeek.com/aria2-command-line-download-utility-tool/
|
||||
|
||||
作者:[MAGESH MARUTHAMUTHU][a]
|
||||
译者:[yangmingming](https://github.com/yangmingming)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:http://www.2daygeek.com/author/magesh/
|
||||
[1]:http://www.2daygeek.com/aria2-command-line-download-utility-tool/
|
||||
[2]:http://www.2daygeek.com/aria2-command-line-download-utility-tool/
|
||||
[3]:http://www.2daygeek.com/install-uget-download-manager-on-ubuntu-centos-debian-fedora-mint-rhel-opensuse/
|
||||
[4]:https://aria2.github.io/
|
@ -0,0 +1,191 @@
|
||||
Linux 与 Windows 的设备驱动模型比对:架构、API 和开发环境比较
|
||||
============================================================================================
|
||||
|
||||
> 名词缩写:
|
||||
> - API 应用程序接口(Application Program Interface )
|
||||
> - ABI 应用系统二进制接口(Application Binary Interface)
|
||||
|
||||
设备驱动是操作系统的一部分,它能够通过一些特定的编程接口便于硬件设备的使用,这样软件就可以控制并且运行那些设备了。因为每个驱动都对应不同的操作系统,所以你就需要不同的 Linux、Windows 或 Unix 设备驱动,以便能够在不同的计算机上使用你的设备。这就是为什么当你雇佣一个驱动开发者或者选择一个研发服务商提供者的时候,查看他们为各种操作系统平台开发驱动的经验是非常重要的。
|
||||
|
||||

|
||||
|
||||
驱动开发的第一步是理解每个操作系统处理它的驱动的不同方式、底层驱动模型、它使用的架构、以及可用的开发工具。例如,Linux 驱动程序模型就与 Windows 非常不同。虽然 Windows 提倡驱动程序开发和操作系统开发分别进行,并通过一组 ABI 调用来结合驱动程序和操作系统,但是 Linux 设备驱动程序开发不依赖任何稳定的 ABI 或 API,所以它的驱动代码并没有被纳入内核中。每一种模型都有自己的优点和缺点,但是如果你想为你的设备提供全面支持,那么重要的是要全面的了解它们。
|
||||
|
||||
在本文中,我们将比较 Windows 和 Linux 设备驱动程序,探索不同的架构,API,构建开发和分发,希望让您比较深入的理解如何开始为每一个操作系统编写设备驱动程序。
|
||||
|
||||
### 1. 设备驱动架构
|
||||
|
||||
Windows 设备驱动程序的体系结构和 Linux 中使用的不同,它们各有优缺点。差异主要受以下原因的影响:Windows 是闭源操作系统,而 Linux 是开源操作系统。比较 Linux 和 Windows 设备驱动程序架构将帮助我们理解 Windows 和 Linux 驱动程序背后的核心差异。
|
||||
|
||||
#### 1.1. Windows 驱动架构
|
||||
|
||||
虽然 Linux 内核分发时带着 Linux 驱动,而 Windows 内核则不包括设备驱动程序。与之不同的是,现代 Windows 设备驱动程序编写使用 Windows 驱动模型(WDM),这是一种完全支持即插即用和电源管理的模型,所以可以根据需要加载和卸载驱动程序。
|
||||
|
||||
处理来自应用的请求,是由 Windows 内核的中被称为 I/O 管理器的部分来完成的。I/O 管理器的作用是是转换这些请求到 I/O 请求数据包(IO Request Packets)(IRP),IRP 可以被用来在驱动层识别请求并且传输数据。
|
||||
|
||||
Windows 驱动模型 WDM 提供三种驱动, 它们形成了三个层:
|
||||
|
||||
- 过滤(Filter)驱动提供关于 IRP 的可选附加处理。
|
||||
- 功能(Function)驱动是实现接口和每个设备通信的主要驱动。
|
||||
- 总线(Bus)驱动服务不同的配适器和不同的总线控制器,来实现主机模式控制设备。
|
||||
|
||||
一个 IRP 通过这些层就像它们经过 I/O 管理器到达底层硬件那样。每个层能够独立的处理一个 IRP 并且把它们送回 I/O 管理器。在硬件底层中有硬件抽象层(HAL),它提供一个通用的接口到物理设备。
|
||||
|
||||
#### 1.2. Linux 驱动架构
|
||||
|
||||
相比于 Windows 设备驱动,Linux 设备驱动架构根本性的不同就是 Linux 没有一个标准的驱动模型也没有一个干净分隔的层。每一个设备驱动都被当做一个能够自动的从内核中加载和卸载的模块来实现。Linux 为即插即用设备和电源管理设备提供一些方式,以便那些驱动可以使用它们来正确地管理这些设备,但这并不是必须的。
|
||||
|
||||
模式输出那些它们提供的函数,并通过调用这些函数和传入随意定义的数据结构来沟通。请求来自文件系统或网络层的用户应用,并被转化为需要的数据结构。模块能够按层堆叠,在一个模块进行处理之后,另外一个再处理,有些模块提供了对一类设备的公共调用接口,例如 USB 设备。
|
||||
|
||||
Linux 设备驱动程序支持三种设备:
|
||||
|
||||
- 实现一个字节流接口的字符(Character)设备。
|
||||
- 用于存放文件系统和处理多字节数据块 IO 的块(Block)设备。
|
||||
- 用于通过网络传输数据包的网络(Network)接口。
|
||||
|
||||
Linux 也有一个硬件抽象层(HAL),它实际扮演了物理硬件的设备驱动接口。
|
||||
|
||||
### 2. 设备驱动 API
|
||||
|
||||
Linux 和 Windows 驱动 API 都属于事件驱动类型:只有当某些事件发生的时候,驱动代码才执行——当用户的应用程序希望从设备获取一些东西,或者当设备有某些请求需要告知操作系统。
|
||||
|
||||
#### 2.1. 初始化
|
||||
|
||||
在 Windows 上,驱动被表示为 `DriverObject` 结构,它在 `DriverEntry` 函数的执行过程中被初始化。这些入口点也注册一些回调函数,用来响应设备的添加和移除、驱动卸载和处理新进入的 IRP。当一个设备连接的时候,Windows 创建一个设备对象,这个设备对象在设备驱动后面处理所有应用请求。
|
||||
|
||||
相比于 Windows,Linux 设备驱动生命周期由内核模块的 `module_init` 和 `module_exit` 函数负责管理,它们分别用于模块的加载和卸载。它们负责注册模块来通过使用内核接口来处理设备的请求。这个模块需要创建一个设备文件(或者一个网络接口),为其所希望管理的设备指定一个数字识别号,并注册一些当用户与设备文件交互的时候所使用的回调函数。
|
||||
|
||||
#### 2.2. 命名和声明设备
|
||||
|
||||
##### 在 Windows 上注册设备
|
||||
|
||||
Windows 设备驱动在新连接设备时是由回调函数 `AddDevice` 通知的。它接下来就去创建一个设备对象(device object),用于识别该设备的特定的驱动实例。取决于驱动的类型,设备对象可以是物理设备对象(Physical Device Object)(PDO),功能设备对象(Function Device Object)(FDO),或者过滤设备对象(Filter Device Object )(FIDO)。设备对象能够堆叠,PDO 在底层。
|
||||
|
||||
设备对象在这个设备连接在计算机期间一直存在。`DeviceExtension` 结构能够被用于关联到一个设备对象的全局数据。
|
||||
|
||||
设备对象可以有如下形式的名字 `\Device\DeviceName`,这被系统用来识别和定位它们。应用可以使用 `CreateFile` API 函数来打开一个有上述名字的文件,获得一个可以用于和设备交互的句柄。
|
||||
|
||||
然而,通常只有 PDO 有自己的名字。未命名的设备能够通过设备级接口来访问。设备驱动注册一个或多个接口,以 128 位全局唯一标识符(GUID)来标示它们。用户应用能够使用已知的 GUID 来获取一个设备的句柄。
|
||||
|
||||
##### 在 Linux 上注册设备
|
||||
|
||||
在 Linux 平台上,用户应用通过文件系统入口访问设备,它通常位于 `/dev` 目录。在模块初始化的时候,它通过调用内核函数 `register_chrdev` 创建了所有需要的入口。应用可以发起 `open` 系统调用来获取一个文件描述符来与设备进行交互。这个调用后来被发送到回调函数,这个调用(以及将来对该返回的文件描述符的进一步调用,例如 `read`、`write` 或`close`)会被分配到由该模块安装到 `file_operations` 或者 `block_device_operations`这样的数据结构中的回调函数。
|
||||
|
||||
设备驱动模块负责分配和保持任何需要用于操作的数据结构。传送进文件系统回调函数的 `file` 结构有一个 `private_data` 字段,它可以被用来存放指向具体驱动数据的指针。块设备和网络接口 API 也提供类似的字段。
|
||||
|
||||
虽然应用使用文件系统的节点来定位设备,但是 Linux 在内部使用一个主设备号(major numbers)和次设备号(minor numbers)的概念来识别设备及其驱动。主设备号被用来识别设备驱动,而次设备号由驱动使用来识别它所管理的设备。驱动为了去管理一个或多个固定的主设备号,必须首先注册自己或者让系统来分配未使用的设备号给它。
|
||||
|
||||
目前,Linux 为主次设备对(major-minor pairs)使用一个 32 位的值,其中 12 位分配主设备号,并允许多达 4096 个不同的设备。主次设备对对于字符设备和块设备是不同的,所以一个字符设备和一个块设备能使用相同的设备对而不导致冲突。网络接口是通过像 eth0 的符号名来识别,这些又是区别于主次设备的字符设备和块设备的。
|
||||
|
||||
#### 2.3. 交换数据
|
||||
|
||||
Linux 和 Windows 都支持在用户级应用程序和内核级驱动程序之间传输数据的三种方式:
|
||||
|
||||
- **缓冲型输入输出(Buffered Input-Output)** 它使用由内核管理的缓冲区。对于写操作,内核从用户空间缓冲区中拷贝数据到内核分配的缓冲区,并且把它传送到设备驱动中。读操作也一样,由内核将数据从内核缓冲区中拷贝到应用提供的缓冲区中。
|
||||
- **直接型输入输出(Direct Input-Output)** 它不使用拷贝功能。代替它的是,内核在物理内存中钉死一块用户分配的缓冲区以便它可以一直留在那里,以便在数据传输过程中不被交换出去。
|
||||
- **内存映射(Memory mapping)** 它也能够由内核管理,这样内核和用户空间应用就能够通过不同的地址访问同样的内存页。
|
||||
|
||||
##### **Windows 上的驱动程序 I/O 模式**
|
||||
|
||||
支持缓冲型 I/O 是 WDM 的内置功能。缓冲区能够被设备驱动通过在 IRP 结构中的 `AssociatedIrp.SystemBuffer` 字段访问。当需要和用户空间通讯的时候,驱动只需从这个缓冲区中进行读写操作。
|
||||
|
||||
Windows 上的直接 I/O 由内存描述符列表(memory descriptor lists)(MDL)介导。这种半透明的结构是通过在 IRP 中的 `MdlAddress` 字段来访问的。它们被用来定位由用户应用程序分配的缓冲区的物理地址,并在 I/O 请求期间钉死不动。
|
||||
|
||||
在 Windows 上进行数据传输的第三个选项称为 `METHOD_NEITHER`。 在这种情况下,内核需要传送用户空间的输入输出缓冲区的虚拟地址给驱动,而不需要确定它们有效或者保证它们映射到一个可以由设备驱动访问的物理内存地址。设备驱动负责处理这些数据传输的细节。
|
||||
|
||||
##### **Linux 上的驱动程序 I/O 模式**
|
||||
|
||||
Linux 提供许多函数例如,`clear_user`、`copy_to_user`、`strncpy_from_user` 和一些其它的用来在内核和用户内存之间进行缓冲区数据传输的函数。这些函数保证了指向数据缓存区指针的有效,并且通过在内存区域之间安全地拷贝数据缓冲区来处理数据传输的所有细节。
|
||||
|
||||
然而,块设备的驱动对已知大小的整个数据块进行操作,它可以在内核和用户地址区域之间被快速移动而不需要拷贝它们。这种情况是由 Linux 内核来自动处理所有的块设备驱动。块请求队列处理传送数据块而不用多余的拷贝,而 Linux 系统调用接口来转换文件系统请求到块请求中。
|
||||
|
||||
最终,设备驱动能够从内核地址区域分配一些存储页面(不可交换的)并且使用 `remap_pfn_range` 函数来直接映射这些页面到用户进程的地址空间。然后应用能获取这些缓冲区的虚拟地址并且使用它来和设备驱动交流。
|
||||
|
||||
### 3. 设备驱动开发环境
|
||||
|
||||
#### 3.1. 设备驱动框架
|
||||
|
||||
##### Windows 驱动程序工具包
|
||||
|
||||
Windows 是一个闭源操作系统。Microsoft 提供 Windows 驱动程序工具包以方便非 Microsoft 供应商开发 Windows 设备驱动。工具包中包含开发、调试、检验和打包 Windows 设备驱动等所需的所有内容。
|
||||
|
||||
Windows 驱动模型(Windows Driver Model)(WDM)为设备驱动定义了一个干净的接口框架。Windows 保持这些接口的源代码和二进制的兼容性。编译好的 WDM 驱动通常是前向兼容性:也就是说,一个较旧的驱动能够在没有重新编译的情况下在较新的系统上运行,但是它当然不能够访问系统提供的新功能。但是,驱动不保证后向兼容性。
|
||||
|
||||
##### **Linux 源代码**
|
||||
|
||||
和 Windows 相对比,Linux 是一个开源操作系统,因此 Linux 的整个源代码是用于驱动开发的 SDK。没有驱动设备的正式框架,但是 Linux 内核包含许多提供了如驱动注册这样的通用服务的子系统。这些子系统的接口在内核头文件中描述。
|
||||
|
||||
尽管 Linux 有定义接口,但这些接口在设计上并不稳定。Linux 不提供有关前向和后向兼容的任何保证。设备驱动对于不同的内核版本需要重新编译。没有稳定性的保证可以让 Linux 内核进行快速开发,因为开发人员不必去支持旧的接口,并且能够使用最好的方法解决手头的这些问题。
|
||||
|
||||
当为 Linux 写树内(in-tree)(指当前 Linux 内核开发主干)驱动程序时,这种不断变化的环境不会造成任何问题,因为它们作为内核源代码的一部分,与内核本身同步更新。然而,闭源驱动必须单独开发,并且在树外(out-of-tree),必须维护它们以支持不同的内核版本。因此,Linux 鼓励设备驱动程序开发人员在树内维护他们的驱动。
|
||||
|
||||
#### 3.2. 为设备驱动构建系统
|
||||
|
||||
Windows 驱动程序工具包为 Microsoft Visual Studio 添加了驱动开发支持,并包括用来构建驱动程序代码的编译器。开发 Windows 设备驱动程序与在 IDE 中开发用户空间应用程序没有太大的区别。Microsoft 提供了一个企业 Windows 驱动程序工具包,提供了类似于 Linux 命令行的构建环境。
|
||||
|
||||
Linux 使用 Makefile 作为树内和树外系统设备驱动程序的构建系统。Linux 构建系统非常发达,通常是一个设备驱动程序只需要少数行就产生一个可工作的二进制代码。开发人员可以使用任何 [IDE][5],只要它可以处理 Linux 源代码库和运行 `make` ,他们也可以很容易地从终端手动编译驱动程序。
|
||||
|
||||
#### 3.3. 文档支持
|
||||
|
||||
Windows 对于驱动程序的开发有良好的文档支持。Windows 驱动程序工具包包括文档和示例驱动程序代码,通过 MSDN 可获得关于内核接口的大量信息,并存在大量的有关驱动程序开发和 Windows 底层的参考和指南。
|
||||
|
||||
Linux 文档不是描述性的,但整个 Linux 源代码可供驱动开发人员使用缓解了这一问题。源代码树中的 Documentation 目录描述了一些 Linux 的子系统,但是有[几本书][4]介绍了关于 Linux 设备驱动程序开发和 Linux 内核概览,它们更详细。
|
||||
|
||||
Linux 没有提供设备驱动程序的指定样本,但现有生产级驱动程序的源代码可用,可以用作开发新设备驱动程序的参考。
|
||||
|
||||
#### 3.4. 调试支持
|
||||
|
||||
Linux 和 Windows 都有可用于追踪调试驱动程序代码的日志机制。在 Windows 上将使用 `DbgPrint` 函数,而在 Linux 上使用的函数称为 `printk`。然而,并不是每个问题都可以通过只使用日志记录和源代码来解决。有时断点更有用,因为它们允许检查驱动代码的动态行为。交互式调试对于研究崩溃的原因也是必不可少的。
|
||||
|
||||
Windows 通过其内核级调试器 `WinDbg` 支持交互式调试。这需要通过一个串行端口连接两台机器:一台计算机运行被调试的内核,另一台运行调试器和控制被调试的操作系统。Windows 驱动程序工具包包括 Windows 内核的调试符号,因此 Windows 的数据结构将在调试器中部分可见。
|
||||
|
||||
Linux 还支持通过 `KDB` 和 `KGDB` 进行的交互式调试。调试支持可以内置到内核,并可在启动时启用。之后,可以直接通过物理键盘调试系统,或通过串行端口从另一台计算机连接到它。KDB 提供了一个简单的命令行界面,这是唯一的在同一台机器上来调试内核的方法。然而,KDB 缺乏源代码级调试支持。KGDB 通过串行端口提供了一个更复杂的接口。它允许使用像 GDB 这样标准的应用程序调试器来调试 Linux 内核,就像任何其它用户空间应用程序一样。
|
||||
|
||||
### 4. 设备驱动分发
|
||||
|
||||
##### 4.1. 安装设备驱动
|
||||
|
||||
在 Windows 上安装的驱动程序,是由被称为为 INF 的文本文件描述的,通常存储在 `C:\Windows\INF` 目录中。这些文件由驱动供应商提供,并且定义哪些设备由该驱动程序服务,哪里可以找到驱动程序的二进制文件,和驱动程序的版本等。
|
||||
|
||||
当一个新设备插入计算机时,Windows 通过查看已经安装的驱动程序并且选择适当的一个加载。当设备被移除的时候,驱动会自动卸载它。
|
||||
|
||||
在 Linux 上,一些驱动被构建到内核中并且保持永久的加载。非必要的驱动被构建为内核模块,它们通常是存储在 `/lib/modules/kernel-version` 目录中。这个目录还包含各种配置文件,如 `modules.dep`,用于描述内核模块之间的依赖关系。
|
||||
|
||||
虽然 Linux 内核可以在自身启动时加载一些模块,但通常模块加载由用户空间应用程序监督。例如,`init` 进程可能在系统初始化期间加载一些模块,`udev` 守护程序负责跟踪新插入的设备并为它们加载适当的模块。
|
||||
|
||||
#### 4.2. 更新设备驱动
|
||||
|
||||
Windows 为设备驱动程序提供了稳定的二进制接口,因此在某些情况下,无需与系统一起更新驱动程序二进制文件。任何必要的更新由 Windows Update 服务处理,它负责定位、下载和安装适用于系统的最新版本的驱动程序。
|
||||
|
||||
然而,Linux 不提供稳定的二进制接口,因此有必要在每次内核更新时重新编译和更新所有必需的设备驱动程序。显然,内置在内核中的设备驱动程序会自动更新,但是树外模块会产生轻微的问题。 维护最新的模块二进制文件的任务通常用 [DKMS][3] 来解决:这是一个当安装新的内核版本时自动重建所有注册的内核模块的服务。
|
||||
|
||||
#### 4.3. 安全方面的考虑
|
||||
|
||||
所有 Windows 设备驱动程序在 Windows 加载它们之前必须被数字签名。在开发期间可以使用自签名证书,但是分发给终端用户的驱动程序包必须使用 Microsoft 信任的有效证书进行签名。供应商可以从 Microsoft 授权的任何受信任的证书颁发机构获取软件出版商证书(Software Publisher Certificate)。然后,此证书由 Microsoft 交叉签名,并且生成的交叉证书用于在发行之前签署驱动程序包。
|
||||
|
||||
Linux 内核也能配置为在内核模块被加载前校验签名,并禁止不可信的内核模块。被内核所信任的公钥集在构建时是固定的,并且是完全可配置的。由内核执行的检查,这个检查严格性在构建时也是可配置的,范围从简单地为不可信模块发出警告,到拒绝加载有效性可疑的任何东西。
|
||||
|
||||
### 5. 结论
|
||||
|
||||
如上所示,Windows 和 Linux 设备驱动程序基础设施有一些共同点,例如调用 API 的方法,但更多的细节是相当不同的。最突出的差异源于 Windows 是由商业公司开发的封闭源操作系统这个事实。这使得 Windows 上有好的、文档化的、稳定的驱动 ABI 和正式框架,而在 Linux 上,更多的是源代码做了一个有益的补充。文档支持也在 Windows 环境中更加发达,因为 Microsoft 具有维护它所需的资源。
|
||||
|
||||
另一方面,Linux 不会使用框架来限制设备驱动程序开发人员,并且内核和产品级设备驱动程序的源代码可以在需要的时候有所帮助。缺乏接口稳定性也有其作用,因为它意味着最新的设备驱动程序总是使用最新的接口,内核本身承载较小的后向兼容性负担,这带来了更干净的代码。
|
||||
|
||||
了解这些差异以及每个系统的具体情况是为您的设备提供有效的驱动程序开发和支持的关键的第一步。我们希望这篇文章对 Windows 和 Linux 设备驱动程序开发做的对比,有助于您理解它们,并在设备驱动程序开发过程的研究中,将此作为一个伟大的起点。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: http://xmodulo.com/linux-vs-windows-device-driver-model.html
|
||||
|
||||
作者:[Dennis Turpitka][a]
|
||||
译者:[FrankXinqi &YangYang](https://github.com/FrankXinqi)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: http://xmodulo.com/author/dennis
|
||||
[1]: http://xmodulo.com/linux-vs-windows-device-driver-model.html?format=pdf
|
||||
[2]: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=PBHS9R4MB9RX4
|
||||
[3]: http://xmodulo.com/build-kernel-module-dkms-linux.html
|
||||
[4]: http://xmodulo.com/go/linux_device_driver_books
|
||||
[5]: https://linux.cn/article-7704-1.html
|
@ -0,0 +1,110 @@
|
||||
谁需要 GUI?—— Linux 终端生存之道
|
||||
=================================================
|
||||
|
||||
完全在 Linux 终端中生存并不容易,但这绝对是可行的。
|
||||
|
||||

|
||||
|
||||
### 处理常见功能的最佳 Linux shell 应用
|
||||
|
||||
你是否曾想像过完完全全在 Linux 终端里生存?没有图形桌面,没有现代的 GUI 软件,只有文本 —— 在 Linux shell 中,除了文本还是文本。这可能并不容易,但这是绝对可行的。[我最近尝试完全在 Linux shell 中生存30天][1]。下边提到的就是我最喜欢用的 shell 应用,可以用来处理大部分的常用电脑功能(网页浏览、文字处理等)。这些显然有些不足,因为纯文本操作实在是有些艰难。
|
||||
|
||||

|
||||
|
||||
### 在 Linux 终端里发邮件
|
||||
|
||||
要在终端里发邮件,选择有很多。很多人会推荐 mutt 和 notmuch,这两个软件都功能强大并且表现非凡,但是我却更喜欢 alpine。为何?不仅是因为它的高效性,还因为如果你习惯了像 Thunderbird 之类的 GUI 邮件客户端,你会发现 alpine 的界面与它们非常相似。
|
||||
|
||||

|
||||
|
||||
### 在 Linux 终端里浏览网页
|
||||
|
||||
我有一个词要告诉你:[w3m][5]。好吧,我承认这并不是一个真实的词。但 w3m 的确是我在 Linux 终端的 web 浏览器选择。它能够很好的呈现网页,并且它也足够强大,可以用来在像 Google+ 之类的网站上发布消息(尽管方法并不有趣)。 Lynx 可能是基于文本的 Web 浏览器的事实标准,但 w3m 还是我的最爱。
|
||||
|
||||

|
||||
|
||||
### 在 Linux 终端里编辑文本
|
||||
|
||||
对于编辑简单的文本文件,有一个应用是我最的最爱。不!不!不是 emacs,同样,也绝对不是 vim。对于编辑文本文件或者简要记下笔记,我喜欢使用 nano。对!就是 nano。它非常简单,易于学习并且使用方便。当然还有更多的软件具有更多功能,但 nano 的使用是最令人愉快的。
|
||||
|
||||

|
||||
|
||||
### 在 Linux 终端里处理文字
|
||||
|
||||
在一个只有文本的 shell 之中,“文本编辑器” 和 “文字处理程序” 实在没有什么大的区别。但是像我这样需要大量写作的,有一个专门用于长期写作的软件是非常必要的。而我最爱的就是 wordgrinder。它由足够的工具让我愉快工作——一个菜单驱动的界面(使用快捷键控制)并且支持 OpenDocument、HTML 或其他等多种文件格式。
|
||||
|
||||

|
||||
|
||||
### 在 Linux 终端里听音乐
|
||||
|
||||
当谈到在 shell 中播放音乐(比如 mp3,ogg 等),有一个软件绝对是卫冕之王:[cmus][7]。它支持所有你想得到的文件格式。它的使用超级简单,运行速度超级快,并且只使用系统少量的资源。如此清洁,如此流畅。这才是一个好的音乐播放器的样子。
|
||||
|
||||

|
||||
|
||||
### 在 Linux 终端里发送即时消息
|
||||
|
||||
当我在想如果可以在终端里发送即时消息会是什么样子的时候,我的思绪瞬间爆发了。你可能知道 Pidgin——一个支持多种协议的 IM 客户端,它也有一个终端版,叫做“[finch][8]”,你可以使用它来同时链接多个网络、同时和几个人聊天。而且,它的界面也和 Pidgin 极为相似。多么令人惊叹啊!想要使用 Google 环聊(Google Hangouts)就试试 [hangups][9]。它有一个非常漂亮的分页式界面,并且效果非常好。认真来说,除了一些可能需要的 emoji 表情和嵌入式图片外,在终端里发送即时消息真的是一个很好的体验。
|
||||
|
||||

|
||||
|
||||
### 在 Linux 终端里发布推文
|
||||
|
||||
这不是开玩笑!由于 [rainbowstream][10] 的存在,我们已经可以在终端里发布推文了。尽管我时不时遇到一些 bug,但整体上,它工作得很好。虽然没有网页版 Twitter 或官方移动客户端那么好用,但这是一个终端版的 Twitter,来试一试吧。尽管它的功能还未完善,但是用起来还是很酷,不是吗?
|
||||
|
||||

|
||||
|
||||
### 在 Linux 终端里看 Reddit 新闻
|
||||
|
||||
不管如何,在命令行中享受 Reddit 新闻时间真的感觉很棒。使用 rtv 真是一个相当愉快的体验。不管是阅读、评论,还是投票表决,它都可以。其体验和在网页版有一定相似。
|
||||
|
||||

|
||||
|
||||
### 在 Linux 终端里管理进程
|
||||
|
||||
可以使用 [htop][12]。与 top 相似,但更好用、更美观。有时候,我打开 htop 之后就让它一直运行。没有原因,就是喜欢!从某方面说,它就像将音乐可视化——当然,这里显示的是 RAM 和 CPU 的使用情况。
|
||||
|
||||

|
||||
|
||||
### 在 Linux 终端里管理文件
|
||||
|
||||
在一个纯文本终端里并不意味着你不能享受生活之美好。比方说一个出色的文件浏览和管理器。这方面,[Midnight Commander][13] 是很好用的。
|
||||
|
||||

|
||||
|
||||
### 在 Linux 终端里管理终端窗口
|
||||
|
||||
如果要在终端里工作很长时间,就需要一个多窗口终端了。它是这样一个软件 —— 可以将用户终端会话分割成一个自定义网格,从而可以同时使用和查看多个终端应用。对于 shell,它相当于一个平铺式窗口管理器。我最喜欢用的是 [tmux][14]。不过 [GNU Screen][15] 也很好用。学习怎么使用它们可能要花点时间,但一旦会用,就会很方便。
|
||||
|
||||

|
||||
|
||||
### 在 Linux 终端里进行讲稿演示
|
||||
|
||||
这类软件有 LibreOffice、Google slides、gasp 或者 PowerPoint。我在讲稿演示软件花费很多时间,很高兴有一个终端版的软件。它称做“[文本演示程序(tpp)][16]”。很显然,没有图片,只是一个使用简单标记语言将放在一起的幻灯片展示出来的简单程序。它不可能让你在其中插入猫的图片,但可以让你在终端里进行完整的演示。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: http://www.networkworld.com/article/3091139/linux/who-needs-a-gui-how-to-live-in-a-linux-terminal.html#slide1
|
||||
|
||||
作者:[Bryan Lunduke][a]
|
||||
译者:[GHLandy](https://github.com/GHLandy)
|
||||
校对:[jasminepeng](https://github.com/jasminepeng)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创翻译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: http://www.networkworld.com/author/Bryan-Lunduke/
|
||||
[1]: http://www.networkworld.com/article/3083268/linux/30-days-in-a-terminal-day-0-the-adventure-begins.html
|
||||
[2]: https://en.wikipedia.org/wiki/Mutt_(email_client)
|
||||
[3]: https://notmuchmail.org/
|
||||
[4]: https://en.wikipedia.org/wiki/Alpine_(email_client)
|
||||
[5]: https://en.wikipedia.org/wiki/W3m
|
||||
[6]: http://cowlark.com/wordgrinder/index.html
|
||||
[7]: https://en.wikipedia.org/wiki/Cmus
|
||||
[8]: https://developer.pidgin.im/wiki/Using%20Finch
|
||||
[9]: https://github.com/tdryer/hangups
|
||||
[10]: http://www.rainbowstream.org/
|
||||
[11]: https://github.com/michael-lazar/rtv
|
||||
[12]: http://hisham.hm/htop/
|
||||
[13]: https://en.wikipedia.org/wiki/Midnight_Commander
|
||||
[14]: https://tmux.github.io/
|
||||
[15]: https://en.wikipedia.org/wiki/GNU_Screen
|
||||
[16]: http://www.ngolde.de/tpp.html
|
@ -0,0 +1,58 @@
|
||||
为满足当今和未来 IT 需求,培训员工还是雇佣新人?
|
||||
================================================================
|
||||
|
||||

|
||||
|
||||
在数字化时代,由于 IT 工具不断更新,技术公司紧随其后,对 IT 技能的需求也不断变化。对于企业来说,寻找和雇佣那些拥有令人垂涎能力的创新人才,是非常不容易的。同时,培训内部员工来使他们接受新的技能和挑战,需要一定的时间,而时间要求常常是紧迫的。
|
||||
|
||||
[Sandy Hill][1] 对 IT 涉及到的多项技术都很熟悉。她作为 [Pegasystems][2] 项目的 IT 总监,负责多个 IT 团队,从应用的部署到数据中心的运营都要涉及。更重要的是,Pegasystems 开发帮助销售、市场、服务以及运营团队流水化操作,以及客户联络的应用。这意味着她需要掌握使用 IT 内部资源的最佳方法,面对公司客户遇到的 IT 挑战。
|
||||
|
||||

|
||||
|
||||
**TEP(企业家项目):这些年你是如何调整培训重心的?**
|
||||
|
||||
**Hill**:在过去的几年中,我们经历了爆炸式的发展,现在我们要实现更多的全球化进程。因此,培训目标是确保每个人都在同一起跑线上。
|
||||
|
||||
我们主要的关注点在培养员工使用新产品和工具上,这些新产品和工具能够推动创新,提高工作效率。例如,我们使用了之前没有的资产管理系统。因此我们需要为全部员工做培训,而不是雇佣那些已经知道该产品的人。当我们正在发展的时候,我们也试图保持紧张的预算和稳定的职员总数。所以,我们更愿意在内部培训而不是雇佣新人。
|
||||
|
||||
**TEP:说说培训方法吧,怎样帮助你的员工发展他们的技能?**
|
||||
|
||||
**Hill**:我要求每一位员工制定一个技术性的和非技术性的训练目标。这作为他们绩效评估的一部分。他们的技术性目标需要与他们的工作职能相符,非技术岗目标则随意,比如着重发展一项软技能,或是学一些专业领域之外的东西。我每年对职员进行一次评估,看看差距和不足之处,以使团队保持全面发展。
|
||||
|
||||
**TEP:你的训练计划能够在多大程度上减轻招聘工作量, 保持职员的稳定性?**
|
||||
|
||||
**Hill**:使我们的职员保持学习新技术的兴趣,可以让他们不断提高技能。让职员知道我们重视他们并且让他们在擅长的领域成长和发展,以此激励他们。
|
||||
|
||||
**TEP:你们发现哪些培训是最有效的?**
|
||||
|
||||
**HILL**:我们使用几种不同的培训方法,认为效果很好。对新的或特殊的项目,我们会由供应商提供培训课程,作为项目的一部分。要是这个方法不能实现,我们将进行脱产培训。我们也会购买一些在线的培训课程。我也鼓励职员每年参加至少一次会议,以了解行业的动向。
|
||||
|
||||
**TEP:哪些技能需求,更适合雇佣新人而不是培训现有员工?**
|
||||
|
||||
**Hill**:这和项目有关。最近有一个项目,需要使用 OpenStack,而我们根本没有这方面的专家。所以我们与一家从事这一领域的咨询公司合作。我们利用他们的专业人员运行该项目,并现场培训我们的内部团队成员。让内部员工学习他们需要的技能,同时还要完成他们的日常工作,是一项艰巨的任务。
|
||||
|
||||
顾问帮助我们确定我们需要的员工人数。这样我们就可以对员工进行评估,看是否存在缺口。如果存在人员上的缺口,我们还需要额外的培训或是员工招聘。我们也确实雇佣了一些合同工。另一个选择是对一些全职员工进行为期六至八周的培训,但我们的项目模式不容许这么做。
|
||||
|
||||
**TEP:最近雇佣的员工,他们的那些技能特别能够吸引到你?**
|
||||
|
||||
**Hill**:在最近的招聘中,我更看重软技能。除了扎实的技术能力外,他们需要能够在团队中进行有效的沟通和工作,要有说服他人,谈判和解决冲突的能力。
|
||||
|
||||
IT 人常常独来独往,不擅社交。然而如今IT 与整个组织结合越来越紧密,为其他业务部门提供有用的更新和状态报告的能力至关重要,可展示 IT 部门存在的重要性。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://enterprisersproject.com/article/2016/6/training-vs-hiring-meet-it-needs-today-and-tomorrow
|
||||
|
||||
作者:[Paul Desmond][a]
|
||||
译者:[Cathon](https://github.com/Cathon)
|
||||
校对:[jasminepeng](https://github.com/jasminepeng)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://enterprisersproject.com/user/paul-desmond
|
||||
[1]: https://enterprisersproject.com/user/sandy-hill
|
||||
[2]: https://www.pega.com/pega-can?&utm_source=google&utm_medium=cpc&utm_campaign=900.US.Evaluate&utm_term=pegasystems&gloc=9009726&utm_content=smAXuLA4U|pcrid|102822102849|pkw|pegasystems|pmt|e|pdv|c|
|
||||
|
||||
|
||||
|
||||
|
@ -0,0 +1,140 @@
|
||||
轻轻几个点击,在 AWS 和 Azure 上搭建 Docker 数据中心
|
||||
===================================================
|
||||
|
||||
通过几个点击即可在 “AWS 快速起步”和“Azure 市场”上高效搭建产品级 Docker 数据中心。
|
||||
|
||||
通过 AWS 快速起步的 CloudFormation 模板和在 Azure 市场上的预编译模板来部署 Docker 数据中心使得比以往在公有云基础设施下的部署企业级的 CaaS Docker 环境更加容易。
|
||||
|
||||
Docker 数据中心 CaaS 平台为各种规模的企业的敏捷应用部署提供了容器和集群的编排和管理,使之更简单、安全和可伸缩。使用新为 Docker 数据中心预编译的云模板,开发者和 IT 运维人员可以无缝的把容器化的应用迁移到亚马逊 EC2 或者微软的 Azure 环境而无需修改任何代码。现在,企业可以快速实现更高的计算和运营效率,可以通过短短几步操作实现支持 Docker 的容器管理和编排。
|
||||
|
||||
### 什么是 Docker 数据中心?
|
||||
|
||||
Docker 数据中心包括了 Docker 通用控制面板(Docker Universal Control Plane)(UCP),Docker 可信注册库( Docker Trusted Registry)(UTR)和商用版 Docker 引擎(CS Docker Engine),并带有与客户的应用服务等级协议相匹配的商业支持服务。
|
||||
|
||||
- Docker 通用控制面板(UCP),一种企业级的集群管理方案,帮助客户通过单个管理面板管理整个集群
|
||||
- Docker 可信注册库(DTR), 一种镜像存储管理方案,帮助客户安全存储和管理 Docker 镜像
|
||||
- 商用版的 Docker 引擎
|
||||
|
||||

|
||||
|
||||
### 在 AWS 上快速布置 Docker 数据中心
|
||||
|
||||
秉承 Docker 与 AWS 最佳实践,参照 AWS 快速起步教程来,你可以在 AWS 云上快速部署 Docker 容器。Docker 数据中心快速起步基于模块化和可定制的 CloudFormation 模板,客户可以在其之上增加额外功能或者为自己的 Docker 部署修改模板。
|
||||
|
||||
- [AWS 的 Docker 数据中心应用说明](https://youtu.be/aUx7ZdFSkXU)
|
||||
|
||||
#### 架构
|
||||
|
||||

|
||||
|
||||
AWS Cloudformation 的安装过程始于创建 AWS 资源,这些 AWS 需要的资源包括:VPC、安全组、公有与私有子网、因特网网关、NAT 网关与 S3 bucket。
|
||||
|
||||
然后,AWS Cloudformation 启动第一个 UCP 控制器实例,紧接着,安装 Docker 引擎和 UCP 容器。它把第一个 UCP 控制器创建的根证书备份到 S3。一旦第一个 UCP 控制器成功运行,其他 UCP 控制器、UCP 集群节点和第一个 DTR 复制的进程就会被触发。和第一个 UCP 控制器节点类似,其他所有节点创建进程也都由商用版 Docker 引擎开始,然后安装并运行 UCP 和 DTR 容器以加入集群。两个弹性负载均衡器(ELB),一个分配给 UCP,另外一个为 DTR 服务,它们启动并自动完成配置来在两个可用区(AZ)之间提供弹性负载均衡。
|
||||
|
||||
除这些之外,如有需要,UCP 控制器和节点在 ASG 中启动并提供扩展功能。这种架构确保 UCP 和 DTR 两者都部署在两个 AZ 上以增强弹性与高可靠性。在公有或者私有 HostedZone 上,Route53 用来动态注册或者配置 UCP 和 DTR。
|
||||
|
||||

|
||||
|
||||
#### 快速起步模板的核心功能如下:
|
||||
|
||||
- 创建 VPC、不同 AZ 上的私有和公有子网、ELB、NAT 网关、因特网网关、自动伸缩组,它们全部基于 AWS 最佳实践
|
||||
- 为 DDC 创建一个 S3 bucket,其用于证书备份和 DTR 映像存储(DTR 需要额外配置)
|
||||
- 在客户的 VPC 范畴,跨多 AZ 部署 3 个 UCP 控制器
|
||||
- 创建预配置正常检测的 UCP ELB
|
||||
- 创建一个 DNS 记录并关联到 UCP ELB
|
||||
- 创建可伸缩的 UCP 节点集群
|
||||
- 在 VPC 范畴内,跨多 AZ 创建 3 个 DTR 副本
|
||||
- 创建一个预配置正常检测的 DTR
|
||||
- 创建一个 DNS 记录,并关联到 DTR ELB
|
||||
|
||||
- [下载 AWS 快速指南](https://s3.amazonaws.com/quickstart-reference/docker/latest/doc/docker-datacenter-on-the-aws-cloud.pdf)
|
||||
|
||||
|
||||
### 在 AWS 使用 Docker 数据中心
|
||||
|
||||
1. 登录 [Docker Store][1] 获取 [30 天免费试用][2]或者[联系销售][4]
|
||||
2. 确认之后,看到提示“Launch Stack”后,客户会被重定向到 AWS Cloudformation 入口
|
||||
3. 确认启动 Docker 的 AWS 区域
|
||||
4. 提供启动参数
|
||||
5. 确认并启动
|
||||
6. 启动完成之后,点击输出标签可以看到 UCP/DTR 的 URL、缺省用户名、密码和 S3 bucket 的名称
|
||||
|
||||
- [Docker 数据中心需要 2000 美刀信用担保](https://aws.amazon.com/mp/contactdocker/)
|
||||
|
||||
### 在 Azure 使用 Azure 市场的预编译模板部署
|
||||
|
||||
在 Azure 市场上,Docker 数据中心是一个预先编译的模板,客户可以在 Azure 横跨全球的数据中心即起即用。客户可以根据自己需求从 Azure 提供的各种 VM 中选择适合自己的 VM 部署 Docker 数据中心。
|
||||
|
||||
#### 架构
|
||||
|
||||

|
||||
|
||||
Azure 部署过程始于输入一些基本用户信息,如 ssh 登录的管理员用户名(系统级管理员)和资源组名称。你可以把资源组理解为一组有生命周期和部署边界的资源集合。你可以在这个链接了解更多关于资源组的信息: http://azure.microsoft.com/en-us/documentation/articles/resource-group-overview/ 。
|
||||
|
||||
下一步,输入集群详细信息,包括:UCP 控制器 VM 大小、控制器个数(缺省为 3 个)、UCP 节点 VM 大小、UCP 节点个数(缺省 1,最大值为 10)、DTR 节点 VM 大小、DTR 节点个数、虚拟网络名和地址(例如:10.0.0.1/19)。关于网络,客户可以配置 2 个子网:第一个子网分配给 UCP 控制器 ,第二个分配给 DTC 和 UCP 节点。
|
||||
|
||||
最后,点击 OK 完成部署。对于小集群,服务开通需要大约 15-19 分钟,大集群更久些。
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
#### 如何在 Azure 部署
|
||||
|
||||
1. 注册 [Docker 数据中心 30 天试用][5]许可或者[联系销售][6]
|
||||
2. [跳转到微软 Azure 市场的 Docker 数据中心][7]
|
||||
3. [查看部署文档][8]
|
||||
|
||||
|
||||
---
|
||||
|
||||
通过注册获取 Docker 数据中心许可证开始,然后你就能够通过 AWS 或者 Azure 模板搭建自己的数据中心。
|
||||
|
||||
- [获取 30 天试用许可证][9]
|
||||
- [通过视频理解 Docker 数据中心架构][10]
|
||||
- [观看演示视频][11]
|
||||
- [获取 AWS 提供的部署 Docker 数据中心的 75 美元红包奖励][12]
|
||||
|
||||
了解有关 Docker 的更多信息:
|
||||
|
||||
- 初识 Docker? 尝试一下 10 分钟[在线学习课程][20]
|
||||
- 分享镜像,自动构建,或用一个[免费的 Docker Hub 账号][21]尝试更多
|
||||
- 阅读 [Docker 1.12 发行说明][22]
|
||||
- 订阅 [Docker Weekly][23]
|
||||
- 报名参加即将到来的 [Docker Online Meetups][24]
|
||||
- 参加即将发生的 [Docker Meetups][25]
|
||||
- 观看 [DockerCon EU2015][26]视频
|
||||
- 开始为 [Docker][27] 贡献力量
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://blog.docker.com/2016/06/docker-datacenter-aws-azure-cloud/
|
||||
|
||||
作者:[Trisha McCanna][a]
|
||||
译者:[firstadream](https://github.com/firstadream)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://blog.docker.com/author/trisha/
|
||||
[1]: https://store.docker.com/login?next=%2Fbundles%2Fdocker-datacenter%2Fpurchase?plan=free-trial
|
||||
[2]: https://store.docker.com/login?next=%2Fbundles%2Fdocker-datacenter%2Fpurchase?plan=free-trial
|
||||
[4]: https://goto.docker.com/contact-us.html
|
||||
[5]: https://store.docker.com/login?next=%2Fbundles%2Fdocker-datacenter%2Fpurchase?plan=free-trial
|
||||
[6]: https://goto.docker.com/contact-us.html
|
||||
[7]: https://azure.microsoft.com/en-us/marketplace/partners/docker/dockerdatacenterdocker-datacenter/
|
||||
[8]: https://success.docker.com/Datacenter/Apply/Docker_Datacenter_on_Azure
|
||||
[9]: http://www.docker.com/trial
|
||||
[10]: https://www.youtube.com/playlist?list=PLkA60AVN3hh8tFH7xzI5Y-vP48wUiuXfH
|
||||
[11]: https://www.youtube.com/playlist?list=PLkA60AVN3hh8a8JaIOA5Q757KiqEjPKWr
|
||||
[12]: https://aws.amazon.com/quickstart/promo/
|
||||
[20]: https://docs.docker.com/engine/understanding-docker/
|
||||
[21]: https://hub.docker.com/
|
||||
[22]: https://docs.docker.com/release-notes/
|
||||
[23]: https://www.docker.com/subscribe_newsletter/
|
||||
[24]: http://www.meetup.com/Docker-Online-Meetup/
|
||||
[25]: https://www.docker.com/community/meetup-groups
|
||||
[26]: https://www.youtube.com/playlist?list=PLkA60AVN3hh87OoVra6MHf2L4UR9xwJkv
|
||||
[27]: https://docs.docker.com/contributing/contributing/
|
||||
|
@ -0,0 +1,143 @@
|
||||
2016 年 Linux 下五个最佳视频编辑软件
|
||||
=====================================================
|
||||
|
||||

|
||||
|
||||
概要: 在这篇文章中,Tiwo 讨论了 Linux 下最佳视频编辑器的优缺点和在基于 Ubuntu 的发行版中的安装方法。
|
||||
|
||||
在过去,我们已经在类似的文章中讨论了 [Linux 下最佳图像管理应用软件][1],[Linux 上四个最佳的现代开源代码编辑器][2]。今天,我们来看看 Linux 下的最佳视频编辑软件。
|
||||
|
||||
当谈及免费的视频编辑软件,Windows Movie Maker 和 iMovie 是大多数人经常推荐的。
|
||||
|
||||
不幸的是,它们在 GNU/Linux 下都是不可用的。但是你不必担心这个,因为我们已经为你收集了一系列最佳的视频编辑器。
|
||||
|
||||
### Linux下最佳的视频编辑应用程序
|
||||
|
||||
接下来,让我们来看看 Linux 下排名前五的最佳视频编辑软件:
|
||||
|
||||
#### 1. Kdenlive
|
||||
|
||||

|
||||
|
||||
[Kdenlive][3] 是一款来自于 KDE 的自由而开源的视频编辑软件,它提供双视频监视器、多轨时间轴、剪辑列表、可自定义的布局支持、基本效果和基本转换的功能。
|
||||
|
||||
它支持各种文件格式和各种摄像机和相机,包括低分辨率摄像机(Raw 和 AVI DV 编辑):mpeg2、mpeg4 和 h264 AVCHD(小型摄像机和摄像机);高分辨率摄像机文件,包括 HDV 和 AVCHD 摄像机;专业摄像机,包括 XDCAM-HD^TM 流、IMX^TM (D10)流、DVCAM(D10)、DVCAM、DVCPRO^TM 、DVCPRO50^TM 流和 DNxHD^TM 流等等。
|
||||
|
||||
你可以在命令行下运行下面的命令安装 :
|
||||
|
||||
```
|
||||
sudo apt-get install kdenlive
|
||||
```
|
||||
|
||||
或者,打开 Ubuntu 软件中心,然后搜索 Kdenlive。
|
||||
|
||||
#### 2. OpenShot
|
||||
|
||||

|
||||
|
||||
[OpenShot][5] 是我们这个 Linux 视频编辑软件列表中的第二选择。 OpenShot 可以帮助您创建支持过渡、效果、调整音频电平的电影,当然,它也支持大多数格式和编解码器。
|
||||
|
||||
您还可以将电影导出到 DVD,上传到 YouTube、Vimeo、Xbox 360 和许多其他常见的格式。 OpenShot 比 Kdenlive 更简单。 所以如果你需要一个简单界面的视频编辑器,OpenShot 会是一个不错的选择。
|
||||
|
||||
最新的版本是 2.0.7。您可以从终端窗口运行以下命令安装 OpenShot 视频编辑器:
|
||||
|
||||
```
|
||||
sudo apt-get install openshot
|
||||
```
|
||||
|
||||
它需要下载 25 MB,安装后需要 70 MB 硬盘空间。
|
||||
|
||||
#### 3. Flowblade Movie Editor
|
||||
|
||||

|
||||
|
||||
[Flowblade Movie Editor][6] 是一个用于 Linux 的多轨非线性视频编辑器。它是自由而开源的。 它配备了一个时尚而现代的用户界面。
|
||||
|
||||
它是用 Python 编写的,旨在提供一个快速、精确的功能。 Flowblade 致力于在 Linux 和其他自由平台上提供最好的体验。 所以现在没有 Windows 和 OS X 版本。
|
||||
|
||||
要在 Ubuntu 和其他基于 Ubuntu 的系统上安装 Flowblade,请使用以下命令:
|
||||
|
||||
```
|
||||
sudo apt-get install flowblade
|
||||
```
|
||||
|
||||
#### 4. Lightworks
|
||||
|
||||

|
||||
|
||||
如果你要寻找一个有更多功能的视频编辑软件,这会是答案。 [Lightworks][7] 是一个跨平台的专业的视频编辑器,在 Linux、Mac OS X 和 Windows 系统下都可用。
|
||||
|
||||
它是一个获奖的专业的[非线性编辑][8](NLE)软件,支持高达 4K 的分辨率以及标清和高清格式的视频。
|
||||
|
||||
该应用程序有两个版本:Lightworks 免费版和 Lightworks 专业版。不过免费版本不支持 Vimeo(H.264 / MPEG-4)和 YouTube(H.264 / MPEG-4) - 高达 2160p(4K UHD)、蓝光和 H.264 / MP4 导出选项,以及可配置的位速率设置,但是专业版本支持。
|
||||
|
||||
- Lightworks 免费版
|
||||
- Lightworks 专业版
|
||||
|
||||
专业版本有更多的功能,例如更高的分辨率支持,4K 和蓝光支持等。
|
||||
|
||||
##### 怎么安装Lightworks?
|
||||
|
||||
不同于其他的视频编辑器,安装 Lightwork 不像运行单个命令那么直接。别担心,这不会很复杂。
|
||||
|
||||
- 第1步 – 你可以从 [Lightworks 下载页面][9]下载安装包。这个安装包大约 79.5MB。*请注意:这里没有32 位 Linux 的支持。*
|
||||
- 第2步 – 一旦下载,你可以使用 [Gdebi 软件包安装器][10]来安装。Gdebi 会自动下载依赖关系 :
|
||||

|
||||
- 第3步 – 现在你可以从 Ubuntu 仪表板或您的 Linux 发行版菜单中打开它。
|
||||
- 第4步 – 当你第一次使用它时,需要一个账号。点击 “Not Registerd?” 按钮来注册。别担心,它是免费的。
|
||||
- 第5步 – 在你的账号通过验证后,就可以登录了。
|
||||
|
||||
现在,Lightworks 可以使用了。
|
||||
|
||||
需要 Lightworks 的视频教程? 在 [Lightworks 视频教程页][11]得到它们。
|
||||
|
||||
#### 5. Blender
|
||||
|
||||

|
||||
|
||||
|
||||
Blender 是一个专业的,工业级的开源、跨平台的视频编辑器。在 3D 作品的制作中,是非常受欢迎的。 Blender 已被用于几部好莱坞电影的制作,包括蜘蛛侠系列。
|
||||
|
||||
虽然最初是设计用于制作 3D 模型,但它也可以用于各种格式的视频编辑和输入能力。 该视频编辑器包括:
|
||||
|
||||
- 实时预览、亮度波形、色度矢量示波器和直方图显示
|
||||
- 音频混合、同步、擦除和波形可视化
|
||||
- 多达 32 个插槽用于添加视频、图像、音频、场景、面具和效果
|
||||
- 速度控制、调整图层、过渡、关键帧、过滤器等
|
||||
|
||||
最新的版本可以从 [Blender 下载页][12]下载.
|
||||
|
||||
### 哪一个是最好的视频编辑软件?
|
||||
|
||||
如果你需要一个简单的视频编辑器,OpenShot、Kdenlive 和 Flowblade 是一个不错的选择。这些软件是适合初学者的,并且带有标准规范的系统。
|
||||
|
||||
如果你有一个高性能的计算机,并且需要高级功能,你可以使用 Lightworks。如果你正在寻找更高级的功能, Blender 可以帮助你。
|
||||
|
||||
这就是我写的 5 个最佳的视频编辑软件,它们可以在 Ubuntu、Linux Mint、Elementary 和其他 Linux 发行版下使用。 请与我们分享您最喜欢的视频编辑器。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://itsfoss.com/best-video-editing-software-linux/
|
||||
|
||||
作者:[Tiwo Satriatama][a]
|
||||
译者:[DockerChen](https://github.com/DockerChen)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创翻译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://itsfoss.com/author/tiwo/
|
||||
[1]: https://linux.cn/article-7462-1.html
|
||||
[2]: https://linux.cn/article-7468-1.html
|
||||
[3]: https://kdenlive.org/
|
||||
[4]: https://itsfoss.com/tag/open-source/
|
||||
[5]: http://www.openshot.org/
|
||||
[6]: http://jliljebl.github.io/flowblade/
|
||||
[7]: https://www.lwks.com/
|
||||
[8]: https://en.wikipedia.org/wiki/Non-linear_editing_system
|
||||
[9]: https://www.lwks.com/index.php?option=com_lwks&view=download&Itemid=206
|
||||
[10]: https://itsfoss.com/gdebi-default-ubuntu-software-center/
|
||||
[11]: https://www.lwks.com/videotutorials
|
||||
[12]: https://www.blender.org/download/
|
||||
|
||||
|
||||
|
@ -0,0 +1,106 @@
|
||||
玩转 GitHub 的问题单(issue)
|
||||
==============================================
|
||||
|
||||

|
||||
|
||||
***图片来源:*** opensource.com
|
||||
|
||||
对于大多数开源项目来讲,问题追踪系统(Issue-tracking system)是至关重要的。虽然有非常多的开源工具提供了这样的功能,但是大量项目还是选择了 GitHub 自带的问题追踪器(Issue Tracker)。
|
||||
|
||||
它结构简单,可以让其他人可以非常轻松地参与进来,但这才仅仅是开始。
|
||||
|
||||
如果没有适当的处理,你的储存库(repository)会变得很庞大,挤满重复的问题单、模糊不明的特性需求单、含混的 bug 报告单。项目维护者会被大量工作压得喘不过气来,新的贡献者也搞不清楚项目当前的工作重点是什么。
|
||||
|
||||
接下来,我们一起研究下,如何玩转 GitHub 的问题单。
|
||||
|
||||
### 问题单就是用户的故事
|
||||
|
||||
我的团队曾经和开源专家 [Jono Bacon][1] 做过一次对话,他是 [社区艺术(The Art of Community)][2] 的作者、一位战略顾问、前 GitHub 社区总监。他告诉我们,高质量的问题单是项目成功的关键。有些人把问题单仅仅看作是一堆你不得不去处理的问题列表,但是如果这些问题单管理完善,进行了分类并打上标签,会令人意想不到的提升我们对代码和社区的了解程度,也让我们更清楚问题的关键点在哪里。
|
||||
|
||||
“在提交问题单时,用户不太会有耐心或者有兴趣把问题的细节描述清楚。在这种情况下,你应当努力花最短的时间,尽量多的获取有用的信息。”,Jono Bacon 说。
|
||||
|
||||
统一的问题单模板可以大大减轻项目维护者的负担,尤其是开源项目的维护者。我们发现,让用户讲故事的方法总是可以把问题描述的非常清楚。用户讲故事时需要说明“是谁,做了什么,为什么而做”,也就是:我是【何种用户】,为了【达到何种目的】,我要【做何种操作】。
|
||||
|
||||
实际操作起来,大概是这样的:
|
||||
|
||||
>我是一名**顾客**,我想**购买东西**,所以我想**创建个账户**。
|
||||
|
||||
我们建议,问题单的标题始终使用这样的用户故事形式。你可以设置[问题单模板][3]来保证一致性。
|
||||
|
||||

|
||||
|
||||
*问题单模板让特性需求单保持统一的形式*
|
||||
|
||||
这个做法的核心点在于,问题单要清晰的呈现给它涉及的每一个人:它要尽量简单的指明受众(或者说用户),操作(或者说任务),和输出(或者说目标)。不过,不需要过分拘泥于这个模板,只要能把故事里的是什么事情或者是什么原因说清楚,就达到目的了。
|
||||
|
||||
### 高质量的问题单
|
||||
|
||||
问题单的质量是参差不齐的,这一点任何一个开源软件的贡献者或维护者都能证实。在[《The Agile Samurai》][4]中概述过一个良好的问题单所应具备的素质。
|
||||
|
||||
好的问题单尽量满足如下条件:
|
||||
|
||||
- 客户价值所在
|
||||
- 避免使用术语或晦涩的文字,就算不是专家也能看懂
|
||||
- 可以切分,也就是说我们可以逐步解决问题
|
||||
- 尽量跟其他问题单没有瓜葛,依赖其它问题会降低处理的灵活性
|
||||
- 可以协商,也就说我们有好几种办法达到目标
|
||||
- 问题足够小,可以非常容易的评估出所需时间和资源
|
||||
- 可衡量,我们可以对结果进行测试
|
||||
|
||||
### 不满足上述条件的问题单呢? 要有约束
|
||||
|
||||
如果一个问题单很难衡量,或者很难在短时间内完成,你也一样有办法搞定它。有些人把这种办法叫做“约束”(constraints)。
|
||||
|
||||
例如,“这个产品要快”,这种问题单不符合故事模板,而且是没办法协商的。多快才是快呢?这种模糊的需求没有达到“好问题单”的标准,但是如果你进一步定义一下,例如“每个页面都需要在 0.5 秒内加载完”,那我们就能更轻松地解决它了。我们可以把“约束”看作是成功的标尺,或者要实现的里程碑。每个团队都应该定期的对“约束”进行测试。
|
||||
|
||||
### 问题单里面有什么?
|
||||
|
||||
敏捷方法中,用户故事里通常要包含验收指标或者标准。在 GitHub 里,建议大家使用 markdown 格式的清单来概括解决这个问题单需要完成的任务。优先级越高的问题单应当包含更多的细节。
|
||||
|
||||
比如说,你打算提交一个关于新版网站主页的问题单。那这个问题单的子任务列表可能就是这样的:
|
||||
|
||||

|
||||
|
||||
*使用 markdown 的清单把复杂问题拆分成多个部分*
|
||||
|
||||
在必要的情况下,你还可以链接到其他问题单,以进一步明确任务。(GitHub 里做这个挺方便的)
|
||||
|
||||
将特性定义的越细化,越容易跟踪进度、测试,最终能更高效的发布有价值的代码。
|
||||
|
||||
以问题单的形式收到到问题所在后,还可以用 API 更深入的了解软件的健康度。
|
||||
|
||||
“在统计问题单的类型和趋势时,GitHub API 可以发挥巨大作用”,Bacon 告诉我们,“如果再做些数据挖掘工作,你就能发现代码里的问题点、社区里的活跃成员,或者其他有用的信息。”
|
||||
|
||||
有些问题单管理工具提供的 API 可以提高额外信息,比如预估时间或者历史进度。
|
||||
|
||||
### 团队协同一致
|
||||
|
||||
团队决定使用某种问题单模板后,如何让所有人都照做?存储库里的 ReadMe.md 其实也可以是你们项目的 “How-to” 文档。这个文档应描述清楚这个项目是做什么的(最好是用可以搜索的语言),以及其他贡献者应当如何参与进来(比如提交需求单、bug 报告、建议,或者直接贡献代码)。
|
||||
|
||||

|
||||
|
||||
*在 ReadMe 文件里增加清晰的说明,供新协作者参考*
|
||||
|
||||
ReadMe 文件是提供“问题单指引”的完美场所。如果希望特性需求单遵循“用户讲故事”的格式,那就把格式写在 ReadMe 里。如果使用某种跟踪工具来管理待办事项,那就标记在 ReadMe 里,这样别人也能看到。
|
||||
|
||||
“问题单模板、合理的标签、提交问题单的指导文档、确保问题单被分类并及时回应,这些对于开源项目都至关重要”,Bacon 说。
|
||||
|
||||
记住一点:这不是为了完成工作而做的工作。这是让其他人更轻松的发现、了解、融入你的社区而设立的规则。
|
||||
|
||||
"关注社区的成长,不仅要关注参与开发者的的数量增长,也要关注那些在问题单上帮助我们的人,他们让问题单更加明确、保持更新,这是活跃沟通和高效解决问题的力量源泉",Bacon 说。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/life/16/7/how-take-your-projects-github-issues-good-great
|
||||
|
||||
作者:[Matt Butler][a]
|
||||
译者:[echoma](https://github.com/echoma)
|
||||
校对:[jasminepeng](https://github.com/jasminepeng)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创翻译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/mattzenhub
|
||||
[1]: http://www.jonobacon.org/
|
||||
[2]: http://www.artofcommunityonline.org/
|
||||
[3]: https://help.github.com/articles/creating-an-issue-template-for-your-repository/
|
||||
[4]: https://www.amazon.ca/Agile-Samurai-Masters-Deliver-Software/dp/1934356581
|
@ -0,0 +1,66 @@
|
||||
一个老奶奶的唠叨:当年我玩 Linux 时……
|
||||
=====================
|
||||
|
||||

|
||||
|
||||
在很久以前,那时还没有 Linux 系统。真的没有!之前也从未存在过。不像现在,Linux 系统随处可见。那时有各种流派的 Unix 系统、有苹果的操作系统、有微软的 Windows 操作系统。
|
||||
|
||||
比如说 Windows,它的很多东西都改变了,但是依然保持不变的东西的更多。尽管它已经增加了 20GB 以上的鬼知道是什么的东西,但是 Windows 还是大体保持不变(除了不能在 DOS 的提示下实际做些什么了)。嘿,谁还记得 Gorilla.bas 那个出现在 DOS 系统里的炸香蕉的游戏吗?多么美好的时光啊!不过互联网却不会忘记,你可以在 Kongregate.com 这个网站玩这个游戏的 Flash版本。
|
||||
|
||||
苹果系统也改变了,从一个鼓励你 hack 的友善系统变成了一个漂亮而密实的、根本不让你打开的小盒子,而且还限制了你使用的硬件接口。1998 年:软盘没了。2012 年:光驱没了。而 12 英寸的 MacBook 只有一个单一的 USB Type-C 接口,提供了电源、蓝牙、无线网卡、外部存储、视频输出和其它的一些配件的接口。而你要是想一次连接多个外设就不得不背着一堆转接器,这真是太令人抓狂了!然后就轮到耳机插孔了,没错,这唯一一个苹果世界里留着的非专有的标准硬件接口了,也注定要消失了。(LCTT 译注:还好,虽然最新的 IPhone 7 上没有耳机插孔了,但是新发布的 Macbook 上还有)
|
||||
|
||||
还有一大堆其它的操作系统,比如:Amiga、BeOS、OS/2 ,如果你愿意的话,你能找到几十个操作系统。我建议你去找找看,太容易找到了。Amiga、 BeOS 和 OS/2 这些系统都值得关注,因为它们有强大的功能,比如 32 位的多任务和高级图形处理能力。但是市场的影响击败了强大的系统性能,因此技术上并不出众的 Apple 和 Windows 操作系统统治了市场的主导地位,而那些曾经的系统也逐渐销声匿迹了。
|
||||
|
||||
然后 Linux 系统出现了,世界也因此改变了。
|
||||
|
||||
### 第一款电脑
|
||||
|
||||
我曾经使用过的第一款电脑是 Apple IIc ,大概在 1994年左右,而那个时候 Linux 系统刚出来 3 年。这是我从一个朋友那里借来的,用起来各方面都还不错,但是很不方便。所以我自己花了将近 500 美元买了一台二手的 Tandy 牌的电脑。这对于卖电脑的人来说是一件很伤心的事,因为新电脑要花费双倍的价钱。那个时候,电脑贬值的速度非常快。这个电脑当时看起来强劲得像是个怪物:一个英特尔 386SX 的 CPU,4MB的内存,一个 107MB 的硬盘,14 英寸的彩色 CRT 显示器,运行 MS-DOS 5 和 Windows 3.1 系统。
|
||||
|
||||
我曾无数次的拆开那个可怜的怪物,并且多次重新安装 Windows 和 DOS 系统。因为 Windows 桌面用的比较少,所以我的大部分工作都是在 DOS 下完成的。我喜欢玩血腥暴力的视频游戏,包括 Doom、Duke Nukem、Quake 和 Heretic。啊!那些美好的,让人心动的 8 位图像!
|
||||
|
||||
那个时候硬件的发展一直落后于软件,因此我经常升级硬件。现在我们能买到满足我们需求的任何配置的电脑。我已经好多年都没有再更新我的任何电脑硬件了。
|
||||
|
||||
### 《比特杂志(Computer bits)》
|
||||
|
||||
回到那些曾经辉煌的年代,电脑商店布满大街小巷,找到本地的一家网络服务提供商(ISP)也不用走遍整个街区。ISP 那个时候真的非比寻常,它们不是那种冷冰冰的令人讨论的超级大公司,而是像美国电信运营商和有线电视公司这样的好朋友。他们都非常友好,并且提供各种各样的像 BBS、文件下载、MUD (多玩家在线游戏)等的额外服务。
|
||||
|
||||
我花了很多的时间在电脑商店购买配件,但是很多时候我一个女人家去那里会让店里的员工感到吃惊,我真的很无语了,这怎么就会让一些人看不惯了。我现成已经是一位 58 岁的老家伙了,但是他们还是一样的看不惯我。我希望我这个女电脑迷在我死之前能被他们所接受。
|
||||
|
||||
那些商店的书架上摆满了《比特杂志(Computer bits)》。有关《比特杂志》的[历史刊物](https://web.archive.org/web/20020122193349/http://computerbits.com/)可以在互联网档案库(Internet Archive)中查到。《比特杂志》是当地一家免费报纸,有很多关于计算机方面的优秀的文章和大量的广告。可惜当时的广告没有网络版,因此大家不能再看到那些很有价值的关于计算机方面的详细信息了。你知道现在的广告商们有多么的抓狂吗?他们埋怨那些安装广告过滤器的人,致使科技新闻变成了伪装的广告。他们应该学习一下过去的广告模式,那时候的广告里有很多有价值的信息,大家都喜欢阅读。我从《比特杂志》和其它的电脑杂志的广告中学到了所有关于计算机硬件的知识。《电脑购买者杂志(Computer Shopper)》更是非常好的学习资料,其中有上百页的广告和很多高质量的文章。
|
||||
|
||||

|
||||
|
||||
《比特杂志》的出版人 Paul Harwood 开启了我的写作生涯。我的第一篇计算机专业性质的文章就是在《比特杂志》发表的。 Paul,仿佛你一直都在我的身旁,谢谢你。
|
||||
|
||||
在互联网档案库中,关于《比特杂志》的分类广告信息已经几乎查询不到了。分类广告模式曾经给出版商带来巨大的收入。免费的分类广告网站 Craigslist 在这个领域独占鳌头,同时也扼杀了像《比特杂志》这种以传统的报纸和出版为主的杂志行业。
|
||||
|
||||
其中有一些让我最难以忘怀的记忆就是一个 12 岁左右的吊儿郎当的小屁孩,他脸上挂满了对我这种光鲜亮丽的女人所做工作的不屑和不理解的表情,他在我钟爱的电脑店里走动,递给我一本《比特杂志》,当成给初学者的一本好书。我翻开杂志,指着其中一篇我写的关于 Linux 系统的文章给他看,他说“哦,我明白了”。他尴尬的脸变成了那种正常生理上都不可能呈现的颜色,然后很仓促地夹着尾巴溜走了。(不是的,我亲爱的、诚实的读者们,他不是真的只有 12 岁,而应该是 20 来岁。他现在应该比以前更成熟懂事一些了吧!)
|
||||
|
||||
### 发现 Linux
|
||||
|
||||
我第一次了解到 Linux 系统是在《比特杂志》上,大概在 1997 年左右。我一开始用的一些 Linux操作系统版本是 Red Hat 5 和 Mandrake Linux(曼德拉草)。 Mandrake 真是太棒了,它是第一款易安装型的 Linux 系统,并且还附带图形界面和声卡驱动,因此我马上就可以玩 Tux Racer 游戏了。不像那时候大多数的 Linux 迷们,因为我之前没接触过 Unix系统,所以我学习起来比较难。但是一切都还顺利吧,因为我学到的东西都很有用。相对于我在 Windows 中的体验,我在 Windows 中学习的大部分东西都是徒劳,最终只能放弃返回到 DOS 下。
|
||||
|
||||
玩转电脑真是充满了太多的乐趣,后来我转行成为计算机自由顾问,去帮助一些小型公司的 IT 部门把数据迁移到 Linux 服务器上,这让 Windows 系统或多或少的失去一些用武之地。通常情况下我们都是在背地里偷偷地做这些工作的,因为那段时期微软把 Linux 称为毒瘤,诬蔑 Linux 系统是一种共产主义,用来削弱和吞噬我们身体里的珍贵血液的阴谋。
|
||||
|
||||
### Linux 赢了
|
||||
|
||||
我持续做了很多年的顾问工作,也做其它一些相关的工作,比如:电脑硬件修理和升级、布线、系统和网络管理,还有运行包括 Apple、Windows、Linux 系统在内的混合网络。Apple 和 Windows 系统故意不兼容对方,因此这两个系统真的是最头疼,也最难整合到同一网络中。但是在 Linux 系统和其它开源软件中最有趣的一件事是总有一些人能够处理这些厂商之间的兼容性问题。
|
||||
|
||||
现在已经大不同了。在系统间的互操作方面一直存在一些兼容性问题,而且也没有桌面 Linux 系统的 1 级 OEM 厂商。我觉得这是因为微软和苹果公司在零售行业在大力垄断造成的。也许他们这样做反而帮了我们帮大忙,因为我们可以从 ZaReason 和 System76 这样独立的 Linux 系统开发商得到更好的服务和更高性能的系统。他们对 Linux 系统都很专业,也特别欢迎我们这样的用户。
|
||||
|
||||
Linux 除了在零售行业的桌面版系统占有一席之地以外,从嵌入式系统到超级计算机以及分布式计算系统等各个方面都占据着主要地位。开源技术掌握着软件行业的发展方向,所有的软件行业的前沿技术,比如容器、集群以及人工智能的发展都离不开开源技术的支持。从我的第一台老式的 386SX 电脑到现在,Linux 和开源技术都取得了巨大的进步。
|
||||
|
||||
如果没有 Linux 系统和开源,这一切都不可能发生。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/life/16/7/my-linux-story-carla-schroder
|
||||
|
||||
作者:[Carla Schroder][a]
|
||||
译者:[rusking](https://github.com/rusking)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/carlaschroder
|
@ -0,0 +1,69 @@
|
||||
怎样用 Tar 和 OpenSSL 给文件和目录加密及解密
|
||||
=========
|
||||
|
||||
当你有重要的敏感数据的时候,给你的文件和目录额外加一层保护是至关重要的,特别是当你需要通过网络与他人传输数据的时候。
|
||||
|
||||
由于这个原因,我在寻找一个可疑在 Linux 上加密及解密文件和目录的实用程序,幸运的是我找到了一个用 tar(Linux 的一个压缩打包工具)和 OpenSSL 来解决的方案。借助这两个工具,你真的可以毫不费力地创建和加密 tar 归档文件。
|
||||
|
||||
在这篇文章中,我们将了解如何使用 OpenSSL 创建和加密 tar 或 gz(gzip,另一种压缩文件)归档文件:
|
||||
|
||||
牢记使用 OpenSSL 的常规方式是:
|
||||
|
||||
```
|
||||
# openssl command command-options arguments
|
||||
```
|
||||
|
||||
### 在 Linux 中加密文件
|
||||
|
||||
要加密当前工作目录的内容(根据文件的大小,这可能需要一点时间):
|
||||
|
||||
```
|
||||
# tar -czf - * | openssl enc -e -aes256 -out secured.tar.gz
|
||||
```
|
||||
|
||||
上述命令的解释:
|
||||
|
||||
1. `enc` - openssl 命令使用加密进行编码
|
||||
2. `-e` – 用来加密输入文件的 `enc` 命令选项,这里是指前一个 tar 命令的输出
|
||||
3. `-aes256` – 加密用的算法
|
||||
4. `-out` – 用于指定输出文件名的 `enc` 命令选项,这里文件名是 `secured.tar.gz`
|
||||
|
||||
### 在 Linux 中解密文件
|
||||
|
||||
要解密上述 tar 归档内容,使用以下命令。
|
||||
|
||||
```
|
||||
# openssl enc -d -aes256 -in secured.tar.gz | tar xz -C test
|
||||
```
|
||||
|
||||
上述命令的解释:
|
||||
|
||||
1. `-d` – 用于解密文件
|
||||
2. `-C` – 提取内容到 `test` 子目录
|
||||
|
||||
下图展示了加解密过程,以及当你尝试执行以下操作时会发生什么:
|
||||
|
||||
1. 以传统方式提取 tar 包的内容
|
||||
2. 使用了错误的密码的时候
|
||||
3. 当你输入正确的密码的时候
|
||||
|
||||
[][1]
|
||||
|
||||
*在 Linux 中加密和解密 Tar 归档文件*
|
||||
|
||||
当你在本地网络或因特网工作的时候,你可以随时通过加密来保护你和他人共享的重要文本或文件,这有助于降低将其暴露给恶意攻击者的风险。
|
||||
|
||||
我们研究了一种使用 OpenSSL(一个 openssl 命令行工具)加密 tar 包的简单技术,你可以参考它的手册页(man page)来获取更多信息和有用的命令。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: http://www.tecmint.com/encrypt-decrypt-files-tar-openssl-linux/
|
||||
|
||||
作者:[Gabriel Cánepa][a]
|
||||
译者:[OneNewLife](https://github.com/OneNewLife)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: http://www.tecmint.com/author/gacanepa/
|
||||
[1]:http://www.tecmint.com/wp-content/uploads/2016/08/Encrypt-Decrypt-Tar-Archive-Files-in-Linux.png
|
@ -1,12 +1,13 @@
|
||||
# 如何在 Ubuntu 上使用 Grafana 监控 Docker
|
||||
如何在 Ubuntu 上使用 Grafana 监控 Docker
|
||||
=========
|
||||
|
||||
Grafana 是一个有着丰富指标的开源控制面板。在进行大型的测量数据的可视化时是非常有用的。根据不同的丰富指标,它提供了一个强大、优雅的方式来创建、浏览数据的方式。
|
||||
Grafana 是一个有着丰富指标的开源控制面板。在可视化大规模测量数据的时候是非常有用的。根据不同的指标数据,它提供了一个强大、优雅的来创建、分享和浏览数据的方式。
|
||||
|
||||
它提供了丰富多样、灵活的图形选项。此外,针对数据源,它支持许多不同的存储后端。每个数据源都有针对特定数据源公开的特性和功能定制的查询编辑器。下述数据源 Grafana 提供了正式的支持:Graphite, InfluxDB, OpenTSDB, Prometheus, Elasticsearch 和 Cloudwatch。
|
||||
它提供了丰富多样、灵活的图形选项。此外,针对数据源(Data Source),它支持许多不同的存储后端。每个数据源都有针对特定数据源的特性和功能所定制的查询编辑器。Grafana 提供了对下述数据源的正式支持:Graphite、InfluxDB、OpenTSDB、 Prometheus、Elasticsearch 和 Cloudwatch。
|
||||
|
||||
查询语言和每个数据源的能力显然是不同的,你可以将来自多个数据源的数据混合到一个单一的仪表盘上,但每个小组被绑定到属于一个特定组织的特点数据源。它支持验证登陆和基于角色的访问控制的实现。它是作为一个独立软件部署的,使用 Go 和 JavaScript 编写的。
|
||||
每个数据源的查询语言和能力显然是不同的,你可以将来自多个数据源的数据混合到一个单一的仪表盘上,但每个面板(Panel)被绑定到属于一个特定组织(Organization)的特定数据源上。它支持验证登录和基于角色的访问控制方案。它是作为一个独立软件部署,使用 Go 和 JavaScript 编写的。
|
||||
|
||||
在这篇文章,我将讲解如何在 Ubuntu 16.04 上安装 Grafana 并使用这个软件配置 Docker 监控
|
||||
在这篇文章,我将讲解如何在 Ubuntu 16.04 上安装 Grafana 并使用这个软件配置 Docker 监控。
|
||||
|
||||
### 先决条件
|
||||
|
||||
@ -14,7 +15,7 @@ Grafana 是一个有着丰富指标的开源控制面板。在进行大型的测
|
||||
|
||||
### 安装 Grafana
|
||||
|
||||
我们可以在 Docker 中构建我们的 Grafana。 这里有一个官方的 Grafana Docker 镜像.请运行下述命令来构建Grafana 容器。
|
||||
我们可以在 Docker 中构建我们的 Grafana。 有一个官方提供的 Grafana Docker 镜像。请运行下述命令来构建Grafana 容器。
|
||||
|
||||
```
|
||||
root@ubuntu:~# docker run -i -p 3000:3000 grafana/grafana
|
||||
@ -48,115 +49,66 @@ t=2016-07-27T15:20:20+0000 lvl=info msg="Starting plugin search" logger=plugins
|
||||
t=2016-07-27T15:20:20+0000 lvl=info msg="Server Listening" logger=server address=0.0.0.0:3000 protocol=http subUrl=
|
||||
```
|
||||
|
||||
我们可以通过运行此命令确认 Grafana 容器的工作状态 `docker ps -a` 或通过这个URL访问 `http://Docker IP:3000`
|
||||
我们可以通过运行此命令确认 Grafana 容器的工作状态 `docker ps -a` 或通过这个URL访问 `http://Docker IP:3000`。
|
||||
|
||||
所有的 Grafana 配置设置都使用环境变量定义,在使用容器技术时这个是非常有用的。Grafana 配置文件路径为 /etc/grafana/grafana.ini.
|
||||
所有的 Grafana 配置设置都使用环境变量定义,在使用容器技术时这个是非常有用的。Grafana 配置文件路径为 `/etc/grafana/grafana.ini`。
|
||||
|
||||
### 理解配置项
|
||||
|
||||
Grafana 有多个 ini 文件作为被指定的配置文件,或可以指定使用前面提到的环境变量。
|
||||
Grafana 可以在它的 ini 配置文件中指定几个配置选项,或可以使用前面提到的环境变量来指定。
|
||||
|
||||
#### 配置文件位置
|
||||
|
||||
通常配置文件路径:
|
||||
|
||||
- 默认配置文件路径 : $WORKING_DIR/conf/defaults.ini
|
||||
- 自定义配置文件路径 : $WORKING_DIR/conf/custom.ini
|
||||
- 默认配置文件路径 : `$WORKING_DIR/conf/defaults.ini`
|
||||
- 自定义配置文件路径 : `$WORKING_DIR/conf/custom.ini`
|
||||
|
||||
PS:当你使用 deb、rpm 或 docker 镜像安装 Grafana ,你的配置文件在 /etc/grafana/grafana.ini
|
||||
PS:当你使用 deb、rpm 或 docker 镜像安装 Grafana 时,你的配置文件在 `/etc/grafana/grafana.ini`。
|
||||
|
||||
#### 理解配置变量
|
||||
|
||||
现在我们看一些配置文件中的变量:
|
||||
|
||||
`instance_name` : 这是 Grafana 服务器实例的名字。默认值从 ${HOSTNAME} 获取,将会被环境变量 HOSTNAME替换,如果为空或不存在,Grafana 将会尝试使用系统调用来获取机器名。
|
||||
|
||||
`[paths]`
|
||||
|
||||
`data` : 这个是 Grafana 存储 sqlite3 数据库(如果使用),基于文件的 Sessions(如果使用),和其他数据的路径
|
||||
|
||||
`logs` : 这个是 Grafana 存储日志的路径
|
||||
|
||||
这些路径通常都是在 init.d 脚本或 systemd service文件通过命令行指定。
|
||||
|
||||
`[server]`
|
||||
|
||||
`http_addr` : 应用监听的 IP 地址,如果为空,则监听所有的IP。
|
||||
|
||||
`http_port` : 应用监听的端口,默认是 3000,你可以使用下面的命令在 80 端口重定向到 3000 端口。
|
||||
|
||||
```
|
||||
$iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 3000
|
||||
```
|
||||
|
||||
`root_url` : 这个 URL 用于从浏览器访问 Grafana 。
|
||||
|
||||
`cert_file` : 证书文件的路径(如果协议是 HTTPS)
|
||||
|
||||
`cert_key` : 证书密钥文件的路径(如果协议是 HTTPS)
|
||||
|
||||
`[database]`
|
||||
|
||||
Grafana 使用数据库来存储用户和仪表盘以及其他信息,默认配置为使用嵌入在 Grafana 主要的二进制文件中传的 SQLite3
|
||||
|
||||
`type`
|
||||
你可以根据你的需求选择 MySQL、Postgres、SQLite3。
|
||||
|
||||
`path`
|
||||
|
||||
它只在选择 SQLite3 数据库时被应用,这个是数据库将要被存储的路径。
|
||||
|
||||
`host`
|
||||
仅适用 MySQL 或者 Postgres。它包括 IP 地址或主机名以及端口。例如,Grafana 和 MySQL 运行在同一台主机上设置如: host = 127.0.0.1:3306
|
||||
|
||||
`name`
|
||||
Grafana 数据库的名称,把它设置为 Grafana 或其它名称。
|
||||
|
||||
`user`
|
||||
数据库用户(不适用于 SQLite3)
|
||||
|
||||
`password`
|
||||
数据库用户密码(不适用于 SQLite3)
|
||||
|
||||
`ssl_mode`
|
||||
对于Postgres,使用 disable,require,或 verify-full.对于 MySQL,使用 true,false,或 skip-verify
|
||||
|
||||
`ca_cert_path`
|
||||
|
||||
(只适用于MySQL)CA 证书文件路径,在多数 Linux 系统中,证书可以在 /etc/ssl/certs 找到
|
||||
|
||||
`client_key_path`
|
||||
(只适用于MySQL)客户端密钥的路径,只在服务端需要用户端验证时使用。
|
||||
|
||||
`client_cert_path`
|
||||
(只适用于MySQL)客户端证书的路径,只在服务端需要用户端验证时使用。
|
||||
|
||||
`server_cert_name`
|
||||
(只适用于MySQL) MySQL 服务端使用的证书的通用名称字段。如果 ssl_mode 设置为 skip-verify 时可以不设置
|
||||
|
||||
`[security]`
|
||||
|
||||
`admin_user` : 这个是 Grafana 默认的管理员用户的用户名,默认设置为 admin.
|
||||
|
||||
`admin_password` : 这个是 Grafana 默认的管理员用户的密码,在第一次运行时设置,默认为 admin
|
||||
|
||||
`login_remember_days` : 保持登陆/记住我 的持续天数
|
||||
|
||||
`secret_key` : 用于保持登陆/记住我的 cookies 的签名
|
||||
- `instance_name`:这是 Grafana 服务器实例的名字。默认值从 `${HOSTNAME}` 获取,其值是环境变量` HOSTNAME`,如果该变量为空或不存在,Grafana 将会尝试使用系统调用来获取机器名。
|
||||
- `[paths]`:这些路径通常都是在 init.d 脚本或 systemd service 文件中通过命令行指定。
|
||||
- `data`:这个是 Grafana 存储 sqlite3 数据库(如果使用)、基于文件的会话(如果使用),和其他数据的路径。
|
||||
- `logs`:这个是 Grafana 存储日志的路径。
|
||||
- `[server]`
|
||||
- `http_addr`:应用监听的 IP 地址,如果为空,则监听所有的接口。
|
||||
- `http_port`:应用监听的端口,默认是 3000,你可以使用下面的命令将你的 80 端口重定向到 3000 端口:`$iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 3000`
|
||||
- `root_url` : 这个 URL 用于从浏览器访问 Grafana 。
|
||||
- `cert_file` : 证书文件的路径(如果协议是 HTTPS)。
|
||||
- `cert_key` : 证书密钥文件的路径(如果协议是 HTTPS)。
|
||||
- `[database]`:Grafana 使用数据库来存储用户和仪表盘以及其他信息,默认配置为使用内嵌在 Grafana 主二进制文件中的 SQLite3。
|
||||
- `type`:你可以根据你的需求选择 MySQL、Postgres、SQLite3。
|
||||
- `path`:仅用于选择 SQLite3 数据库时,这个是数据库所存储的路径。
|
||||
- `host`:仅适用 MySQL 或者 Postgres。它包括 IP 地址或主机名以及端口。例如,Grafana 和 MySQL 运行在同一台主机上设置如: `host = 127.0.0.1:3306`。
|
||||
- `name`:Grafana 数据库的名称,把它设置为 Grafana 或其它名称。
|
||||
- `user`:数据库用户(不适用于 SQLite3)。
|
||||
- `password`:数据库用户密码(不适用于 SQLite3)。
|
||||
- `ssl_mode`:对于 Postgres,使用 `disable`,`require`,或 `verify-full` 等值。对于 MySQL,使用 `true`,`false`,或 `skip-verify`。
|
||||
- `ca_cert_path`:(只适用于 MySQL)CA 证书文件路径,在多数 Linux 系统中,证书可以在 `/etc/ssl/certs` 找到。
|
||||
- `client_key_path`:(只适用于 MySQL)客户端密钥的路径,只在服务端需要用户端验证时使用。
|
||||
- `client_cert_path`:(只适用于 MySQL)客户端证书的路径,只在服务端需要用户端验证时使用。
|
||||
- `server_cert_name`:(只适用于 MySQL)MySQL 服务端使用的证书的通用名称字段。如果 `ssl_mode` 设置为 `skip-verify` 时可以不设置。
|
||||
- `[security]`
|
||||
- `admin_user`:这个是 Grafana 默认的管理员用户的用户名,默认设置为 admin。
|
||||
- `admin_password`:这个是 Grafana 默认的管理员用户的密码,在第一次运行时设置,默认为 admin。
|
||||
- `login_remember_days`:保持登录/记住我的持续天数。
|
||||
- `secret_key`:用于保持登录/记住我的 cookies 的签名。
|
||||
|
||||
### 设置监控的重要组件
|
||||
|
||||
我们可以使用下面的组件来创建我们的 Docker 监控系统
|
||||
我们可以使用下面的组件来创建我们的 Docker 监控系统。
|
||||
|
||||
`cAdvisor` : 他被称为 Container Advisor。它提供了对用户的资源利用和性能特征的解读。它收集、合并、处理、导出运行中的容器的信息。你可以通过文档了解更多关于这个。
|
||||
- `cAdvisor`:它被称为 Container Advisor。它给用户提供了一个资源利用和性能特征的解读。它会收集、聚合、处理、导出运行中的容器的信息。你可以通过[这个文档](https://github.com/google/cadvisor)了解更多。
|
||||
- `InfluxDB`:这是一个包含了时间序列、度量和分析数据库。我们使用这个数据源来设置我们的监控。cAdvisor 只展示实时信息,并不保存这些度量信息。Influx Db 帮助保存 cAdvisor 提供的监控数据,以展示非某一时段的数据。
|
||||
- `Grafana Dashboard`:它可以帮助我们在视觉上整合所有的信息。这个强大的仪表盘使我们能够针对 InfluxDB 数据存储进行查询并将他们放在一个布局合理好看的图表中。
|
||||
|
||||
`InfluxDB` : 这是一个时间排序、度量和分析数据库。我们使用这个数据源来设置我们的监控。cAdvisor 只展示时间信息,不保存度量信息。Influx Db帮助保存 cAdvisor 提供的监控数据,以展示非实时数据。
|
||||
### Docker 监控的安装
|
||||
|
||||
`Grafana Dashboard` : 它可以帮助我们在视觉上整合所有的信息。这个强大的仪表盘使我们能够针对数据存储 InfluxDB 进行查询并将他们放在一个布局合理好看的图表中。
|
||||
|
||||
### Docker监控的安装
|
||||
|
||||
我们需要一步一步的安装每一个下面的组件在我们的 Docker 系统中。
|
||||
我们需要一步一步的在我们的 Docker 系统中安装以下每一个组件:
|
||||
|
||||
#### 安装 InfluxDB
|
||||
|
||||
@ -185,11 +137,11 @@ d3b6f7789e0d1d01fa4e0aacdb636c221421107d1df96808ecbe8e241ceb1823
|
||||
--name influxsrv : container have name influxsrv, use to cAdvisor link it.
|
||||
```
|
||||
|
||||
你可以测试 InfluxDB 是否安装好,通过访问这个 URL>>http://45.79.148.234:8083 (译者注,应当访问你自己的服务器的IP:8083),并且使用 root 用户的帐号和密码登陆
|
||||
你可以测试 InfluxDB 是否安装好,通过访问这个 URL `http://你的 IP 地址:8083`,用户名和密码都是 ”root“。
|
||||
|
||||

|
||||
|
||||
我们可以在这个界面上创建我们需要的数据库.
|
||||
我们可以在这个界面上创建我们所需的数据库。
|
||||
|
||||

|
||||
|
||||
@ -217,39 +169,39 @@ root@ubuntu:~#
|
||||
-storage_driver_db=cadvisor: database name. Uses db ‘cadvisor’ by default
|
||||
```
|
||||
|
||||
你可以通过访问这个地址来测试安装 cAdvisor 是否正常 >>http://45.79.148.234:8080. 这将为你的 Docker 主机和容器提供统计信息。
|
||||
你可以通过访问这个地址来测试安装 cAdvisor 是否正常 `http://你的 IP 地址:8080`。 这将为你的 Docker 主机和容器提供统计信息。
|
||||
|
||||

|
||||
|
||||
#### 安装 Grafana 控制面板
|
||||
|
||||
首先我们需要安装 Grafana 仪表板并链接到 InfluxDB,你可以执行下面的命令来设置他
|
||||
最后,我们需要安装 Grafana 仪表板并连接到 InfluxDB,你可以执行下面的命令来设置它。
|
||||
|
||||
```
|
||||
root@ubuntu:~# docker run -d -p 3000:3000 -e INFLUXDB_HOST=localhost -e INFLUXDB_PORT=8086 -e INFLUXDB_NAME=cadvisor -e INFLUXDB_USER=root -e INFLUXDB_PASS=root --link influxsrv:influxsrv --name grafana grafana/grafana
|
||||
f3b7598529202b110e4e6b998dca6b6e60e8608d75dcfe0d2b09ae408f43684a
|
||||
```
|
||||
|
||||
现在我们可以登陆 Grafana 来配置数据源. 访问 http://45.79.148.234:3000 或 http://45.79.148.234:
|
||||
现在我们可以登录 Grafana 来配置数据源. 访问 `http://你的 IP 地址:3000` 或 `http://你的 IP 地址`(如果你在前面做了端口映射的话):
|
||||
|
||||
用户名- admin
|
||||
密码- admin
|
||||
- 用户名 - admin
|
||||
- 密码 - admin
|
||||
|
||||
一旦我们安装好了 Grafana,我们可以链接 InfluxDB。登陆到控制台并且点击面板左上方角落的 Grafana 图标(火球)。点击数据源(Data Sources)来配置。
|
||||
一旦我们安装好了 Grafana,我们可以连接 InfluxDB。登录到仪表盘并且点击面板左上方角落的 Grafana 图标(那个火球)。点击数据源(Data Sources)来配置。
|
||||
|
||||

|
||||
|
||||
现在你可以添加我们新的图像到我们默认的数据源 InfluxDB.
|
||||
现在你可以添加新的图形(Graph)到我们默认的数据源 InfluxDB。
|
||||
|
||||

|
||||
|
||||
我们可以通过在测量页面调整我们的图像可以编辑和调整我们的查询
|
||||
我们可以通过在测量(Metric)页面编辑和调整我们的查询以调整我们的图形。
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
你可以在 [更多信息][1]看到更多关于Docker监控的小心。 感谢你的阅读。我希望你可以留下有价值的建议和评论。希望你有个美好的一天
|
||||
关于 Docker 监控,你可用[从此了解][1]更多信息。 感谢你的阅读。我希望你可以留下有价值的建议和评论。希望你有个美好的一天。
|
||||
|
||||
------
|
||||
|
||||
@ -257,7 +209,7 @@ via: http://linoxide.com/linux-how-to/monitor-docker-containers-grafana-ubuntu/
|
||||
|
||||
作者:[Saheetha Shameer][a]
|
||||
译者:[Bestony](https://github.com/bestony)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
@ -0,0 +1,188 @@
|
||||
写一个 JavaScript 框架:比 setTimeout 更棒的定时执行
|
||||
===================
|
||||
|
||||
这是 [JavaScript 框架系列][2]的第二章。在这一章里,我打算讲一下在浏览器里的异步代码不同执行方式。你将了解定时器和事件循环之间的不同差异,比如 setTimeout 和 Promises。
|
||||
|
||||
这个系列是关于一个开源的客户端框架,叫做 NX。在这个系列里,我主要解释一下写该框架不得不克服的主要困难。如果你对 NX 感兴趣可以参观我们的 [主页][1]。
|
||||
|
||||
这个系列包含以下几个章节:
|
||||
|
||||
1. [项目结构][2]
|
||||
2. 定时执行 (当前章节)
|
||||
3. [沙箱代码评估][3]
|
||||
4. [数据绑定介绍](https://blog.risingstack.com/writing-a-javascript-framework-data-binding-dirty-checking/)
|
||||
5. [数据绑定与 ES6 代理](https://blog.risingstack.com/writing-a-javascript-framework-data-binding-es6-proxy/)
|
||||
6. 自定义元素
|
||||
7. 客户端路由
|
||||
|
||||
### 异步代码执行
|
||||
|
||||
你可能比较熟悉 `Promise`、`process.nextTick()`、`setTimeout()`,或许还有 `requestAnimationFrame()` 这些异步执行代码的方式。它们内部都使用了事件循环,但是它们在精确计时方面有一些不同。
|
||||
|
||||
在这一章里,我将解释它们之间的不同,然后给大家演示怎样在一个类似 NX 这样的先进框架里面实现一个定时系统。不用我们重新做一个,我们将使用原生的事件循环来达到我们的目的。
|
||||
|
||||
### 事件循环
|
||||
|
||||
事件循环甚至没有在 [ES6 规范](http://www.ecma-international.org/ecma-262/6.0/)里提到。JavaScript 自身只有任务(Job)和任务队列(job queue)。更加复杂的事件循环是在 NodeJS 和 HTML5 规范里分别定义的,因为这篇是针对前端的,我会在详细说明后者。
|
||||
|
||||
事件循环可以被看做某个条件的循环。它不停的寻找新的任务来运行。这个循环中的一次迭代叫做一个滴答(tick)。在一次滴答期间执行的代码称为一次任务(task)。
|
||||
|
||||
```
|
||||
while (eventLoop.waitForTask()) {
|
||||
eventLoop.processNextTask()
|
||||
}
|
||||
```
|
||||
任务是同步代码,它可以在循环中调度其它任务。一个简单的调用新任务的方式是 `setTimeout(taskFn)`。不管怎样, 任务可能有很多来源,比如用户事件、网络或者 DOM 操作。
|
||||
|
||||

|
||||
|
||||
### 任务队列
|
||||
|
||||
更复杂一些的是,事件循环可以有多个任务队列。这里有两个约束条件,相同任务源的事件必须在相同的队列,以及任务必须按插入的顺序进行处理。除此之外,浏览器可以做任何它想做的事情。例如,它可以决定接下来处理哪个任务队列。
|
||||
|
||||
```
|
||||
while (eventLoop.waitForTask()) {
|
||||
const taskQueue = eventLoop.selectTaskQueue()
|
||||
if (taskQueue.hasNextTask()) {
|
||||
taskQueue.processNextTask()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
用这个模型,我们不能精确的控制定时。如果用 `setTimeout()`浏览器可能决定先运行完其它几个队列才运行我们的队列。
|
||||
|
||||

|
||||
|
||||
### 微任务队列
|
||||
|
||||
幸运的是,事件循环还提供了一个叫做微任务(microtask)队列的单一队列。当前任务结束的时候,微任务队列会清空每个滴答里的任务。
|
||||
|
||||
```
|
||||
while (eventLoop.waitForTask()) {
|
||||
const taskQueue = eventLoop.selectTaskQueue()
|
||||
if (taskQueue.hasNextTask()) {
|
||||
taskQueue.processNextTask()
|
||||
}
|
||||
|
||||
const microtaskQueue = eventLoop.microTaskQueue
|
||||
while (microtaskQueue.hasNextMicrotask()) {
|
||||
microtaskQueue.processNextMicrotask()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
最简单的调用微任务的方法是 `Promise.resolve().then(microtaskFn)`。微任务按照插入顺序进行处理,并且由于仅存在一个微任务队列,浏览器不会把时间弄乱了。
|
||||
|
||||
此外,微任务可以调度新的微任务,它将插入到同一个队列,并在同一个滴答内处理。
|
||||
|
||||

|
||||
|
||||
### 绘制(Rendering)
|
||||
|
||||
最后是绘制(Rendering)调度,不同于事件处理和分解,绘制并不是在单独的后台任务完成的。它是一个可以运行在每个循环滴答结束时的算法。
|
||||
|
||||
在这里浏览器又有了许多自由:它可能在每个任务以后绘制,但是它也可能在好几百个任务都执行了以后也不绘制。
|
||||
|
||||
幸运的是,我们有 `requestAnimationFrame()`,它在下一个绘制之前执行传递的函数。我们最终的事件模型像这样:
|
||||
|
||||
```
|
||||
while (eventLoop.waitForTask()) {
|
||||
const taskQueue = eventLoop.selectTaskQueue()
|
||||
if (taskQueue.hasNextTask()) {
|
||||
taskQueue.processNextTask()
|
||||
}
|
||||
|
||||
const microtaskQueue = eventLoop.microTaskQueue
|
||||
while (microtaskQueue.hasNextMicrotask()) {
|
||||
microtaskQueue.processNextMicrotask()
|
||||
}
|
||||
|
||||
if (shouldRender()) {
|
||||
applyScrollResizeAndCSS()
|
||||
runAnimationFrames()
|
||||
render()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
现在用我们所知道知识来创建定时系统!
|
||||
|
||||
### 利用事件循环
|
||||
|
||||
和大多数现代框架一样,[NX][1] 也是基于 DOM 操作和数据绑定的。批量操作和异步执行以取得更好的性能表现。基于以上理由我们用 `Promises`、 `MutationObservers` 和 `requestAnimationFrame()`。
|
||||
|
||||
我们所期望的定时器是这样的:
|
||||
|
||||
1. 代码来自于开发者
|
||||
2. 数据绑定和 DOM 操作由 NX 来执行
|
||||
3. 开发者定义事件钩子
|
||||
4. 浏览器进行绘制
|
||||
|
||||
#### 步骤 1
|
||||
|
||||
NX 寄存器对象基于 [ES6 代理](https://ponyfoo.com/articles/es6-proxies-in-depth) 以及 DOM 变动基于[MutationObserver](https://davidwalsh.name/mutationobserver-api) (变动观测器)同步运行(下一节详细介绍)。 它作为一个微任务延迟直到步骤 2 执行以后才做出反应。这个延迟已经在 `Promise.resolve().then(reaction)` 进行了对象转换,并且它将通过变动观测器自动运行。
|
||||
|
||||
#### 步骤 2
|
||||
|
||||
来自开发者的代码(任务)运行完成。微任务由 NX 开始执行所注册。 因为它们是微任务,所以按序执行。注意,我们仍然在同一个滴答循环中。
|
||||
|
||||
#### 步骤 3
|
||||
|
||||
开发者通过 `requestAnimationFrame(hook)` 通知 NX 运行钩子。这可能在滴答循环后发生。重要的是,钩子运行在下一次绘制之前和所有数据操作之后,并且 DOM 和 CSS 改变都已经完成。
|
||||
|
||||
#### 步骤 4
|
||||
|
||||
浏览器绘制下一个视图。这也有可能发生在滴答循环之后,但是绝对不会发生在一个滴答的步骤 3 之前。
|
||||
|
||||
### 牢记在心里的事情
|
||||
|
||||
我们在原生的事件循环之上实现了一个简单而有效的定时系统。理论上讲它运行的很好,但是还是很脆弱,一个轻微的错误可能会导致很严重的 BUG。
|
||||
|
||||
在一个复杂的系统当中,最重要的就是建立一定的规则并在以后保持它们。在 NX 中有以下规则:
|
||||
|
||||
1. 永远不用 `setTimeout(fn, 0)` 来进行内部操作
|
||||
2. 用相同的方法来注册微任务
|
||||
3. 微任务仅供内部操作
|
||||
4. 不要干预开发者钩子运行时间
|
||||
|
||||
#### 规则 1 和 2
|
||||
|
||||
数据反射和 DOM 操作将按照操作顺序执行。这样只要不混合就可以很好的延迟它们的执行。混合执行会出现莫名其妙的问题。
|
||||
|
||||
`setTimeout(fn, 0)` 的行为完全不可预测。使用不同的方法注册微任务也会发生混乱。例如,下面的例子中 microtask2 不会正确地在 microtask1 之前运行。
|
||||
|
||||
```
|
||||
Promise.resolve().then().then(microtask1)
|
||||
Promise.resolve().then(microtask2)
|
||||
```
|
||||
|
||||

|
||||
|
||||
#### 规则 3 和 4
|
||||
|
||||
分离开发者的代码执行和内部操作的时间窗口是非常重要的。混合这两种行为会导致不可预测的事情发生,并且它会需要开发者了解框架内部。我想很多前台开发者已经有过类似经历。
|
||||
|
||||
### 结论
|
||||
|
||||
如果你对 NX 框架感兴趣,可以参观我们的[主页][1]。还可以在 GIT 上找到我们的[源代码][5]。
|
||||
|
||||
在下一节我们再见,我们将讨论 [沙盒化代码执行][4]!
|
||||
|
||||
你也可以给我们留言。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://blog.risingstack.com/writing-a-javascript-framework-execution-timing-beyond-settimeout/
|
||||
|
||||
作者:[Bertalan Miklos][a]
|
||||
译者:[kokialoves](https://github.com/kokialoves)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://blog.risingstack.com/author/bertalan/
|
||||
[1]: http://nx-framework.com/
|
||||
[2]: https://blog.risingstack.com/writing-a-javascript-framework-project-structuring/
|
||||
[3]: https://blog.risingstack.com/writing-a-javascript-framework-sandboxed-code-evaluation/
|
||||
[4]: https://blog.risingstack.com/writing-a-javascript-framework-sandboxed-code-evaluation/
|
||||
[5]: https://github.com/RisingStack/nx-framework
|
144
published/201611/20160815 How to manage binary blobs with Git.md
Normal file
144
published/201611/20160815 How to manage binary blobs with Git.md
Normal file
@ -0,0 +1,144 @@
|
||||
Git 系列(七):使用 Git 管理二进制大对象
|
||||
=====================
|
||||
|
||||
通过这系列的前六篇文章,我们已经学会使用 Git 来对文本文件进行版本控制的管理。我们不禁要问,还有二进制文件呢,也可进行进行版本控制吗?答案是肯定的,Git 已经有了可以处理像多媒体文件这样的二进制大对象块(blob)的扩展。因此,今天我们会学习使用 Git 来管理所谓的二进制资产。
|
||||
|
||||
似乎大家都认可的事就是 Git 对于大的二进制对象文件支持得不好。要记住,二进制大对象与大文本文件是不同的。虽然 Git 对大型的文本文件版本控制毫无问题,但是对于不透明的二进制文件起不了多大作用,只能把它当作一个大的实体黑盒来提交。
|
||||
|
||||
设想这样的场景,有一个另人兴奋的第一人称解密游戏,您正在为它制作复杂的 3D 建模,源文件是以二进制格式保存的,最后生成一个 1GB 大小的的文件。您提交过一次,在 Git 源仓库历史中有一个 1GB 大小的新增提交。随后,您修改了下模型人物的头发造型,然后提交更新,因为 Git 并不能把头发从头部及模型中其余的部分离开来,所以您只能又提交 1GB 的量。接着,您改变了模型的眼睛颜色,提交这部分更新:又是 GB 级的提交量。对一个模型的一些微小修改,就会导致三个 GB 级的提交量。对于想对一个游戏所有资源进行版本控制这样的规模,这是个严重的问题。
|
||||
|
||||
不同的是如 `.obj` 这种格式的文本文件,和其它类型文件一样,都是一个提交就存储所有更新修改状态,不同的是 `.obj` 文件是一系列描述模型的纯文本行。如果您修改了该模型并保存回 `.obj` 文件,Git 可以逐行读取这两个文件,然后创建一个差异版本,得到一个相当小的提交。模型越精细,提交就越小,这就是标准的 Git 用例。虽然文件本身很大,但 Git 使用覆盖或稀疏存储的方法来构建当前数据使用状态的完整描述。
|
||||
|
||||
然而,不是所有的都是纯文本的,但都要使用 Git,所以需要解决方案,并且已经出现几个了。
|
||||
|
||||
[OSTree](https://ostree.readthedocs.io/en/latest/) 开始是作为 GNOME 项目出现的,旨在管理操作系统的二进制文件。它不适用于这里,所以我直接跳过。
|
||||
|
||||
[Git 大文件存储](https://git-lfs.github.com/)(LFS) 是放在 GitHub 上的一个开源项目,是从 git-media 项目中分支出来的。[git-media](https://github.com/alebedev/git-media) 和 [git-annex](https://git-annex.branchable.com/walkthrough/) 是 Git 用于管理大文件的扩展。它们是对同一问题的两种不同的解决方案,各有优点。虽然它们都不是官方的项目,但在我看来,每个都有独到之处:
|
||||
|
||||
* git-media 是集中模式,有一个公共资产的存储库。你可以告诉 git-media 大文件需要存储的位置,是在硬盘、服务器还是在云存储服务器,项目中的每个用户都将该位置视为大型文件的中心主存储位置。
|
||||
* git-annex 侧重于分布模式。用户各自创建存储库,每个存储库都有一个存储大文件的本地目录 `.git/annex`。这些 annex 会定期同步,只要有需要,每个用户都可以访问到所有的资源。除非通过 annex-cost 特别配置,否则 git-annex 优先使用本地存储,再使用外部存储。
|
||||
|
||||
对于这些,我已经在生产中使用了 git-media 和 git-annex,那么下面会向你们概述其工作原理。
|
||||
|
||||
### git-media
|
||||
|
||||
git-media 是使用 Ruby 语言开发的,所以首先要安装 gem(LCTT 译注:Gem 是基于 Ruby 的一些开发工具包)。安装说明在[其网站](https://github.com/alebedev/git-media)上。想使用 git-meida 的用户都需要安装它,因为 gem 是跨平台的工具,所以在各平台都适用。
|
||||
|
||||
安装完 git-media 后,你需要设置一些 Git 的配置选项。在每台机器上只需要配置一次。
|
||||
|
||||
```
|
||||
$ git config filter.media.clean "git-media filter-clean"
|
||||
$ git config filter.media.smudge "git-media filter-smudge"
|
||||
```
|
||||
|
||||
在要使用 git-media 的每个存储库中,设置一个属性以将刚刚创建的过滤器结合到要您分类为“媒体(media)”的文件类型里。别被这种术语混淆。一个更好的术语是“资产”,因为“媒体”通常的意思是音频、视频和照片,但您也可以很容易地将 3D 模型,烘焙和纹理等归类为媒体。
|
||||
|
||||
例如:
|
||||
|
||||
```
|
||||
$ echo "*.mp4 filter=media -crlf" >> .gitattributes
|
||||
$ echo "*.mkv filter=media -crlf" >> .gitattributes
|
||||
$ echo "*.wav filter=media -crlf" >> .gitattributes
|
||||
$ echo "*.flac filter=media -crlf" >> .gitattributes
|
||||
$ echo "*.kra filter=media -crlf" >> .gitattributes
|
||||
```
|
||||
|
||||
当您要暂存(stage)这些类型的文件时,文件会被复制到 `.git/media` 目录。
|
||||
|
||||
假设在服务器已经有了一个 Git 源仓库,最后一步就告诉源仓库“母舰”所在的位置,也就是,当媒体文件被推送给所有用户共享时,媒体文件将会存储的位置。这在仓库的 `.git/config` 文件中设置,请替换成您的用户名、主机和路径:
|
||||
|
||||
```
|
||||
[git-media]
|
||||
transport = scp
|
||||
autodownload = false #默认为 true,拉取资源
|
||||
scpuser = seth
|
||||
scphost = example.com
|
||||
scppath = /opt/jupiter.git
|
||||
```
|
||||
|
||||
如果您的服务器上 SSH 设置比较复杂,例如使用了非标准端口或非默认 SSH 密钥文件的路径,请使用 `.ssh/config` 为主机设置默认配置。
|
||||
|
||||
git-media 的使用和普通文件一样,可以把普通文件和 blob 文件一样对待,一样进行 commit 操作。操作流程中唯一的不同就是,在某些时候,您应该将您的资产(或称媒体)同步到共享存储库中。
|
||||
|
||||
当要为团队发布资产或自己备份资料时,请使用如下命令:
|
||||
|
||||
```
|
||||
$ git media sync
|
||||
```
|
||||
|
||||
要用一个变更后的版本替换 git-media 中的文件时(例如,一个已经美声过的音频文件,或者一个已经完成的遮罩绘画,或者一个已经被颜色分级的视频文件),您必须明确的告诉 Git 更新该媒体。这将覆盖 git-media 不会复制远程已经存在的文件的默认设置:
|
||||
|
||||
```
|
||||
$ git update-index --really-refresh
|
||||
```
|
||||
|
||||
当您团队的其他成员(或是您本人,在其它机器上)克隆本仓库时,如果没有在 `.git/config` 中把 `autodownload` 选项设置为 `true` 的话,默认是不会下载资源的。但 git-media 的一个同步命令 `git media sync` 可解决所有问题。
|
||||
|
||||
### git-annex
|
||||
|
||||
git-annex 的处理流程略微的有些不同,默认是使用本地仓库的,但基本的思想都一样。您可以从你的发行版的软件仓库中安装 git-annex,或者根据需要从该网站上下载安装。与 git-media 一样,任何使用 git-annex 的用户都必须在其机器上安装它。
|
||||
|
||||
其初始化设置比 git-media 都简单。运行如下命令,其中替换成您的路径,就可以在您的服务器上创建好裸存储库:
|
||||
|
||||
```
|
||||
$ git init --bare --shared /opt/jupiter.git
|
||||
```
|
||||
|
||||
然后克隆到本地计算机,把它标记为 git-annex 的初始路径:
|
||||
|
||||
```
|
||||
$ git clone seth@example.com:/opt/jupiter.clone
|
||||
Cloning into 'jupiter.clone'...
|
||||
warning: You appear to have clonedan empty repository.
|
||||
Checking connectivity... done.
|
||||
$ git annex init "seth workstation"
|
||||
init seth workstation ok
|
||||
```
|
||||
|
||||
不要使用过滤器来区分媒体资源或大文件,您可以使用 `git annex` 命令来配置归类大文件:
|
||||
|
||||
```
|
||||
$ git annex add bigblobfile.flac
|
||||
add bigblobfile.flac
|
||||
(checksum) ok
|
||||
(Recording state in Git...)
|
||||
```
|
||||
|
||||
跟普通文件一样进行提交操作:
|
||||
|
||||
```
|
||||
$ git commit -m 'added flac source for sound fx'
|
||||
```
|
||||
|
||||
但是推送操作是不同的,因为 `git annex` 使用自己的分支来跟踪资产。您首次推送可能需要 `-u` 选项,具体取决于您如何管理您的存储库:
|
||||
|
||||
```
|
||||
$ git push -u origin master git-annex
|
||||
To seth@example.com:/opt/jupiter.git
|
||||
* [new branch] master -> master
|
||||
* [new branch] git-annex -> git-annex
|
||||
```
|
||||
|
||||
和 git-media 一样,普通的 `git push` 命令是不会拷贝资料到服务器的,仅仅只是发送了相关的消息,要真正共享文件,需要运行同步命令:
|
||||
|
||||
```
|
||||
$ git annex sync --content
|
||||
```
|
||||
|
||||
如果别人已经提交了共享资源,您需要拉取它们,`git annex sync` 命令将提示您要在本地检出你本机没有,但在服务器上存在的资源。
|
||||
|
||||
git-media 和 git-annex 都非常灵活,都可以使用本地存储库来代替服务器,所以它们也常用于管理私有的本地项目。
|
||||
|
||||
Git 是一个非常强大和扩展性非常强的系统应用软件,我们应该毫不犹豫的使用它。现在就开始试试吧!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/life/16/8/how-manage-binary-blobs-git-part-7
|
||||
|
||||
作者:[Seth Kenlon][a]
|
||||
译者:[runningwater](https://github.com/runningwater)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/seth
|
@ -1,9 +1,11 @@
|
||||
小模块的开销
|
||||
JavaScript 小模块的开销
|
||||
====
|
||||
|
||||
大约一年之前,我在将一个大型 JavaScript 代码库重构为小模块时发现了 Browserify 和 Webpack 中一个令人沮丧的事实:
|
||||
更新(2016/10/30):我写完这篇文章之后,我在[这个基准测试中发了一个错误](https://github.com/nolanlawson/cost-of-small-modules/pull/8),会导致 Rollup 比它预期的看起来要好一些。不过,整体结果并没有明显的不同(Rollup 仍然击败了 Browserify 和 Webpack,虽然它并没有像 Closure 十分好),所以我只是更新了图表。该基准测试包括了 [RequireJS 和 RequireJS Almond 打包器](https://github.com/nolanlawson/cost-of-small-modules/pull/5),所以文章中现在也包括了它们。要看原始帖子,可以查看[历史版本](https://web.archive.org/web/20160822181421/https://nolanlawson.com/2016/08/15/the-cost-of-small-modules/)。
|
||||
|
||||
> “代码越模块化,代码体积就越大。”- Nolan Lawson
|
||||
大约一年之前,我在将一个大型 JavaScript 代码库重构为更小的模块时发现了 Browserify 和 Webpack 中一个令人沮丧的事实:
|
||||
|
||||
> “代码越模块化,代码体积就越大。:< ”- Nolan Lawson
|
||||
|
||||
过了一段时间,Sam Saccone 发布了一些关于 [Tumblr][1] 和 [Imgur][2] 页面加载性能的出色的研究。其中指出:
|
||||
|
||||
@ -15,9 +17,9 @@
|
||||
|
||||
一个页面中包含的 JavaScript 脚本越多,页面加载也将越慢。庞大的 JavaScript 包会导致浏览器花费更多的时间去下载、解析和执行,这些都将加长载入时间。
|
||||
|
||||
即使当你使用如 Webpack [code splitting][3]、Browserify [factor bundles][4] 等工具将代码分解为多个包,时间的花费也仅仅是被延迟到页面生命周期的晚些时候。JavaScript 迟早都将有一笔开销。
|
||||
即使当你使用如 Webpack [code splitting][3]、Browserify [factor bundles][4] 等工具将代码分解为多个包,该开销也仅仅是被延迟到页面生命周期的晚些时候。JavaScript 迟早都将有一笔开销。
|
||||
|
||||
此外,由于 JavaScript 是一门动态语言,同时流行的 [CommonJS][5] 模块也是动态的,所以这就使得在最终分发给用户的代码中剔除无用的代码变得异常困难。譬如你可能只使用到 jQuery 中的 $.ajax,但是通过载入 jQuery 包,你将以整个包为代价。
|
||||
此外,由于 JavaScript 是一门动态语言,同时流行的 [CommonJS][5] 模块也是动态的,所以这就使得在最终分发给用户的代码中剔除无用的代码变得异常困难。譬如你可能只使用到 jQuery 中的 $.ajax,但是通过载入 jQuery 包,你将付出整个包的代价。
|
||||
|
||||
JavaScript 社区对这个问题提出的解决办法是提倡 [小模块][6] 的使用。小模块不仅有许多 [美好且实用的好处][7] 如易于维护,易于理解,易于集成等,而且还可以通过鼓励包含小巧的功能而不是庞大的库来解决之前提到的 jQuery 的问题。
|
||||
|
||||
@ -66,7 +68,7 @@ $ browserify node_modules/qs | browserify-count-modules
|
||||
|
||||
顺带一提,我写过的最大的开源站点 [Pokedex.org][21] 包含了 4 个包,共 311 个模块。
|
||||
|
||||
让我们先暂时忽略这些 JavaScript 包的实际大小,我认为去探索一下一定数量的模块本身开销会事一件有意思的事。虽然 Sam Saccone 的文章 [“2016 年 ES2015 转译的开销”][22] 已经广为流传,但是我认为他的结论还未到达足够深度,所以让我们挖掘的稍微再深一点吧。
|
||||
让我们先暂时忽略这些 JavaScript 包的实际大小,我认为去探索一下一定数量的模块本身开销会是一件有意思的事。虽然 Sam Saccone 的文章 [“2016 年 ES2015 转译的开销”][22] 已经广为流传,但是我认为他的结论还未到达足够深度,所以让我们挖掘的稍微再深一点吧。
|
||||
|
||||
### 测试环节!
|
||||
|
||||
@ -86,13 +88,13 @@ console.log(total)
|
||||
module.exports = 1
|
||||
```
|
||||
|
||||
我测试了五种打包方法:Browserify, 带 [bundle-collapser][24] 插件的 Browserify, Webpack, Rollup 和 Closure Compiler。对于 Rollup 和 Closure Compiler 我使用了 ES6 模块,而对于 Browserify 和 Webpack 则用的 CommonJS,目的是为了不涉及其各自缺点而导致测试的不公平(由于它们可能需要做一些转译工作,如 Babel 一样,而这些工作将会增加其自身的运行时间)。
|
||||
我测试了五种打包方法:Browserify、带 [bundle-collapser][24] 插件的 Browserify、Webpack、Rollup 和 Closure Compiler。对于 Rollup 和 Closure Compiler 我使用了 ES6 模块,而对于 Browserify 和 Webpack 则用的是 CommonJS,目的是为了不涉及其各自缺点而导致测试的不公平(由于它们可能需要做一些转译工作,如 Babel 一样,而这些工作将会增加其自身的运行时间)。
|
||||
|
||||
为了更好地模拟一个生产环境,我将带 -mangle 和 -compress 参数的 Uglify 用于所有的包,并且使用 gzip 压缩后通过 GitHub Pages 用 HTTPS 协议进行传输。对于每个包,我一共下载并执行 15 次,然后取其平均值,并使用 performance.now() 函数来记录载入时间(未使用缓存)与执行时间。
|
||||
为了更好地模拟一个生产环境,我对所有的包采用带 `-mangle` 和 `-compress` 参数的 `Uglify` ,并且使用 gzip 压缩后通过 GitHub Pages 用 HTTPS 协议进行传输。对于每个包,我一共下载并执行 15 次,然后取其平均值,并使用 `performance.now()` 函数来记录载入时间(未使用缓存)与执行时间。
|
||||
|
||||
### 包大小
|
||||
|
||||
在我们查看测试结果之前,我们有必要先来看一眼我们要测试的包文件。一下是每个包最小处理后但并未使用 gzip 压缩时的体积大小(单位:Byte):
|
||||
在我们查看测试结果之前,我们有必要先来看一眼我们要测试的包文件。以下是每个包最小处理后但并未使用 gzip 压缩时的体积大小(单位:Byte):
|
||||
|
||||
| | 100 个模块 | 1000 个模块 | 5000 个模块 |
|
||||
| --- | --- | --- | --- |
|
||||
@ -110,7 +112,7 @@ module.exports = 1
|
||||
| rollup | 300 | 2145 | 11510 |
|
||||
| closure | 302 | 2140 | 11789 |
|
||||
|
||||
Browserify 和 Webpack 的工作方式是隔离各个模块到各自的函数空间,然后声明一个全局载入器,并在每次 require() 函数调用时定位到正确的模块处。下面是我们的 Browserify 包的样子:
|
||||
Browserify 和 Webpack 的工作方式是隔离各个模块到各自的函数空间,然后声明一个全局载入器,并在每次 `require()` 函数调用时定位到正确的模块处。下面是我们的 Browserify 包的样子:
|
||||
|
||||
```
|
||||
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o
|
||||
@ -144,7 +146,7 @@ Browserify 和 Webpack 的工作方式是隔离各个模块到各自的函数空
|
||||
|
||||
在 100 个模块时,各包的差异是微不足道的,但是一旦模块数量达到 1000 个甚至 5000 个时,差异将会变得非常巨大。iPod Touch 在不同包上的差异并不明显,而对于具有一定年代的 Nexus 5 来说,Browserify 和 Webpack 明显耗时更多。
|
||||
|
||||
与此同时,我发现有意思的是 Rollup 和 Closure 的运行开销对于 iPod 而言几乎可以忽略,并且与模块的数量关系也不大。而对于 Nexus 5 来说,运行的开销并非完全可以忽略,但它们仍比 Browserify 或 Webpack 低很多。后者若未在几百毫秒内完成加载则将会占用主线程的好几帧的时间,这就意味着用户界面将冻结并且等待直到模块载入完成。
|
||||
与此同时,我发现有意思的是 Rollup 和 Closure 的运行开销对于 iPod 而言几乎可以忽略,并且与模块的数量关系也不大。而对于 Nexus 5 来说,运行的开销并非完全可以忽略,但 Rollup/Closure 仍比 Browserify/Webpack 低很多。后者若未在几百毫秒内完成加载则将会占用主线程的好几帧的时间,这就意味着用户界面将冻结并且等待直到模块载入完成。
|
||||
|
||||
值得注意的是前面这些测试都是在千兆网速下进行的,所以在网络情况来看,这只是一个最理想的状况。借助 Chrome 开发者工具,我们可以认为地将 Nexus 5 的网速限制到 3G 水平,然后来看一眼这对测试产生的影响([查看表格][30]):
|
||||
|
||||
@ -152,13 +154,13 @@ Browserify 和 Webpack 的工作方式是隔离各个模块到各自的函数空
|
||||
|
||||
一旦我们将网速考虑进来,Browserify/Webpack 和 Rollup/Closure 的差异将变得更为显著。在 1000 个模块规模(接近于 Reddit 1050 个模块的规模)时,Browserify 花费的时间比 Rollup 长大约 400 毫秒。然而 400 毫秒已经不是一个小数目了,正如 Google 和 Bing 指出的,亚秒级的延迟都会 [对用户的参与产生明显的影响][32] 。
|
||||
|
||||
还有一件事需要指出,那就是这个测试并非测量 100 个、1000 个或者 5000 个模块的每个模块的精确运行时间。因为这还与你对 require() 函数的使用有关。在这些包中,我采用的是对每个模块调用一次 require() 函数。但如果你每个模块调用了多次 require() 函数(这在代码库中非常常见)或者你多次动态调用 require() 函数(例如在子函数中调用 require() 函数),那么你将发现明显的性能退化。
|
||||
还有一件事需要指出,那就是这个测试并非测量 100 个、1000 个或者 5000 个模块的每个模块的精确运行时间。因为这还与你对 `require()` 函数的使用有关。在这些包中,我采用的是对每个模块调用一次 `require()` 函数。但如果你每个模块调用了多次 `require()` 函数(这在代码库中非常常见)或者你多次动态调用 `require()` 函数(例如在子函数中调用 `require()` 函数),那么你将发现明显的性能退化。
|
||||
|
||||
Reddit 的移动站点就是一个很好的例子。虽然该站点有 1050 个模块,但是我测量了它们使用 Browserify 的实际执行时间后发现比“1000 个模块”的测试结果差好多。当使用那台运行 Chrome 的 Nexus 5 时,我测出 Reddit 的 Browserify require() 函数耗时 2.14 秒。而那个“1000 个模块”脚本中的等效函数只需要 197 毫秒(在搭载 i7 处理器的 Surface Book 上的桌面版 Chrome,我测出的结果分别为 559 毫秒与 37 毫秒,虽然给出桌面平台的结果有些令人惊讶)。
|
||||
|
||||
这结果提示我们有必要对每个模块使用多个 require() 函数的情况再进行一次测试。不过,我并不认为这对 Browserify 和 Webpack 会是一个公平的测试,因为 Rollup 和 Closure 都会将重复的 ES6 库导入处理为一个的顶级变量声明,同时也阻止了顶层空间以外的其他区域的导入。所以根本上来说,Rollup 和 Closure 中一个导入和多个导入的开销是相同的,而对于 Browserify 和 Webpack,运行开销随 require() 函数的数量线性增长。
|
||||
这结果提示我们有必要对每个模块使用多个 `require()` 函数的情况再进行一次测试。不过,我并不认为这对 Browserify 和 Webpack 会是一个公平的测试,因为 Rollup 和 Closure 都会将重复的 ES6 库导入处理为一个的顶级变量声明,同时也阻止了顶层空间以外的其他区域的导入。所以根本上来说,Rollup 和 Closure 中一个导入和多个导入的开销是相同的,而对于 Browserify 和 Webpack,运行开销随 `require()` 函数的数量线性增长。
|
||||
|
||||
为了我们这个分析的目的,我认为最好假设模块的数量是性能的短板。而事实上,“5000 个模块”也是一个比“5000 个 require() 函数调用”更好的度量标准。
|
||||
为了我们这个分析的目的,我认为最好假设模块的数量是性能的短板。而事实上,“5000 个模块”也是一个比“5000 个 `require()` 函数调用”更好的度量标准。
|
||||
|
||||
### 结论
|
||||
|
||||
@ -168,11 +170,11 @@ Reddit 的移动站点就是一个很好的例子。虽然该站点有 1050 个
|
||||
|
||||
给出这些结果之后,我对 Closure Compiler 和 Rollup 在 JavaScript 社区并没有得到过多关注而感到惊讶。我猜测或许是因为(前者)需要依赖 Java,而(后者)仍然相当不成熟并且未能做到开箱即用(详见 [Calvin’s Metcalf 的评论][37] 中作的不错的总结)。
|
||||
|
||||
即使没有足够数量的 JavaScript 开发者加入到 Rollup 或 Closure 的队伍中,我认为 npm 包作者们也已准备好了去帮助解决这些问题。如果你使用 npm 安装 lodash,你将会发其现主要的导入是一个巨大的 JavaScript 模块,而不是你期望的 Lodash 的超模块(hyper-modular)特性(require('lodash/uniq'),require('lodash.uniq') 等等)。对于 PouchDB,我们做了一个类似的声明以 [使用 Rollup 作为预发布步骤][38],这将产生对于用户而言尽可能小的包。
|
||||
即使没有足够数量的 JavaScript 开发者加入到 Rollup 或 Closure 的队伍中,我认为 npm 包作者们也已准备好了去帮助解决这些问题。如果你使用 npm 安装 lodash,你将会发其现主要的导入是一个巨大的 JavaScript 模块,而不是你期望的 Lodash 的超模块(hyper-modular)特性(`require('lodash/uniq')`,`require('lodash.uniq')` 等等)。对于 PouchDB,我们做了一个类似的声明以 [使用 Rollup 作为预发布步骤][38],这将产生对于用户而言尽可能小的包。
|
||||
|
||||
同时,我创建了 [rollupify][39] 来尝试将这过程变得更为简单一些,只需拖动到已存在的 Browserify 工程中即可。其基本思想是在你自己的项目中使用导入(import)和导出(export)(可以使用 [cjs-to-es6][40] 来帮助迁移),然后使用 require() 函数来载入第三方包。这样一来,你依旧可以在你自己的代码库中享受所有模块化的优点,同时能导出一个适当大小的大模块来发布给你的用户。不幸的是,你依旧得为第三方库付出一些代价,但是我发现这是对于当前 npm 生态系统的一个很好的折中方案。
|
||||
|
||||
所以结论如下:一个大的 JavaScript 包比一百个小 JavaScript 模块要快。尽管这是事实,我依旧希望我们社区能最终发现我们所处的困境————提倡小模块的原则对开发者有利,但是对用户不利。同时希望能优化我们的工具,使得我们可以对两方面都有利。
|
||||
所以结论如下:**一个大的 JavaScript 包比一百个小 JavaScript 模块要快**。尽管这是事实,我依旧希望我们社区能最终发现我们所处的困境————提倡小模块的原则对开发者有利,但是对用户不利。同时希望能优化我们的工具,使得我们可以对两方面都有利。
|
||||
|
||||
### 福利时间!三款桌面浏览器
|
||||
|
||||
@ -205,15 +207,15 @@ Firefox 48 ([查看表格][45])
|
||||
|
||||
[![Nexus 5 (3G) RequireJS 结果][53]](https://nolanwlawson.files.wordpress.com/2016/08/2016-08-20-14_45_29-small_modules3-xlsx-excel.png)
|
||||
|
||||
|
||||
更新 3: 我写了一个 [optimize-js](http://github.com/nolanlawson/optimize-js) ,它会减少一些函数内的函数的解析成本。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://nolanlawson.com/2016/08/15/the-cost-of-small-modules/?utm_source=javascriptweekly&utm_medium=email
|
||||
via: https://nolanlawson.com/2016/08/15/the-cost-of-small-modules/
|
||||
|
||||
作者:[Nolan][a]
|
||||
译者:[Yinr](https://github.com/Yinr)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
410
published/201611/20160820 Protocol Buffer Basics C++.md
Normal file
410
published/201611/20160820 Protocol Buffer Basics C++.md
Normal file
@ -0,0 +1,410 @@
|
||||
C++ 程序员 Protocol Buffers 基础指南
|
||||
============================
|
||||
|
||||
这篇教程提供了一个面向 C++ 程序员关于 protocol buffers 的基础介绍。通过创建一个简单的示例应用程序,它将向我们展示:
|
||||
|
||||
* 在 `.proto` 文件中定义消息格式
|
||||
* 使用 protocol buffer 编译器
|
||||
* 使用 C++ protocol buffer API 读写消息
|
||||
|
||||
这不是一个关于在 C++ 中使用 protocol buffers 的全面指南。要获取更详细的信息,请参考 [Protocol Buffer Language Guide][1] 和 [Encoding Reference][2]。
|
||||
|
||||
### 为什么使用 Protocol Buffers
|
||||
|
||||
我们接下来要使用的例子是一个非常简单的"地址簿"应用程序,它能从文件中读取联系人详细信息。地址簿中的每一个人都有一个名字、ID、邮件地址和联系电话。
|
||||
|
||||
如何序列化和获取结构化的数据?这里有几种解决方案:
|
||||
|
||||
* 以二进制形式发送/接收原生的内存数据结构。通常,这是一种脆弱的方法,因为接收/读取代码必须基于完全相同的内存布局、大小端等环境进行编译。同时,当文件增加时,原始格式数据会随着与该格式相关的软件而迅速扩散,这将导致很难扩展文件格式。
|
||||
* 你可以创造一种 ad-hoc 方法,将数据项编码为一个字符串——比如将 4 个整数编码为 `12:3:-23:67`。虽然它需要编写一次性的编码和解码代码且解码需要耗费一点运行时成本,但这是一种简单灵活的方法。这最适合编码非常简单的数据。
|
||||
* 序列化数据为 XML。这种方法是非常吸引人的,因为 XML 是一种适合人阅读的格式,并且有为许多语言开发的库。如果你想与其他程序和项目共享数据,这可能是一种不错的选择。然而,众所周知,XML 是空间密集型的,且在编码和解码时,它对程序会造成巨大的性能损失。同时,使用 XML DOM 树被认为比操作一个类的简单字段更加复杂。
|
||||
|
||||
Protocol buffers 是针对这个问题的一种灵活、高效、自动化的解决方案。使用 Protocol buffers,你需要写一个 `.proto` 说明,用于描述你所希望存储的数据结构。利用 `.proto` 文件,protocol buffer 编译器可以创建一个类,用于实现对高效的二进制格式的 protocol buffer 数据的自动化编码和解码。产生的类提供了构造 protocol buffer 的字段的 getters 和 setters,并且作为一个单元来处理读写 protocol buffer 的细节。重要的是,protocol buffer 格式支持格式的扩展,代码仍然可以读取以旧格式编码的数据。
|
||||
|
||||
### 在哪可以找到示例代码
|
||||
|
||||
示例代码被包含于源代码包,位于“examples”文件夹。可在[这里][4]下载代码。
|
||||
|
||||
### 定义你的协议格式
|
||||
|
||||
为了创建自己的地址簿应用程序,你需要从 `.proto` 开始。`.proto` 文件中的定义很简单:为你所需要序列化的每个数据结构添加一个消息(message),然后为消息中的每一个字段指定一个名字和类型。这里是定义你消息的 `.proto` 文件 `addressbook.proto`。
|
||||
|
||||
```
|
||||
package tutorial;
|
||||
|
||||
message Person {
|
||||
required string name = 1;
|
||||
required int32 id = 2;
|
||||
optional string email = 3;
|
||||
|
||||
enum PhoneType {
|
||||
MOBILE = 0;
|
||||
HOME = 1;
|
||||
WORK = 2;
|
||||
}
|
||||
|
||||
message PhoneNumber {
|
||||
required string number = 1;
|
||||
optional PhoneType type = 2 [default = HOME];
|
||||
}
|
||||
|
||||
repeated PhoneNumber phone = 4;
|
||||
}
|
||||
|
||||
message AddressBook {
|
||||
repeated Person person = 1;
|
||||
}
|
||||
```
|
||||
|
||||
如你所见,其语法类似于 C++ 或 Java。我们开始看看文件的每一部分内容做了什么。
|
||||
|
||||
`.proto` 文件以一个 package 声明开始,这可以避免不同项目的命名冲突。在 C++,你生成的类会被置于与 package 名字一样的命名空间。
|
||||
|
||||
下一步,你需要定义消息(message)。消息只是一个包含一系列类型字段的集合。大多标准的简单数据类型是可以作为字段类型的,包括 `bool`、`int32`、`float`、`double` 和 `string`。你也可以通过使用其他消息类型作为字段类型,将更多的数据结构添加到你的消息中——在以上的示例,`Person` 消息包含了 `PhoneNumber` 消息,同时 `AddressBook` 消息包含 `Person` 消息。你甚至可以定义嵌套在其他消息内的消息类型——如你所见,`PhoneNumber` 类型定义于 `Person` 内部。如果你想要其中某一个字段的值是预定义值列表中的某个值,你也可以定义 `enum` 类型——这儿你可以指定一个电话号码是 `MOBILE`、`HOME` 或 `WORK` 中的某一个。
|
||||
|
||||
每一个元素上的 `= 1`、`= 2` 标记确定了用于二进制编码的唯一“标签”(tag)。标签数字 1-15 的编码比更大的数字少需要一个字节,因此作为一种优化,你可以将这些标签用于经常使用的元素或 repeated 元素,剩下 16 以及更高的标签用于非经常使用的元素或 `optional` 元素。每一个 `repeated` 字段的元素需要重新编码标签数字,因此 `repeated` 字段适合于使用这种优化手段。
|
||||
|
||||
每一个字段必须使用下面的修饰符加以标注:
|
||||
|
||||
* `required`:必须提供该字段的值,否则消息会被认为是 “未初始化的”(uninitialized)。如果 `libprotobuf` 以调试模式编译,序列化未初始化的消息将引起一个断言失败。以优化形式构建,将会跳过检查,并且无论如何都会写入该消息。然而,解析未初始化的消息总是会失败(通过 parse 方法返回 `false`)。除此之外,一个 `required` 字段的表现与 `optional` 字段完全一样。
|
||||
* `optional`:字段可能会被设置,也可能不会。如果一个 `optional` 字段没被设置,它将使用默认值。对于简单类型,你可以指定你自己的默认值,正如例子中我们对电话号码的 `type` 一样,否则使用系统默认值:数字类型为 0、字符串为空字符串、布尔值为 false。对于嵌套消息,默认值总为消息的“默认实例”或“原型”,它的所有字段都没被设置。调用 accessor 来获取一个没有显式设置的 `optional`(或 `required`) 字段的值总是返回字段的默认值。
|
||||
* `repeated`:字段可以重复任意次数(包括 0 次)。`repeated` 值的顺序会被保存于 protocol buffer。可以将 repeated 字段想象为动态大小的数组。
|
||||
|
||||
你可以查找关于编写 `.proto` 文件的完整指导——包括所有可能的字段类型——在 [Protocol Buffer Language Guide][6] 里面。不要在这里面查找与类继承相似的特性,因为 protocol buffers 不会做这些。
|
||||
|
||||
> **`required` 是永久性的**
|
||||
|
||||
>在把一个字段标识为 `required` 的时候,你应该特别小心。如果在某些情况下你不想写入或者发送一个 `required` 的字段,那么将该字段更改为 `optional` 可能会遇到问题——旧版本的读者(LCTT 译注:即读取、解析旧版本 Protocol Buffer 消息的一方)会认为不含该字段的消息是不完整的,从而有可能会拒绝解析。在这种情况下,你应该考虑编写特别针对于应用程序的、自定义的消息校验函数。Google 的一些工程师得出了一个结论:使用 `required` 弊多于利;他们更愿意使用 `optional` 和 `repeated` 而不是 `required`。当然,这个观点并不具有普遍性。
|
||||
|
||||
### 编译你的 Protocol Buffers
|
||||
|
||||
既然你有了一个 `.proto`,那你需要做的下一件事就是生成一个将用于读写 `AddressBook` 消息的类(从而包括 `Person` 和 `PhoneNumber`)。为了做到这样,你需要在你的 `.proto` 上运行 protocol buffer 编译器 `protoc`:
|
||||
|
||||
1. 如果你没有安装编译器,请[下载这个包][4],并按照 README 中的指令进行安装。
|
||||
2. 现在运行编译器,指定源目录(你的应用程序源代码位于哪里——如果你没有提供任何值,将使用当前目录)、目标目录(你想要生成的代码放在哪里;常与 `$SRC_DIR` 相同),以及你的 `.proto` 路径。在此示例中:
|
||||
|
||||
```
|
||||
protoc -I=$SRC_DIR --cpp_out=$DST_DIR $SRC_DIR/addressbook.proto
|
||||
```
|
||||
|
||||
因为你想要 C++ 的类,所以你使用了 `--cpp_out` 选项——也为其他支持的语言提供了类似选项。
|
||||
|
||||
在你指定的目标文件夹,将生成以下的文件:
|
||||
|
||||
* `addressbook.pb.h`,声明你生成类的头文件。
|
||||
* `addressbook.pb.cc`,包含你的类的实现。
|
||||
|
||||
### Protocol Buffer API
|
||||
|
||||
让我们看看生成的一些代码,了解一下编译器为你创建了什么类和函数。如果你查看 `addressbook.pb.h`,你可以看到有一个在 `addressbook.proto` 中指定所有消息的类。关注 `Person` 类,可以看到编译器为每个字段生成了读写函数(accessors)。例如,对于 `name`、`id`、`email` 和 `phone` 字段,有下面这些方法:(LCTT 译注:此处原文所指文件名有误,径该之。)
|
||||
|
||||
```c++
|
||||
// name
|
||||
inline bool has_name() const;
|
||||
inline void clear_name();
|
||||
inline const ::std::string& name() const;
|
||||
inline void set_name(const ::std::string& value);
|
||||
inline void set_name(const char* value);
|
||||
inline ::std::string* mutable_name();
|
||||
|
||||
// id
|
||||
inline bool has_id() const;
|
||||
inline void clear_id();
|
||||
inline int32_t id() const;
|
||||
inline void set_id(int32_t value);
|
||||
|
||||
// email
|
||||
inline bool has_email() const;
|
||||
inline void clear_email();
|
||||
inline const ::std::string& email() const;
|
||||
inline void set_email(const ::std::string& value);
|
||||
inline void set_email(const char* value);
|
||||
inline ::std::string* mutable_email();
|
||||
|
||||
// phone
|
||||
inline int phone_size() const;
|
||||
inline void clear_phone();
|
||||
inline const ::google::protobuf::RepeatedPtrField< ::tutorial::Person_PhoneNumber >& phone() const;
|
||||
inline ::google::protobuf::RepeatedPtrField< ::tutorial::Person_PhoneNumber >* mutable_phone();
|
||||
inline const ::tutorial::Person_PhoneNumber& phone(int index) const;
|
||||
inline ::tutorial::Person_PhoneNumber* mutable_phone(int index);
|
||||
inline ::tutorial::Person_PhoneNumber* add_phone();
|
||||
```
|
||||
|
||||
正如你所见到,getters 的名字与字段的小写名字完全一样,并且 setter 方法以 set_ 开头。同时每个单一(singular)(`required` 或 `optional`)字段都有 `has_` 方法,该方法在字段被设置了值的情况下返回 true。最后,所有字段都有一个 `clear_` 方法,用以清除字段到空(empty)状态。
|
||||
|
||||
数字型的 `id` 字段仅有上述的基本读写函数集合(accessors),而 `name` 和 `email` 字段有两个额外的方法,因为它们是字符串——一个是可以获得字符串直接指针的`mutable_` 的 getter ,另一个为额外的 setter。注意,尽管 `email` 还没被设置(set),你也可以调用 `mutable_email`;因为 `email` 会被自动地初始化为空字符串。在本例中,如果你有一个单一的(`required` 或 `optional`)消息字段,它会有一个 `mutable_` 方法,而没有 `set_` 方法。
|
||||
|
||||
`repeated` 字段也有一些特殊的方法——如果你看看 `repeated` 的 `phone` 字段的方法,你可以看到:
|
||||
|
||||
* 检查 `repeated` 字段的 `_size`(也就是说,与 `Person` 相关的电话号码的个数)
|
||||
* 使用下标取得特定的电话号码
|
||||
* 更新特定下标的电话号码
|
||||
* 添加新的电话号码到消息中,之后你便可以编辑。(`repeated` 标量类型有一个 `add_` 方法,用于传入新的值)
|
||||
|
||||
为了获取 protocol 编译器为所有字段定义生成的方法的信息,可以查看 [C++ generated code reference][5]。
|
||||
|
||||
#### 枚举和嵌套类
|
||||
|
||||
与 `.proto` 的枚举相对应,生成的代码包含了一个 `PhoneType` 枚举。你可以通过 `Person::PhoneType` 引用这个类型,通过 `Person::MOBILE`、`Person::HOME` 和 `Person::WORK` 引用它的值。(实现细节有点复杂,但是你无须了解它们而可以直接使用)
|
||||
|
||||
编译器也生成了一个 `Person::PhoneNumber` 的嵌套类。如果你查看代码,你可以发现真正的类型为 `Person_PhoneNumber`,但它通过在 `Person` 内部使用 `typedef` 定义,使你可以把 `Person_PhoneNumber` 当成嵌套类。唯一产生影响的一个例子是,如果你想要在其他文件前置声明该类——在 C++ 中你不能前置声明嵌套类,但是你可以前置声明 `Person_PhoneNumber`。
|
||||
|
||||
#### 标准的消息方法
|
||||
|
||||
所有的消息方法都包含了许多别的方法,用于检查和操作整个消息,包括:
|
||||
|
||||
* `bool IsInitialized() const;` :检查是否所有 `required` 字段已经被设置。
|
||||
* `string DebugString() const;` :返回人类可读的消息表示,对调试特别有用。
|
||||
* `void CopyFrom(const Person& from);`:使用给定的值重写消息。
|
||||
* `void Clear();`:清除所有元素为空(empty)的状态。
|
||||
|
||||
上面这些方法以及下一节要讲的 I/O 方法实现了被所有 C++ protocol buffer 类共享的消息(Message)接口。为了获取更多信息,请查看 [complete API documentation for Message][7]。
|
||||
|
||||
#### 解析和序列化
|
||||
|
||||
最后,所有 protocol buffer 类都有读写你选定类型消息的方法,这些方法使用了特定的 protocol buffer [二进制格式][8]。这些方法包括:
|
||||
|
||||
* `bool SerializeToString(string* output) const;`:序列化消息并将消息字节数据存储在给定的字符串中。注意,字节数据是二进制格式的,而不是文本格式;我们只使用 `string` 类作为合适的容器。
|
||||
* `bool ParseFromString(const string& data);`:从给定的字符创解析消息。
|
||||
* `bool SerializeToOstream(ostream* output) const;`:将消息写到给定的 C++ `ostream`。
|
||||
* `bool ParseFromIstream(istream* input);`:从给定的 C++ `istream` 解析消息。
|
||||
|
||||
这些只是两个用于解析和序列化的选择。再次说明,可以查看 `Message API reference` 完整的列表。
|
||||
|
||||
> **Protocol Buffers 和面向对象设计**
|
||||
|
||||
> Protocol buffer 类通常只是纯粹的数据存储器(像 C++ 中的结构体);它们在对象模型中并不是一等公民。如果你想向生成的 protocol buffer 类中添加更丰富的行为,最好的方法就是在应用程序中对它进行封装。如果你无权控制 `.proto` 文件的设计的话,封装 protocol buffers 也是一个好主意(例如,你从另一个项目中重用一个 `.proto` 文件)。在那种情况下,你可以用封装类来设计接口,以更好地适应你的应用程序的特定环境:隐藏一些数据和方法,暴露一些便于使用的函数,等等。**但是你绝对不要通过继承生成的类来添加行为。**这样做的话,会破坏其内部机制,并且不是一个好的面向对象的实践。
|
||||
|
||||
### 写消息
|
||||
|
||||
现在我们尝试使用 protocol buffer 类。你的地址簿程序想要做的第一件事是将个人详细信息写入到地址簿文件。为了做到这一点,你需要创建、填充 protocol buffer 类实例,并且将它们写入到一个输出流(output stream)。
|
||||
|
||||
这里的程序可以从文件读取 `AddressBook`,根据用户输入,将新 `Person` 添加到 `AddressBook`,并且再次将新的 `AddressBook` 写回文件。这部分直接调用或引用 protocol buffer 类的代码会以“// pb”标出。
|
||||
|
||||
```c++
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include "addressbook.pb.h" // pb
|
||||
using namespace std;
|
||||
|
||||
// This function fills in a Person message based on user input.
|
||||
void PromptForAddress(tutorial::Person* person) {
|
||||
cout << "Enter person ID number: ";
|
||||
int id;
|
||||
cin >> id;
|
||||
person->set_id(id); // pb
|
||||
cin.ignore(256, '\n');
|
||||
|
||||
cout << "Enter name: ";
|
||||
getline(cin, *person->mutable_name()); // pb
|
||||
|
||||
cout << "Enter email address (blank for none): ";
|
||||
string email;
|
||||
getline(cin, email);
|
||||
if (!email.empty()) { // pb
|
||||
person->set_email(email); // pb
|
||||
}
|
||||
|
||||
while (true) {
|
||||
cout << "Enter a phone number (or leave blank to finish): ";
|
||||
string number;
|
||||
getline(cin, number);
|
||||
if (number.empty()) {
|
||||
break;
|
||||
}
|
||||
|
||||
tutorial::Person::PhoneNumber* phone_number = person->add_phone(); //pb
|
||||
phone_number->set_number(number); // pb
|
||||
|
||||
cout << "Is this a mobile, home, or work phone? ";
|
||||
string type;
|
||||
getline(cin, type);
|
||||
if (type == "mobile") {
|
||||
phone_number->set_type(tutorial::Person::MOBILE); // pb
|
||||
} else if (type == "home") {
|
||||
phone_number->set_type(tutorial::Person::HOME); // pb
|
||||
} else if (type == "work") {
|
||||
phone_number->set_type(tutorial::Person::WORK); // pb
|
||||
} else {
|
||||
cout << "Unknown phone type. Using default." << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Main function: Reads the entire address book from a file,
|
||||
// adds one person based on user input, then writes it back out to the same
|
||||
// file.
|
||||
int main(int argc, char* argv[]) {
|
||||
// Verify that the version of the library that we linked against is
|
||||
// compatible with the version of the headers we compiled against.
|
||||
GOOGLE_PROTOBUF_VERIFY_VERSION; // pb
|
||||
|
||||
if (argc != 2) {
|
||||
cerr << "Usage: " << argv[0] << " ADDRESS_BOOK_FILE" << endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
tutorial::AddressBook address_book; // pb
|
||||
|
||||
{
|
||||
// Read the existing address book.
|
||||
fstream input(argv[1], ios::in | ios::binary);
|
||||
if (!input) {
|
||||
cout << argv[1] << ": File not found. Creating a new file." << endl;
|
||||
} else if (!address_book.ParseFromIstream(&input)) { // pb
|
||||
cerr << "Failed to parse address book." << endl;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// Add an address.
|
||||
PromptForAddress(address_book.add_person()); // pb
|
||||
|
||||
{
|
||||
// Write the new address book back to disk.
|
||||
fstream output(argv[1], ios::out | ios::trunc | ios::binary);
|
||||
if (!address_book.SerializeToOstream(&output)) { // pb
|
||||
cerr << "Failed to write address book." << endl;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// Optional: Delete all global objects allocated by libprotobuf.
|
||||
google::protobuf::ShutdownProtobufLibrary(); // pb
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
注意 `GOOGLE_PROTOBUF_VERIFY_VERSION` 宏。它是一种好的实践——虽然不是严格必须的——在使用 C++ Protocol Buffer 库之前执行该宏。它可以保证避免不小心链接到一个与编译的头文件版本不兼容的库版本。如果被检查出来版本不匹配,程序将会终止。注意,每个 `.pb.cc` 文件在初始化时会自动调用这个宏。
|
||||
|
||||
同时注意在程序最后调用 `ShutdownProtobufLibrary()`。它用于释放 Protocol Buffer 库申请的所有全局对象。对大部分程序,这不是必须的,因为虽然程序只是简单退出,但是 OS 会处理释放程序的所有内存。然而,如果你使用了内存泄漏检测工具,工具要求全部对象都要释放,或者你正在写一个 Protocol Buffer 库,该库可能会被一个进程多次加载和卸载,那么你可能需要强制 Protocol Buffer 清除所有东西。
|
||||
|
||||
### 读取消息
|
||||
|
||||
当然,如果你无法从它获取任何信息,那么这个地址簿没多大用处!这个示例读取上面例子创建的文件,并打印文件里的所有内容。
|
||||
|
||||
```c++
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include "addressbook.pb.h" // pb
|
||||
using namespace std;
|
||||
|
||||
// Iterates though all people in the AddressBook and prints info about them.
|
||||
void ListPeople(const tutorial::AddressBook& address_book) { // pb
|
||||
for (int i = 0; i < address_book.person_size(); i++) { // pb
|
||||
const tutorial::Person& person = address_book.person(i); // pb
|
||||
|
||||
cout << "Person ID: " << person.id() << endl; // pb
|
||||
cout << " Name: " << person.name() << endl; // pb
|
||||
if (person.has_email()) { // pb
|
||||
cout << " E-mail address: " << person.email() << endl; // pb
|
||||
}
|
||||
|
||||
for (int j = 0; j < person.phone_size(); j++) { // pb
|
||||
const tutorial::Person::PhoneNumber& phone_number = person.phone(j); // pb
|
||||
|
||||
switch (phone_number.type()) { // pb
|
||||
case tutorial::Person::MOBILE: // pb
|
||||
cout << " Mobile phone #: ";
|
||||
break;
|
||||
case tutorial::Person::HOME: // pb
|
||||
cout << " Home phone #: ";
|
||||
break;
|
||||
case tutorial::Person::WORK: // pb
|
||||
cout << " Work phone #: ";
|
||||
break;
|
||||
}
|
||||
cout << phone_number.number() << endl; // ob
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Main function: Reads the entire address book from a file and prints all
|
||||
// the information inside.
|
||||
int main(int argc, char* argv[]) {
|
||||
// Verify that the version of the library that we linked against is
|
||||
// compatible with the version of the headers we compiled against.
|
||||
GOOGLE_PROTOBUF_VERIFY_VERSION; // pb
|
||||
|
||||
if (argc != 2) {
|
||||
cerr << "Usage: " << argv[0] << " ADDRESS_BOOK_FILE" << endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
tutorial::AddressBook address_book; // pb
|
||||
|
||||
{
|
||||
// Read the existing address book.
|
||||
fstream input(argv[1], ios::in | ios::binary);
|
||||
if (!address_book.ParseFromIstream(&input)) { // pb
|
||||
cerr << "Failed to parse address book." << endl;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
ListPeople(address_book);
|
||||
|
||||
// Optional: Delete all global objects allocated by libprotobuf.
|
||||
google::protobuf::ShutdownProtobufLibrary(); // pb
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
### 扩展 Protocol Buffer
|
||||
|
||||
或早或晚在你发布了使用 protocol buffer 的代码之后,毫无疑问,你会想要 "改善"
|
||||
protocol buffer 的定义。如果你想要新的 buffers 向后兼容,并且老的 buffers 向前兼容——几乎可以肯定你很渴望这个——这里有一些规则,你需要遵守。在新的 protocol buffer 版本:
|
||||
|
||||
* 你绝不可以修改任何已存在字段的标签数字
|
||||
* 你绝不可以添加或删除任何 `required` 字段
|
||||
* 你可以删除 `optional` 或 `repeated` 字段
|
||||
* 你可以添加新的 `optional` 或 `repeated` 字段,但是你必须使用新的标签数字(也就是说,标签数字在 protocol buffer 中从未使用过,甚至不能是已删除字段的标签数字)。
|
||||
|
||||
(对于上面规则有一些[例外情况][9],但它们很少用到。)
|
||||
|
||||
如果你能遵守这些规则,旧代码则可以欢快地读取新的消息,并且简单地忽略所有新的字段。对于旧代码来说,被删除的 `optional` 字段将会简单地赋予默认值,被删除的 `repeated` 字段会为空。新代码显然可以读取旧消息。然而,请记住新的 `optional` 字段不会呈现在旧消息中,因此你需要显式地使用 `has_` 检查它们是否被设置或者在 `.proto` 文件在标签数字后使用 `[default = value]` 提供一个合理的默认值。如果一个 `optional` 元素没有指定默认值,它将会使用类型特定的默认值:对于字符串,默认值为空字符串;对于布尔值,默认值为 false;对于数字类型,默认类型为 0。注意,如果你添加一个新的 `repeated` 字段,新代码将无法辨别它被留空(left empty)(被新代码)或者从没被设置(被旧代码),因为 `repeated` 字段没有 `has_` 标志。
|
||||
|
||||
### 优化技巧
|
||||
|
||||
C++ Protocol Buffer 库已极度优化过了。但是,恰当的用法能够更多地提高性能。这里是一些技巧,可以帮你从库中挤压出最后一点速度:
|
||||
|
||||
* 尽可能复用消息对象。即使它们被清除掉,消息也会尽量保存所有被分配来重用的内存。因此,如果我们正在处理许多相同类型或一系列相似结构的消息,一个好的办法是重用相同的消息对象,从而减少内存分配的负担。但是,随着时间的流逝,对象可能会膨胀变大,尤其是当你的消息尺寸(LCTT 译注:各消息内容不同,有些消息内容多一些,有些消息内容少一些)不同的时候,或者你偶尔创建了一个比平常大很多的消息的时候。你应该自己通过调用 [SpaceUsed][10] 方法监测消息对象的大小,并在它太大的时候删除它。
|
||||
* 对于在多线程中分配大量小对象的情况,你的操作系统内存分配器可能优化得不够好。你可以尝试使用 google 的 [tcmalloc][11]。
|
||||
|
||||
### 高级用法
|
||||
|
||||
Protocol Buffers 绝不仅用于简单的数据存取以及序列化。请阅读 [C++ API reference][12] 来看看你还能用它来做什么。
|
||||
|
||||
protocol 消息类所提供的一个关键特性就是反射(reflection)。你不需要针对一个特殊的消息类型编写代码,就可以遍历一个消息的字段并操作它们的值。一个使用反射的有用方法是 protocol 消息与其他编码互相转换,比如 XML 或 JSON。反射的一个更高级的用法可能就是可以找出两个相同类型的消息之间的区别,或者开发某种“协议消息的正则表达式”,利用正则表达式,你可以对某种消息内容进行匹配。只要你发挥你的想像力,就有可能将 Protocol Buffers 应用到一个更广泛的、你可能一开始就期望解决的问题范围上。
|
||||
|
||||
反射是由 [Message::Reflection interface][13] 提供的。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://developers.google.com/protocol-buffers/docs/cpptutorial
|
||||
|
||||
作者:[Google][a]
|
||||
译者:[cposture](https://github.com/cposture)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://developers.google.com/protocol-buffers/docs/cpptutorial
|
||||
[1]: https://developers.google.com/protocol-buffers/docs/proto
|
||||
[2]: https://developers.google.com/protocol-buffers/docs/encoding
|
||||
[3]: https://developers.google.com/protocol-buffers/docs/downloads
|
||||
[4]: https://developers.google.com/protocol-buffers/docs/downloads.html
|
||||
[5]: https://developers.google.com/protocol-buffers/docs/reference/cpp-generated
|
||||
[6]: https://developers.google.com/protocol-buffers/docs/proto
|
||||
[7]: https://developers.google.com/protocol-buffers/docs/reference/cpp/google.protobuf.message.html#Message
|
||||
[8]: https://developers.google.com/protocol-buffers/docs/encoding
|
||||
[9]: https://developers.google.com/protocol-buffers/docs/proto#updating
|
||||
[10]: https://developers.google.com/protocol-buffers/docs/reference/cpp/google.protobuf.message.html#Message.SpaceUsed.details
|
||||
[11]: http://code.google.com/p/google-perftools/
|
||||
[12]: https://developers.google.com/protocol-buffers/docs/reference/cpp/index.html
|
||||
[13]: https://developers.google.com/protocol-buffers/docs/reference/cpp/google.protobuf.message.html#Message.Reflection
|
@ -0,0 +1,447 @@
|
||||
新手指南 - 通过 Docker 在 Linux 上托管 .NET Core
|
||||
=====
|
||||
|
||||
这篇文章基于我之前的文章 [.NET Core 入门][1]。首先,我把 RESTful API 从 .NET Core RC1 升级到了 .NET Core 1.0,然后,我增加了对 Docker 的支持并描述了如何在 Linux 生产环境里托管它。
|
||||
|
||||

|
||||
|
||||
我是首次接触 Docker 并且距离成为一名 Linux 高手还有很远的一段路程。因此,这里的很多想法是来自一个新手。
|
||||
|
||||
### 安装
|
||||
|
||||
按照 https://www.microsoft.com/net/core 上的介绍在你的电脑上安装 .NET Core 。这将会同时在 Windows 上安装 dotnet 命令行工具以及最新的 Visual Studio 工具。
|
||||
|
||||
### 源代码
|
||||
|
||||
你可以直接到 [GitHub](https://github.com/niksoper/aspnet5-books/tree/blog-docker) 上找最到最新完整的源代码。
|
||||
|
||||
### 转换到 .NET CORE 1.0
|
||||
|
||||
自然地,当我考虑如何把 API 从 .NET Core RC1 升级到 .NET Core 1.0 时想到的第一个求助的地方就是谷歌搜索。我是按照下面这两条非常全面的指导来进行升级的:
|
||||
|
||||
- [从 DNX 迁移到 .NET Core CLI][2]
|
||||
- [从 ASP.NET 5 RC1 迁移到 ASP.NET Core 1.0][3]
|
||||
|
||||
当你迁移代码的时候,我建议仔细阅读这两篇指导,因为我在没有阅读第一篇指导的情况下又尝试浏览第二篇,结果感到非常迷惑和沮丧。
|
||||
|
||||
我不想描述细节上的改变因为你可以看 GitHub 上的[提交](https://github.com/niksoper/aspnet5-books/commit/b41ad38794c69a70a572be3ffad051fd2d7c53c0)。这儿是我所作改变的总结:
|
||||
|
||||
- 更新 `global.json` 和 `project.json` 上的版本号
|
||||
- 删除 `project.json` 上的废弃章节
|
||||
- 使用轻型 `ControllerBase` 而不是 `Controller`, 因为我不需要与 MVC 视图相关的方法(这是一个可选的改变)。
|
||||
- 从辅助方法中去掉 `Http` 前缀,比如:`HttpNotFound` -> `NotFound`
|
||||
- `LogVerbose` -> `LogTrace`
|
||||
- 名字空间改变: `Microsoft.AspNetCore.*`
|
||||
- 在 `Startup` 中使用 `SetBasePath`(没有它 `appsettings.json` 将不会被发现)
|
||||
- 通过 `WebHostBuilder` 来运行而不是通过 `WebApplication.Run` 来运行
|
||||
- 删除 Serilog(在写文章的时候,它不支持 .NET Core 1.0)
|
||||
|
||||
唯一令我真正头疼的事是需要移动 Serilog。我本可以实现自己的文件记录器,但是我删除了文件记录功能,因为我不想为了这次操作在这件事情上花费精力。
|
||||
|
||||
不幸的是,将有大量的第三方开发者扮演追赶 .NET Core 1.0 的角色,我非常同情他们,因为他们通常在休息时间还坚持工作但却依旧根本无法接近靠拢微软的可用资源。我建议阅读 Travis Illig 的文章 [.NET Core 1.0 发布了,但 Autofac 在哪儿][4]?这是一篇关于第三方开发者观点的文章。
|
||||
|
||||
做了这些改变以后,我可以从 `project.json` 目录恢复、构建并运行 dotnet,可以看到 API 又像以前一样工作了。
|
||||
|
||||
### 通过 Docker 运行
|
||||
|
||||
在我写这篇文章的时候, Docker 只能够在 Linux 系统上工作。在 [Windows](https://docs.docker.com/engine/installation/windows/#/docker-for-windows) 系统和 [OS X](https://docs.docker.com/engine/installation/mac/) 上有 beta 支持 Docker,但是它们都必须依赖于虚拟化技术,因此,我选择把 Ubuntu 14.04 当作虚拟机来运行。如果你还没有安装过 Docker,请按照[指导](https://docs.docker.com/engine/installation/linux/ubuntulinux/)来安装。
|
||||
|
||||
我最近阅读了一些关于 Docker 的东西,但我直到现在还没有真正用它来干任何事。我假设读者还没有关于 Docker 的知识,因此我会解释我所使用的所有命令。
|
||||
|
||||
#### HELLO DOCKER
|
||||
|
||||
在 Ubuntu 上安装好 Docker 之后,我所进行的下一步就是按照 https://www.microsoft.com/net/core#docker 上的介绍来开始运行 .NET Core 和 Docker。
|
||||
|
||||
首先启动一个已安装有 .NET Core 的容器。
|
||||
|
||||
```
|
||||
docker run -it microsoft/dotnet:latest
|
||||
```
|
||||
|
||||
`-it` 选项表示交互,所以你执行这条命令之后,你就处于容器之内了,可以如你所希望的那样执行任何 bash 命令。
|
||||
|
||||
然后我们可以执行下面这五条命令来在 Docker 内部运行起来微软 .NET Core 控制台应用程序示例。
|
||||
|
||||
```
|
||||
mkdir hwapp
|
||||
cd hwapp
|
||||
dotnet new
|
||||
dotnet restore
|
||||
dotnet run
|
||||
```
|
||||
|
||||
你可以通过运行 `exit` 来离开容器,然后运行 `Docker ps -a` 命令,这会显示你创建的那个已经退出的容器。你可以通过上运行命令 `Docker rm <container_name>` 来清除容器。
|
||||
|
||||
#### 挂载源代码
|
||||
|
||||
我的下一步骤是使用和上面相同的 microsoft/dotnet 镜像,但是将为我们的应用程序以[数据卷](https://docs.docker.com/engine/tutorials/dockervolumes/1)的方式挂载上源代码。
|
||||
|
||||
首先签出有相关提交的仓库:
|
||||
|
||||
```
|
||||
git clone https://github.com/niksoper/aspnet5-books.git
|
||||
cd aspnet5-books/src/MvcLibrary
|
||||
git checkout dotnet-core-1.0
|
||||
```
|
||||
|
||||
现在启动一个容器来运行 .NET Core 1.0,并将源代码放在 `/book` 下。注意更改 `/path/to/repo` 这部分文件来匹配你的电脑:
|
||||
|
||||
```
|
||||
docker run -it \
|
||||
-v /path/to/repo/aspnet5-books/src/MvcLibrary:/books \
|
||||
microsoft/dotnet:latest
|
||||
```
|
||||
|
||||
现在你可以在容器中运行应用程序了!
|
||||
|
||||
```
|
||||
cd /books
|
||||
dotnet restore
|
||||
dotnet run
|
||||
```
|
||||
|
||||
作为一个概念性展示这的确很棒,但是我们可不想每次运行一个程序都要考虑如何把源代码安装到容器里。
|
||||
|
||||
#### 增加一个 DOCKERFILE
|
||||
|
||||
我的下一步骤是引入一个 Dockerfile,这可以让应用程序很容易在自己的容器内启动。
|
||||
|
||||
我的 Dockerfile 和 `project.json` 一样位于 `src/MvcLibrary` 目录下,看起来像下面这样:
|
||||
|
||||
|
||||
```
|
||||
FROM microsoft/dotnet:latest
|
||||
|
||||
# 为应用程序源代码创建目录
|
||||
RUN mkdir -p /usr/src/books
|
||||
WORKDIR /usr/src/books
|
||||
|
||||
# 复制源代码并恢复依赖关系
|
||||
|
||||
COPY . /usr/src/books
|
||||
RUN dotnet restore
|
||||
|
||||
# 暴露端口并运行应用程序
|
||||
EXPOSE 5000
|
||||
CMD [ "dotnet", "run" ]
|
||||
```
|
||||
|
||||
严格来说,`RUN mkdir -p /usr/src/books` 命令是不需要的,因为 `COPY` 会自动创建丢失的目录。
|
||||
|
||||
Docker 镜像是按层建立的,我们从包含 .NET Core 的镜像开始,添加另一个从源代码生成应用程序,然后运行这个应用程序的层。
|
||||
|
||||
添加了 Dockerfile 以后,我通过运行下面的命令来生成一个镜像,并使用生成的镜像启动一个容器(确保在和 Dockerfile 相同的目录下进行操作,并且你应该使用自己的用户名)。
|
||||
|
||||
```
|
||||
docker build -t niksoper/netcore-books .
|
||||
docker run -it niksoper/netcore-books
|
||||
```
|
||||
|
||||
你应该看到程序能够和之前一样的运行,不过这一次我们不需要像之前那样安装源代码,因为源代码已经包含在 docker 镜像里面了。
|
||||
|
||||
#### 暴露并发布端口
|
||||
|
||||
这个 API 并不是特别有用,除非我们需要从容器外面和它进行通信。 Docker 已经有了暴露和发布端口的概念,但这是两件完全不同的事。
|
||||
|
||||
据 Docker [官方文档](https://docs.docker.com/engine/reference/builder/#/expose):
|
||||
|
||||
> `EXPOSE` 指令通知 Docker 容器在运行时监听特定的网络端口。`EXPOSE` 指令不能够让容器的端口可被主机访问。要使可被访问,你必须通过 `-p` 标志来发布一个端口范围或者使用 `-P` 标志来发布所有暴露的端口
|
||||
|
||||
`EXPOSE` 指令只是将元数据添加到镜像上,所以你可以如文档中说的认为它是镜像消费者。从技术上讲,我本应该忽略 `EXPOSE 5000` 这行指令,因为我知道 API 正在监听的端口,但把它们留下很有用的,并且值得推荐。
|
||||
|
||||
在这个阶段,我想直接从主机访问这个 API ,因此我需要通过 `-p` 指令来发布这个端口,这将允许请求从主机上的端口 5000 转发到容器上的端口 5000,无论这个端口是不是之前通过 Dockerfile 暴露的。
|
||||
|
||||
```
|
||||
docker run -d -p 5000:5000 niksoper/netcore-books
|
||||
```
|
||||
|
||||
通过 `-d` 指令告诉 docker 在分离模式下运行容器,因此我们不能看到它的输出,但是它依旧会运行并监听端口 5000。你可以通过 `docker ps` 来证实这件事。
|
||||
|
||||
因此,接下来我准备从主机向容器发起一个请求来庆祝一下:
|
||||
|
||||
```
|
||||
curl http://localhost:5000/api/books
|
||||
```
|
||||
|
||||
它不工作。
|
||||
|
||||
重复进行相同 `curl` 请求,我看到了两个错误:要么是 `curl: (56) Recv failure: Connection reset by peer`,要么是 `curl: (52) Empty reply from server`。
|
||||
|
||||
我返回去看 docker run 的[文档](https://docs.docker.com/engine/reference/run/#/expose-incoming-ports),然后再次检查我所使用的 `-p` 选项以及 Dockerfile 中的 `EXPOSE` 指令是否正确。我没有发现任何问题,这让我开始有些沮丧。
|
||||
|
||||
重新振作起来以后,我决定去咨询当地的一个 Scott Logic DevOps 大师 - Dave Wybourn(也在[这篇 Docker Swarm 的文章](http://blog.scottlogic.com/2016/08/30/docker-1-12-swarm-mode-round-robin.html)里提到过),他的团队也曾遇到这个实际问题。这个问题是我没有配置过 [Kestral](https://docs.asp.net/en/latest/fundamentals/servers.html#kestrel),这是一个全新的轻量级、跨平台 web 服务器,用于 .NET Core 。
|
||||
|
||||
默认情况下, Kestrel 会监听 http://localhost:5000。但问题是,这儿的 `localhost` 是一个回路接口。
|
||||
|
||||
据[维基百科](https://en.wikipedia.org/wiki/Localhost):
|
||||
|
||||
> 在计算机网络中,localhost 是一个代表本机的主机名。本地主机可以通过网络回路接口访问在主机上运行的网络服务。通过使用回路接口可以绕过任何硬件网络接口。
|
||||
|
||||
当运行在容器内时这是一个问题,因为 `localhost` 只能够在容器内访问。解决方法是更新 `Startup.cs` 里的 `Main` 方法来配置 Kestral 监听的 URL:
|
||||
|
||||
```
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
var host = new WebHostBuilder()
|
||||
.UseKestrel()
|
||||
.UseContentRoot(Directory.GetCurrentDirectory())
|
||||
.UseUrls("http://*:5000") // 在所有网络接口上监听端口 5000
|
||||
.UseIISIntegration()
|
||||
.UseStartup<Startup>()
|
||||
.Build();
|
||||
|
||||
host.Run();
|
||||
}
|
||||
```
|
||||
|
||||
通过这些额外的配置,我可以重建镜像,并在容器中运行应用程序,它将能够接收来自主机的请求:
|
||||
|
||||
```
|
||||
docker build -t niksoper/netcore-books .
|
||||
docker run -d -p 5000:5000 niksoper/netcore-books
|
||||
curl -i http://localhost:5000/api/books
|
||||
```
|
||||
|
||||
我现在得到下面这些相应:
|
||||
|
||||
```
|
||||
HTTP/1.1 200 OK
|
||||
Date: Tue, 30 Aug 2016 15:25:43 GMT
|
||||
Transfer-Encoding: chunked
|
||||
Content-Type: application/json; charset=utf-8
|
||||
Server: Kestrel
|
||||
|
||||
[{"id":"1","title":"RESTful API with ASP.NET Core MVC 1.0","author":"Nick Soper"}]
|
||||
```
|
||||
|
||||
### 在产品环境中运行 KESTREL
|
||||
|
||||
[微软的介绍](https://docs.asp.net/en/latest/publishing/linuxproduction.html#why-use-a-reverse-proxy-server):
|
||||
|
||||
> Kestrel 可以很好的处理来自 ASP.NET 的动态内容,然而,网络服务部分的特性没有如 IIS,Apache 或者 Nginx 那样的全特性服务器那么好。反向代理服务器可以让你不用去做像处理静态内容、缓存请求、压缩请求、SSL 端点这样的来自 HTTP 服务器的工作。
|
||||
|
||||
因此我需要在我的 Linux 机器上把 Nginx 设置成一个反向代理服务器。微软介绍了如何[发布到 Linux 生产环境下](https://docs.asp.net/en/latest/publishing/linuxproduction.html)的指导教程。我把说明总结在这儿:
|
||||
|
||||
1. 通过 `dotnet publish` 来给应用程序产生一个自包含包。
|
||||
2. 把已发布的应用程序复制到服务器上
|
||||
3. 安装并配置 Nginx(作为反向代理服务器)
|
||||
4. 安装并配置 [supervisor](http://supervisord.org/)(用于确保 Nginx 服务器处于运行状态中)
|
||||
5. 安装并配置 [AppArmor](https://wiki.ubuntu.com/AppArmor)(用于限制应用的资源使用)
|
||||
6. 配置服务器防火墙
|
||||
7. 安全加固 Nginx(从源代码构建和配置 SSL)
|
||||
|
||||
这些内容已经超出了本文的范围,因此我将侧重于如何把 Nginx 配置成一个反向代理服务器。自然地,我通过 Docker 来完成这件事。
|
||||
|
||||
### 在另一个容器中运行 NGINX
|
||||
|
||||
我的目标是在第二个 Docker 容器中运行 Nginx 并把它配置成我们的应用程序容器的反向代理服务器。
|
||||
|
||||
我使用的是[来自 Docker Hub 的官方 Nginx 镜像](https://hub.docker.com/_/nginx/)。首先我尝试这样做:
|
||||
|
||||
```
|
||||
docker run -d -p 8080:80 --name web nginx
|
||||
```
|
||||
|
||||
这启动了一个运行 Nginx 的容器并把主机上的 8080 端口映射到了容器的 80 端口上。现在在浏览器中打开网址 `http://localhost:8080` 会显示出 Nginx 的默认登录页面。
|
||||
|
||||
现在我们证实了运行 Nginx 是多么的简单,我们可以关闭这个容器。
|
||||
|
||||
```
|
||||
docker rm -f web
|
||||
```
|
||||
|
||||
### 把 NGINX 配置成一个反向代理服务器
|
||||
|
||||
可以通过像下面这样编辑位于 `/etc/nginx/conf.d/default.conf` 的配置文件,把 Nginx 配置成一个反向代理服务器:
|
||||
|
||||
```
|
||||
server {
|
||||
listen 80;
|
||||
|
||||
location / {
|
||||
proxy_pass http://localhost:6666;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
通过上面的配置可以让 Nginx 将所有对根目录的访问请求代理到 `http://localhost:6666`。记住这里的 `localhost` 指的是运行 Nginx 的容器。我们可以在 Nginx容器内部利用卷来使用我们自己的配置文件:
|
||||
|
||||
```
|
||||
docker run -d -p 8080:80 \
|
||||
-v /path/to/my.conf:/etc/nginx/conf.d/default.conf \
|
||||
nginx
|
||||
```
|
||||
|
||||
注意:这把一个单一文件从主机映射到容器中,而不是一个完整目录。
|
||||
|
||||
### 在容器间进行通信
|
||||
|
||||
Docker 允许内部容器通过共享虚拟网络进行通信。默认情况下,所有通过 Docker 守护进程启动的容器都可以访问一种叫做“桥”的虚拟网络。这使得一个容器可以被另一个容器在相同的网络上通过 IP 地址和端口来引用。
|
||||
|
||||
你可以通过监测(inspect)容器来找到它的 IP 地址。我将从之前创建的 `niksoper/netcore-books` 镜像中启动一个容器并监测(inspect)它:
|
||||
|
||||
```
|
||||
docker run -d -p 5000:5000 --name books niksoper/netcore-books
|
||||
docker inspect books
|
||||
```
|
||||
|
||||

|
||||
|
||||
我们可以看到这个容器的 IP 地址是 `"IPAddress": "172.17.0.3"`。
|
||||
|
||||
所以现在如果我创建下面的 Nginx 配置文件,并使用这个文件启动一个 Nginx容器, 它将代理请求到我的 API :
|
||||
|
||||
```
|
||||
server {
|
||||
listen 80;
|
||||
|
||||
location / {
|
||||
proxy_pass http://172.17.0.3:5000;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
现在我可以使用这个配置文件启动一个 Nginx 容器(注意我把主机上的 8080 端口映射到了 Nginx 容器上的 80 端口):
|
||||
|
||||
```
|
||||
docker run -d -p 8080:80 \
|
||||
-v ~/dev/nginx/my.nginx.conf:/etc/nginx/conf.d/default.conf \
|
||||
nginx
|
||||
```
|
||||
|
||||
一个到 `http://localhost:8080` 的请求将被代理到应用上。注意下面 `curl` 响应的 `Server` 响应头:
|
||||
|
||||

|
||||
|
||||
### DOCKER COMPOSE
|
||||
|
||||
在这个地方,我为自己的进步而感到高兴,但我认为一定还有更好的方法来配置 Nginx,可以不需要知道应用程序容器的确切 IP 地址。另一个当地的 Scott Logic DevOps 大师 Jason Ebbin 在这个地方进行了改进,并建议使用 [Docker Compose](https://docs.docker.com/compose/)。
|
||||
|
||||
概况描述一下,Docker Compose 使得一组通过声明式语法互相连接的容器很容易启动。我不想再细说 Docker Compose 是如何工作的,因为你可以在[之前的文章](http://blog.scottlogic.com/2016/01/25/playing-with-docker-compose-and-erlang.html)中找到。
|
||||
|
||||
我将通过一个我所使用的 `docker-compose.yml` 文件来启动:
|
||||
|
||||
```
|
||||
version: '2'
|
||||
services:
|
||||
books-service:
|
||||
container_name: books-api
|
||||
build: .
|
||||
|
||||
reverse-proxy:
|
||||
container_name: reverse-proxy
|
||||
image: nginx
|
||||
ports:
|
||||
- "9090:8080"
|
||||
volumes:
|
||||
- ./proxy.conf:/etc/nginx/conf.d/default.conf
|
||||
```
|
||||
|
||||
*这是版本 2 语法,所以为了能够正常工作,你至少需要 1.6 版本的 Docker Compose。*
|
||||
|
||||
这个文件告诉 Docker 创建两个服务:一个是给应用的,另一个是给 Nginx 反向代理服务器的。
|
||||
|
||||
### BOOKS-SERVICE
|
||||
|
||||
这个与 docker-compose.yml 相同目录下的 Dockerfile 构建的容器叫做 `books-api`。注意这个容器不需要发布任何端口,因为只要能够从反向代理服务器访问它就可以,而不需要从主机操作系统访问它。
|
||||
|
||||
### REVERSE-PROXY
|
||||
|
||||
这将基于 nginx 镜像启动一个叫做 `reverse-proxy` 的容器,并将位于当前目录下的 `proxy.conf` 文件挂载为配置。它把主机上的 9090 端口映射到容器中的 8080 端口,这将允许我们在 `http://localhost:9090` 上通过主机访问容器。
|
||||
|
||||
`proxy.conf` 文件看起来像下面这样:
|
||||
|
||||
```
|
||||
server {
|
||||
listen 8080;
|
||||
|
||||
location / {
|
||||
proxy_pass http://books-service:5000;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
这儿的关键点是我们现在可以通过名字引用 `books-service`,因此我们不需要知道 `books-api` 这个容器的 IP 地址!
|
||||
|
||||
现在我们可以通过一个运行着的反向代理启动两个容器(`-d` 意味着这是独立的,因此我们不能看到来自容器的输出):
|
||||
|
||||
```
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
验证我们所创建的容器:
|
||||
|
||||
```
|
||||
docker ps
|
||||
```
|
||||
|
||||
最后来验证我们可以通过反向代理来控制该 API :
|
||||
|
||||
```
|
||||
curl -i http://localhost:9090/api/books
|
||||
```
|
||||
|
||||
### 怎么做到的?
|
||||
|
||||
Docker Compose 通过创建一个新的叫做 `mvclibrary_default` 的虚拟网络来实现这件事,这个虚拟网络同时用于 `books-api` 和 `reverse-proxy` 容器(名字是基于 `docker-compose.yml` 文件的父目录)。
|
||||
|
||||
通过 `docker network ls` 来验证网络已经存在:
|
||||
|
||||

|
||||
|
||||
你可以使用 `docker network inspect mvclibrary_default` 来看到新的网络的细节:
|
||||
|
||||

|
||||
|
||||
注意 Docker 已经给网络分配了子网:`"Subnet": "172.18.0.0/16"`。/16 部分是无类域内路由选择(CIDR),完整的解释已经超出了本文的范围,但 CIDR 只是表示 IP 地址范围。运行 `docker network inspect bridge` 显示子网:`"Subnet": "172.17.0.0/16"`,因此这两个网络是不重叠的。
|
||||
|
||||
现在用 `docker inspect books-api` 来确认应用程序的容器正在使用该网络:
|
||||
|
||||

|
||||
|
||||
注意容器的两个别名(`"Aliases"`)是容器标识符(`3c42db680459`)和由 `docker-compose.yml` 给出的服务名(`books-service`)。我们通过 `books-service` 别名在自定义 Nginx 配置文件中来引用应用程序的容器。这本可以通过 `docker network create` 手动创建,但是我喜欢用 Docker Compose,因为它可以干净简洁地将容器创建和依存捆绑在一起。
|
||||
|
||||
### 结论
|
||||
|
||||
所以现在我可以通过几个简单的步骤在 Linux 系统上用 Nginx 运行应用程序,不需要对主机操作系统做任何长期的改变:
|
||||
|
||||
```
|
||||
git clone https://github.com/niksoper/aspnet5-books.git
|
||||
cd aspnet5-books/src/MvcLibrary
|
||||
git checkout blog-docker
|
||||
docker-compose up -d
|
||||
curl -i http://localhost:9090/api/books
|
||||
```
|
||||
|
||||
我知道我在这篇文章中所写的内容不是一个真正的生产环境就绪的设备,因为我没有写任何有关下面这些的内容,绝大多数下面的这些主题都需要用单独一篇完整的文章来叙述。
|
||||
|
||||
- 安全考虑比如防火墙和 SSL 配置
|
||||
- 如何确保应用程序保持运行状态
|
||||
- 如何选择需要包含的 Docker 镜像(我把所有的都放入了 Dockerfile 中)
|
||||
- 数据库 - 如何在容器中管理它们
|
||||
|
||||
对我来说这是一个非常有趣的学习经历,因为有一段时间我对探索 ASP.NET Core 的跨平台支持非常好奇,使用 “Configuratin as Code” 的 Docker Compose 方法来探索一下 DevOps 的世界也是非常愉快并且很有教育意义的。
|
||||
|
||||
如果你对 Docker 很好奇,那么我鼓励你来尝试学习它 或许这会让你离开舒适区,不过,有可能你会喜欢它?
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: http://blog.scottlogic.com/2016/09/05/hosting-netcore-on-linux-with-docker.html
|
||||
|
||||
作者:[Nick Soper][a]
|
||||
译者:[ucasFL](https://github.com/ucasFL)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: http://blog.scottlogic.com/nsoper
|
||||
[1]: http://blog.scottlogic.com/2016/01/20/restful-api-with-aspnet50.html
|
||||
[2]: https://docs.microsoft.com/en-us/dotnet/articles/core/migrating-from-dnx
|
||||
[3]: https://docs.asp.net/en/latest/migration/rc1-to-rtm.html
|
||||
[4]: http://www.paraesthesia.com/archive/2016/06/29/netcore-rtm-where-is-autofac/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1,13 +1,13 @@
|
||||
Adobe 的新任首席信息官(CIO)股份领导对于开始一个新职位的忠告
|
||||
Adobe 的新任首席信息官(CIO)对于开始一个新领导职位的建议
|
||||
====
|
||||
|
||||

|
||||
|
||||
我目前的几个月在一家十分受人尊敬的基于云的技术公司担任新的 CIO 一职。我的首要任务之一就是熟悉组织的人、文化和当务之急的事件。
|
||||
|
||||
作为这一目标的一部分,我访问了所有主要的网站。而在印度,上任不到两个月时,我被问道:“你打算做什么?你的计划是什么?” 我回答道,这个问题不会让经验丰富的 CIOs 感到吃惊,我现在仍然处于探索模式,我在做的主要是聆听和学习。
|
||||
作为这一目标的一部分,我访问了所有主要的网站。而在印度,上任不到两个月时,我被问道:“你打算做什么?你的计划是什么?” 我回答道,这个问题不会让经验丰富的 CIO 们感到吃惊:我现在仍然处于探索模式,我在做的主要是聆听和学习。
|
||||
|
||||
我从来没有在入职时制定一份蓝图说我要做什么。我知道一些 CIOs 拥有一本关于他要怎么做的”剧本“。他会煽动整个组织将他的计划付诸行动。
|
||||
我从来没有在入职时制定一份蓝图说我要做什么。我知道一些 CIO 们拥有一本关于他要怎么做的”剧本“。他会煽动整个组织将他的计划付诸行动。
|
||||
|
||||
是的,在有些地方是完全崩坏了并无法发挥作用的情况下,这种行动可能是有意义的。但是,当我进入到一个公司时,我的策略是先开始一个探索的过程。我不想带入任何先入为主的观念,比如什么事应该是什么样子的,哪些工作和哪些是有冲突的,而哪些不是。
|
||||
|
||||
@ -25,13 +25,13 @@ Adobe 的新任首席信息官(CIO)股份领导对于开始一个新职位
|
||||
|
||||
### 了解客户
|
||||
|
||||
从很早开始,我们就收到客户的会面请求。与客户会面是一种很好的方式来启发你对 IT 机构未来的的思考,包括各种我们可以改进的地方,如技术、客户和消费者
|
||||
从很早开始,我们就收到客户的会面请求。与客户会面是一种很好的方式来启发你对 IT 机构未来的的思考,包括各种我们可以改进的地方,如技术、客户和消费者。
|
||||
|
||||
### 对未来的计划
|
||||
|
||||
作为一个新上任的领导者,我有一个全新的视角用以考虑组织的未来,而不会有挑战和障碍来干扰我。
|
||||
|
||||
CIOs 所需要做的就是推动 IT 进化到下一代。当我会见我的员工是,我问他们我们可以开始定位我们三到五年后的未来。这意味着开始讨论方案和当务之急的事。
|
||||
CIO 们所需要做的就是推动 IT 进化到下一代。当我会见我的员工时,我问他们我们三到五年后的未来可以做什么,以便我们可以开始尽早定位。这意味着开始讨论方案和当务之急的事。
|
||||
|
||||
从那以后,它使领导小组团结在一起,所以我们能够共同来组建我们的下一代体系——它的使命、愿景、组织模式和操作规范。如果你开始从内而外的改变,那么它会渗透到业务和其他你所做的一切事情上。
|
||||
|
||||
@ -43,7 +43,7 @@ via: https://enterprisersproject.com/article/2016/9/adobes-new-cio-shares-leader
|
||||
|
||||
作者:[Cynthia Stoddard][a]
|
||||
译者:[Chao-zhi](https://github.com/Chao-zhi)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
@ -0,0 +1,51 @@
|
||||
拥有开源项目部门的公司可以从四个方面获益
|
||||
====
|
||||
|
||||

|
||||
|
||||
在我的第一篇关于开源项目部门(program office)的系列文章中,我深入剖析了[什么是开源项目部门,为什么你的公司需要一个开源项目部门][1]。接着我又说到了[谷歌是如何创建一种新的开源项目部门的][2]。而这篇文章,我将阐述拥有一个开源项目部门的好处。
|
||||
|
||||
乍一看,非软件开发公司会更加热情的去拥抱开源项目部门的一个重要原因是他们并没有什么损失。毕竟,他们并不需要依靠这些软件产品来获得收益。比如,Facebook 可以很轻易的释放出一个 “分布式键值数据存储” 作为开源项目,是因为他们并没有售卖一个叫做 “企业级键值数据存储” 的产品。这回答了关于风险的问题,但是并没有回答他们如何通过向开源生态共献代码而获益的问题。让我们逐个来推测和探讨其中可能的原因。你会发现开源项目供应商的许多动机都是相同的,但是也有些许不同。
|
||||
|
||||
### 招聘
|
||||
|
||||
招聘可能是一个将开源项目部门推销给上层管理部门的最容易方法。向他们展示与招聘相关的成本,以及投资回报率,然后解释如何与天才工程师发展关系,从而与那些对这些项目感兴趣并且十分乐意在其中工作的天才开发者们建立联系。不需要我多说了,你懂的!
|
||||
|
||||
### 技术影响
|
||||
|
||||
曾几何时,那些没有专门从事软件销售的公司是难以直接对他们软件供应商的开发周期施加影响力的,尤其当他们并不是一个大客户时。开源完全改变了这一点,它将用户与供应商放在了一个更公平的竞争环境中。随着开源开发的兴起,任何人,假如他们愿意投入时间和资源的话,都可以将技术推向一个选定的方向。但是这些公司发现,虽然将投资用于开发上会带来丰硕的成果,但是总体战略的努力却更加有效——对比一下 bug 的修复和软件的构建——大多数公司都将 bug 的修复推给上游的开源项目,但是一些公司开始认识到通过更深层次的回报承诺和更快的功能开发来协调持久的工作,将会更有利于业务。通过开源项目部门模式,公司的职员能够从开源社区中准确嗅出战略重心,然后投入开发资源。
|
||||
|
||||
对于快速增长的公司,如 Google 和 Facebook,其对现有的开源项目提供的领导力仍然不足以满足业务的膨胀。面对激烈的增长和建立超大规模系统所带来的挑战,许多大型企业开始构建仅供内部使用的高度定制的软件栈。除非他们能说服别人在一些基础设施项目上达成合作。因此,虽然他们保持在诸如 Linux 内核,Apache 和其他现有项目领域的投资,他们也开始推出自己的大型项目。Facebook 发布了 Cassandra,Twitter 创造了 Mesos,并且甚至谷歌也创建了 Kubernetes 项目。这些项目已成为行业创新的主要平台,证实了该举措是相关公司引人注目的成功。(请注意,Facebook 在它需要创造一个新软件项目来解决更大规模的问题之后,已经在内部停止使用 Cassandra 了,但是,这时 Cassandra 已经变得流行,而 DataStax 公司接过了开发任务)。所有这些项目已经促使了开发商、相关的项目、以及最终用户构成的整个生态加速增长和发展。
|
||||
|
||||
没有与公司战略举措取得一致的开源项目部门不可能成功的。不这样做的话,这些公司依然会试图单独地解决这些问题,而且更慢。不仅拥有这些项目可以帮助内部解决业务问题,它们也帮助这些公司逐渐成为行业巨头。当然,谷歌成为行业巨头好多年了,但是 Kubernetes 的发展确保了软件的质量,并且在容器技术未来的发展方向上有着直接的话语权,并且远超之前就有的话语权。这些公司目前还是闻名于他们超大规模的基础设施和硅谷的中坚份子。鲜为人知,但是更为重要的是它们与技术生产人员的亲密度。开源项目部门凭借技术建议和与有影响力的开发者的关系,再加上在社区治理和人员管理方面深厚的专业知识来引领这些工作,并最大限度地发挥其影响力,
|
||||
|
||||
### 市场营销能力
|
||||
|
||||
与技术的影响齐头并进的是每个公司谈论他们在开源方面的努力。通过传播这些与项目和社区有关的消息,一个开源项目部门能够通过有针对性的营销活动来提供最大的影响。营销在开放源码领域一直是一个肮脏的词汇,因为每个人都有一个由企业营销造成的糟糕的经历。在开源社区中,营销呈现出一种与传统方法截然不同的形式,它会更注重于我们的社区已经在战略方向上做了什么。因此,一个开源项目部门不可能去宣传一些根本还没有发布任何代码的项目,但是他们会讨论他们创造什么软件和参与了其他什么举措。基本上,不会有“雾件(vaporware)”。
|
||||
|
||||
想想谷歌的开源项目部门作出的第一份工作。他们不只是简单的贡献代码给 Linux 内核或其他项目,他们更多的是谈论它,并经常在开源会议主题演讲。他们不仅仅是把钱给写开源代码的代码的学生,他们还创建了一个全球计划——“Google Summer of Code”,现在已经成为一种开源发展的文化试金石。这些市场营销的作用在 Kubernetes 开发完成之前就奠定了谷歌在开源世界巨头的地位。最终使得,谷歌在创建 GPLv3 授权协议期间拥有重要影响力,并且在科技活动中公司的发言人和开源项目部门的代表人成为了主要人物。开源项目部门是协调这些工作的最好的实体,并可以为母公司提供真正的价值。
|
||||
|
||||
###改善内部流程
|
||||
|
||||
改善内部流程听起来不像一个大好处,但克服混乱的内部流程对于每一个开源项目部门都是一个挑战,不论是对软件供应商还是公司内的部门。而软件供应商必须确保他们的流程不与他们发布的产品重叠(例如,不小心开源了他们的商业售卖软件),用户更关心的是侵犯了知识产权(IP)法:专利、版权和商标。没有人想只是因为释放软件而被起诉。没有一个活跃的开源项目部门去管理和协调这些许可和其他法律问题的话,大公司在开源流程和管理上会面临着巨大的困难。为什么这个很重要呢?如果不同的团队释放的软件是在不兼容的许可证下,那么这不仅是一个坑爹的尴尬,它还将对实现最基本的目标改良协作产生巨大的障碍。
|
||||
|
||||
考虑到还有许多这样的公司仍在飞快的增长,如果无法建立基本流程规则的话,将可以预见到它们将会遇到阻力。我见过一个罗列着批准、未经批准的许可证的巨大的电子表格,以及指导如何(或如何不)创建开源社区而遵守法律限制。关键是当开发者需要做出决定时要有一个可以依据的东西,并且每次当开发人员想要为一个开源社区贡献代码时,可以不产生大量的法律开销,和效率低下的知识产权检查。
|
||||
|
||||
有一个活跃的开放源码项目部门,负责维护许可规则和源的贡献,以及建立培训项目工程师,有助于避免潜在的法律缺陷和昂贵的诉讼。毕竟,良好的开源项目合作可以减少由于某人没有看许可证而导致公司赔钱这样的事件。好消息是,公司已经可以较少的担心关于专有的知识产权与软件供应商冲突的事。坏消息是,它们的法律问题不够复杂,尤其是当他们需要直接面对软件供应商的阻力时。
|
||||
|
||||
你的组织是如何受益于拥有一个开源项目部门的?可以在评论中与我们分享。
|
||||
|
||||
本文作者 John Mark Walker 是 Dell EMC 的产品管理总监,负责管理 ViPR 控制器产品及 CoprHD 开源社区。他领导过包括 ManageIQ 在内的许多开源社区。
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/business/16/9/4-big-ways-companies-benefit-having-open-source-program-offices
|
||||
|
||||
作者:[John Mark Walker][a]
|
||||
译者:[chao-zhi](https://github.com/chao-zhi)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/johnmark
|
||||
[1]: https://opensource.com/business/16/5/whats-open-source-program-office
|
||||
[2]: https://opensource.com/business/16/8/google-open-source-program-office
|
92
published/201611/20160914 Down and dirty with Windows Nano Server 2016.md
Executable file
92
published/201611/20160914 Down and dirty with Windows Nano Server 2016.md
Executable file
@ -0,0 +1,92 @@
|
||||
一起来看看 Windows Nano Server 2016
|
||||
====
|
||||
|
||||

|
||||
|
||||
> 对于远程 Windows 服务器管理,Nano Server 是快速的功能强大的工具,但是你需要知道你在做的是什么。
|
||||
|
||||
下面谈论[即将到来的 Windows Server 2016 的 Nano 版本][1],带远程管理和命令行设计,考虑到了私有云和数据中心。但是,谈论它和动手用它区别还是很大的,让我们深入看下去。
|
||||
|
||||
没有本地登录,且所有的程序、工具和代理都是 64 位,安装升级快捷,只需要非常少的时间就能重启。它非常适合做计算节点(无论在不在集群)、存储主机、DNS 服务器、IIS web 服务器,以及在容器中提供主机服务或者虚拟化的客户操作系统。
|
||||
|
||||
Nano 服务器也并不是太好玩的,你必须知道你要完成什么。你会看着远程的 PowerShell 的连接而不知所措,但如果你知道你要做什么的话,那它就非常方便和强大。
|
||||
|
||||
微软为设置 Nano 服务器提供了一个[快速入门手册][2] ,在这我给大家具体展示一下。
|
||||
|
||||
首先,你必须创建一个 .vhd 格式的虚拟磁盘文件。在步骤一中,我有几个文件不在正确的位置的小问题,Powershell 总是提示不匹配,所以我不得不反复查找文件的位置方便我可以用 ISO 信息(需要把它拷贝粘贴到你要创建 .vhd 文件的服务器上)。当你所有的东西都位置正确了,你可以开始创建 .vhd 文件的步骤了。
|
||||
|
||||

|
||||
|
||||
*步骤一:尝试运行 New-NanoServerImage 脚本时,很多文件路径错误,我把文件位置的问题搞定后,就能进行下去创建 .vhd 文件了(如图所示)*
|
||||
|
||||
接下来,你可以用创建 VM 向导在 Hyper-V 里面创建 VM 虚拟机,你需要指定一个存在的虚拟磁盘同时指向你新创建的 .vhd 文件。(步骤二)
|
||||
|
||||

|
||||
|
||||
*步骤二:连接虚拟磁盘(一开始创建的)*
|
||||
|
||||
当你启动 Nano 服务器的时候,你或许会发现有内存错误,提示你已经分配了多少内存,如果你还有其他 VM 虚拟机的话, Hyper-V 服务器剩余了多少内存。我已经关闭了一些虚机以增加可用内存,因为微软说 Nano 服务器最少需要 512M 内存,但是它又推荐你至少 800M,最后我分配了 8G 内存因为我给它 1G 的时候根本不能用,为了方便,我也没有尝试其他的内存配置。
|
||||
|
||||
最后我终于到达登录界面,到达 Nano Server Recovery Console 界面(步骤三),Nano 服务器的基本命令界面。
|
||||
|
||||

|
||||
|
||||
*步骤三:Nano 服务器的恢复窗口*
|
||||
|
||||
本来我以为进到这里会很美好,但是当我弄明白几个细节(如何加入域,弹出个磁盘,添加用户),我明白一些配置的细节,用几个参数运行 New-NanoServerImage cmdlet 会变得很简单。
|
||||
|
||||
然而,当你的服务器运行时,也有办法确认它的状态,就像步骤四所示,这一切都始于一个远程 PowerShell 连接。
|
||||
|
||||

|
||||
|
||||
*步骤四:从 Nano 服务器恢复窗口得到的信息,你可以从远程运行一个 Powershell 连接。*
|
||||
|
||||
微软展示了如何创建连接,但是尝试了四个不同的方法,我发现 [MSDN][4] 提供的是最好的方式,步骤五展示。
|
||||
|
||||

|
||||
|
||||
*步骤五:创建到 Nano 服务器的 PowerShell 远程连接*
|
||||
|
||||
提示:创建远程连接,你可以用下面这条命令:
|
||||
|
||||
```
|
||||
Enter-PSSession –ComputerName "192.168.0.100"-Credential ~\Administrator.
|
||||
```
|
||||
|
||||
如果你提前知道这台服务器将要做 DNS 服务器或者集群中的一个计算节点,可以事先在 .vhd 文件中加入一些角色和特定的软件包。如果不太清楚,你可以先建立 PowerShell 连接,然后安装 NanoServerPackage 并导入它,你就可以用 Find-NanoServerPackage 命令来查找你要部署的软件包了(步骤六)。
|
||||
|
||||

|
||||
|
||||
*步骤六:你安装完并导入 NanoServerPackage 后,你可以找到你需要启动服务器的工具以及设置的用户和你需要的一些其他功能包。*
|
||||
|
||||
我测试了安装 DNS 安装包,用 `Install-NanoServerPackage –Name Microsoft-NanoServer-DNS-Package` 这个命令。安装好后,我用 `Enable-WindowsOptionalFeature –Online –FeatureName DNS-Server-Full-Role` 命令启用它。
|
||||
|
||||
之前我并不知道这些命令,之前也从来没运行过,也没有弄过 DNS,但是现在稍微研究一下我就能用 Nano 服务器建立一个 DNS 服务并且运行它。
|
||||
|
||||
接下来是用 PowerShell 来配置 DNS 服务器。这个复杂一些,需要网上研究一下。但是它也不是那么复杂,当你学习了使用 cmdlet ,就可以用 `Add-DNSServerPrimaryZone` 添加 zone,用 `Add-DNSServerResourceRecordA` 命令在 zone 中添加记录。
|
||||
|
||||
做完这些命令行的工作,你可能需要验证是否起效。你可以快速浏览一下 PowerShell 命令,没有太多的 DNS 命令(使用 `Get-Command` 命令)。
|
||||
|
||||
如果你需要一个图形化的配置,你可以从一个图形化的主机上用图形管理器打开 Nano 服务器的 IP 地址。右击需要管理的服务器,提供你的验证信息,你连接好后,在图形管理器中右击然后选择 Add Roles and Features,它会显示你安装好的 DNS 服务,如步骤七所示。
|
||||
|
||||

|
||||
|
||||
*步骤七:通过图形化界面验证 DNS 已经安装*
|
||||
|
||||
不用麻烦登录服务器的远程桌面,你可以用服务器管理工具来进行操作。当然你能验证 DNS 角色不代表你能够通过 GUI 添加新的角色和特性,它有命令行就足够了。你现在可以用 Nano 服务器做一些需要的调整了。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: http://www.infoworld.com/article/3119770/windows-server/down-and-dirty-with-windows-nano-server-2016.html
|
||||
|
||||
作者:[J. Peter Bruzzese][a]
|
||||
译者:[jiajia9linuxer](https://github.com/jiajia9linuxer)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: http://www.infoworld.com/author/J.-Peter-Bruzzese/
|
||||
[1]: http://www.infoworld.com/article/3049191/windows-server/nano-server-a-slimmer-slicker-windows-server-core.html
|
||||
[2]: https://technet.microsoft.com/en-us/windows-server-docs/compute/nano-server/getting-started-with-nano-server
|
||||
[3]: https://technet.microsoft.com/en-us/windows-server-docs/get-started/system-requirements--and-installation
|
||||
[4]: https://msdn.microsoft.com/en-us/library/mt708805(v=vs.85).aspx
|
@ -0,0 +1,57 @@
|
||||
宽松开源许可证的崛起意味着什么
|
||||
====
|
||||
|
||||
为什么像 GNU GPL 这样的限制性许可证越来越不受青睐。
|
||||
|
||||
“如果你用了任何开源软件, 那么你软件的其他部分也必须开源。” 这是微软前 CEO 巴尔默 2001 年说的, 尽管他说的不对, 还是引发了人们对自由软件的 FUD (恐惧, 不确定和怀疑(fear, uncertainty and doubt))。 大概这才是他的意图。
|
||||
|
||||
对开源软件的这些 FUD 主要与开源许可有关。 现在有许多不同的许可证, 当中有些限制比其他的更严格(也有人称“更具保护性”)。 诸如 GNU 通用公共许可证 (GPL) 这样的限制性许可证使用了 copyleft 的概念。 copyleft 赋予人们自由发布软件副本和修改版的权力, 只要衍生工作保留同样的权力。 bash 和 GIMP 等开源项目就是使用了 GPL(v3)。 还有一个 AGPL( Affero GPL) 许可证, 它为网络上的软件(如 web service)提供了 copyleft 许可。
|
||||
|
||||
这意味着, 如果你使用了这种许可的代码, 然后加入了你自己的专有代码, 那么在一些情况下, 整个代码, 包括你的代码也就遵从这种限制性开源许可证。 Ballmer 说的大概就是这类的许可证。
|
||||
|
||||
但宽松许可证不同。 比如, 只要保留版权声明和许可声明且不要求开发者承担责任, MIT 许可证允许任何人任意使用开源代码, 包括修改和出售。 另一个比较流行的宽松开源许可证是 Apache 许可证 2.0,它还包含了贡献者向用户提供专利授权相关的条款。 使用 MIT 许可证的有 JQuery、.NET Core 和 Rails , 使用 Apache 许可证 2.0 的软件包括安卓, Apache 和 Swift。
|
||||
|
||||
两种许可证类型最终都是为了让软件更有用。 限制性许可证促进了参与和分享的开源理念, 使每一个人都能从软件中得到最大化的利益。 而宽松许可证通过允许人们任意使用软件来确保人们能从软件中得到最多的利益, 即使这意味着他们可以使用代码, 修改它, 据为己有,甚至以专有软件出售,而不做任何回报。
|
||||
|
||||
开源许可证管理公司黑鸭子软件的数据显示, 去年使用最多的开源许可证是限制性许可证 GPL 2.0,份额大约 25%。 宽松许可证 MIT 和 Apache 2.0 次之, 份额分别为 18% 和 16%, 再后面是 GPL 3.0, 份额大约 10%。 这样来看, 限制性许可证占 35%, 宽松许可证占 34%, 几乎是平手。
|
||||
|
||||
但这份当下的数据没有揭示发展趋势。黑鸭子软件的数据显示, 从 2009 年到 2015 年的六年间, MIT 许可证的份额上升了 15.7%, Apache 的份额上升了 12.4%。 在这段时期, GPL v2 和 v3 的份额惊人地下降了 21.4%。 换言之, 在这段时期里, 大量软件从限制性许可证转到宽松许可证。
|
||||
|
||||
这个趋势还在继续。 黑鸭子软件的[最新数据][1]显示, MIT 现在的份额为 26%, GPL v2 为 21%, Apache 2 为 16%, GPL v3 为 9%。 即 30% 的限制性许可证和 42% 的宽松许可证--与前一年的 35% 的限制许可证和 34% 的宽松许可证相比, 发生了重大的转变。 对 GitHub 上使用许可证的[调查研究][2]证实了这种转变。 它显示 MIT 以压倒性的 45% 占有率成为最流行的许可证, 与之相比, GPL v2 只有 13%, Apache 11%。
|
||||
|
||||

|
||||
|
||||
### 引领趋势
|
||||
|
||||
从限制性许可证到宽松许可证,这么大的转变背后是什么呢? 是公司害怕如果使用了限制性许可证的软件,他们就会像巴尔默说的那样,失去自己私有软件的控制权了吗? 事实上, 可能就是如此。 比如, Google 就[禁用了 Affero GPL 软件][3]。
|
||||
|
||||
[Instructional Media + Magic][4] 的主席 Jim Farmer, 是一个教育开源技术的开发者。 他认为很多公司为避免法律问题而不使用限制性许可证。 “问题就在于复杂性。 许可证的复杂性越高, 被他人因为某行为而告上法庭的可能性越高。 高复杂性更可能带来诉讼”, 他说。
|
||||
|
||||
他补充说, 这种对限制性许可证的恐惧正被律师们驱动着, 许多律师建议自己的客户使用 MIT 或 Apache 2.0 许可证的软件, 并明确反对使用 Affero 许可证的软件。
|
||||
|
||||
他说, 这会对软件开发者产生影响, 因为如果公司都避开限制性许可证软件的使用,开发者想要自己的软件被使用, 就更会把新的软件使用宽松许可证。
|
||||
|
||||
但 SalesAgility(开源 SuiteCRM 背后的公司)的 CEO Greg Soper 认为这种到宽松许可证的转变也是由一些开发者驱动的。 “看看像 Rocket.Chat 这样的应用。 开发者本可以选择 GPL 2.0 或 Affero 许可证, 但他们选择了宽松许可证,” 他说。 “这样可以给这个应用最大的机会, 因为专有软件厂商可以使用它, 不会伤害到他们的产品, 且不需要把他们的产品也使用开源许可证。 这样如果开发者想要让第三方应用使用他的应用的话, 他有理由选择宽松许可证。”
|
||||
|
||||
Soper 指出, 限制性许可证致力于帮助开源项目获得成功,方式是阻止开发者拿了别人的代码、做了修改,但不把结果回报给社区。 “Affero 许可证对我们的产品健康发展很重要, 因为如果有人利用了我们的代码开发,做得比我们好, 却又不把代码回报回来, 就会扼杀掉我们的产品,” 他说。 “ 对 Rocket.Chat 则不同, 因为如果它使用 Affero, 那么它会污染公司的知识产权, 所以公司不会使用它。 不同的许可证有不同的使用案例。”
|
||||
|
||||
曾在 Gnome、OpenOffice 工作过,现在是 LibreOffice 的开源开发者的 Michael Meeks 同意 Jim Farmer 的观点,认为许多公司确实出于对法律的担心,而选择使用宽松许可证的软件。 “copyleft 许可证有风险, 但同样也有巨大的益处。 遗憾的是人们都听从律师的, 而律师只是讲风险, 却从不告诉你有些事是安全的。”
|
||||
|
||||
巴尔默发表他的错误言论已经过去 15 年了, 但它产生的 FUD 还是有影响--即使从限制性许可证到宽松许可证的转变并不是他的目的。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: http://www.cio.com/article/3120235/open-source-tools/what-the-rise-of-permissive-open-source-licenses-means.html
|
||||
|
||||
作者:[Paul Rubens][a]
|
||||
译者:[willcoderwang](https://github.com/willcoderwang)
|
||||
校对:[jasminepeng](https://github.com/jasminepeng)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: http://www.cio.com/author/Paul-Rubens/
|
||||
[1]: https://www.blackducksoftware.com/top-open-source-licenses
|
||||
[2]: https://github.com/blog/1964-open-source-license-usage-on-github-com
|
||||
[3]: http://www.theregister.co.uk/2011/03/31/google_on_open_source_licenses/
|
||||
[4]: http://immagic.com/
|
||||
|
@ -0,0 +1,86 @@
|
||||
Wire:一个极酷、专注于个人隐私的开源聊天应用程序已经来到了 Linux 上
|
||||
===========
|
||||
|
||||
[][21]
|
||||
|
||||
|
||||
回到大约两年前,一些曾开发 [Skype][20] 的开发人员发行了一个漂亮的新聊天应用个程序:[Wire][19]。当我说它漂亮的时候,只是谈论它的“外貌”。Wire 具有一个许多其他聊天应用程序所没有的整洁优美的“外貌”,但这并不是它最大的卖点。
|
||||
|
||||
从一开始,Wire 就推销自己是[世界上最注重隐私的聊天应用程序][18]。无论是文本、语音电话,还是图表、图像等基本的内容,它都提供端到端的加密。
|
||||
|
||||
WhatsApp 也提供‘端到端加密’,但是考虑一下它的所有者 [Facebook 为了吸引用户而把 WhatsApp 的数据分享出去][17]。我不太相信 WhatsApp 以及它的加密手段。
|
||||
|
||||
使 Wire 对于我们这些 FOSS(自由/开源软件)爱好者来说更加重要的是,几个月前 [Wire 开源了][16]。几个月下来我们见到了一个用于 Linux 的 beta 版本 Wire 桌面应用程序。
|
||||
|
||||
除了一个包装器以外,桌面版的 Wire 并没有比 web 版多任何东西。感谢 [Electron 开源项目][15]提供了一种开发跨平台桌面应用程序的简单方式。许多其他应用程序也通过使用 Electron 为 Linux 带去了一个本地桌面应用程序,包括 [Skype][14]。
|
||||
|
||||
### WIRE 的特性:
|
||||
|
||||
在我们了解有关 Linux 版 Wire 应用程序的更多信息之前,让我们先快速看一下它的一些主要特性。
|
||||
|
||||
* 开源应用程序
|
||||
* 针对所有类型内容的全加密
|
||||
* 无广告,无数据收集,无数据分享
|
||||
* 支持文本,语音以及视频聊天
|
||||
* 支持群聊和群电话
|
||||
* [音频过滤器][1](不需要吸入氦元素,只需要使用过滤器就可以用有趣的声音说话)
|
||||
* 不需要电话号码,可以使用邮箱登录
|
||||
* 优美、现代化的界面
|
||||
* 跨平台聊天应用程序,iOS,Android,Web,Mac,Windows 和 Linux 客户机均有相应版本
|
||||
* 欧洲法保护(欧洲法比美国法更注重隐私)
|
||||
|
||||
Wire 有一些更棒的特性,尤其是和[Snapchat][13]类似的音频过滤器。
|
||||
|
||||
### 在 Linux 上安装 WIRE
|
||||
|
||||
在安装 Wire 到 Linux 上之前,让我先警告你它目前还处于 beta 阶段。所以,如果你遇到一些故障,请不要生气。
|
||||
|
||||
Wire 有一个 64 位系统可使用的 .deb 客户端。如果你有一台 [32 位或者 64 位系统][12]的电脑,你可以使用这些技巧来找到它。你可以从下面的链接下载 .deb 文件。
|
||||
|
||||
- [下载 Linux 版 Wire [Beta]][11]
|
||||
|
||||
如果感兴趣的话,你也可以看一看它的源代码:
|
||||
|
||||
- [桌面版 Wire 源代码][10]
|
||||
|
||||
这是 Wire 的默认界面,看起来像 [elementary OS Loki][9]:
|
||||
|
||||

|
||||
|
||||
你看,他们甚至还弄了一个机器人:)
|
||||
|
||||
你已经开始使用 Wire 了吗?如果是,你的体验是什么样的?如果没有,你将尝试一下吗?因为它现在是[开源的][7]并且可以在 Linux 上使用。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://itsfoss.com/wire-messaging-linux/
|
||||
|
||||
作者:[Abhishek Prakash][a]
|
||||
译者:[ucasFL](https://github.com/ucasFL)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://itsfoss.com/author/abhishek/
|
||||
[1]:https://medium.com/colorful-conversations/the-tune-for-this-summer-audio-filters-eca8cb0b4c57#.c8gvs143k
|
||||
[2]:http://pinterest.com/pin/create/button/?url=https://itsfoss.com/wire-messaging-linux/&description=Coolest+Privacy+Focused+Open+Source+Chat+App+Wire+Comes+To+Linux&media=https://itsfoss.com/wp-content/uploads/2016/10/wire-on-desktop-linux.jpeg
|
||||
[3]:https://www.linkedin.com/cws/share?url=https://itsfoss.com/wire-messaging-linux/
|
||||
[4]:https://twitter.com/share?original_referer=https%3A%2F%2Fitsfoss.com%2F&source=tweetbutton&text=Coolest+Privacy+Focused+Open+Source+Chat+App+Wire+Comes+To+Linux&url=https%3A%2F%2Fitsfoss.com%2Fwire-messaging-linux%2F&via=%40itsfoss
|
||||
[5]:https://itsfoss.com/wire-messaging-linux/#comments
|
||||
[6]:https://itsfoss.com/author/abhishek/
|
||||
[7]:https://itsfoss.com/tag/open-source
|
||||
[8]:https://itsfoss.com/wp-content/uploads/2016/10/Wire-desktop-appl-linux.jpeg
|
||||
[9]:https://itsfoss.com/tag/elementary-os-loki/
|
||||
[10]:https://github.com/wireapp/wire-desktop
|
||||
[11]:https://wire.com/download/
|
||||
[12]:https://itsfoss.com/32-bit-64-bit-ubuntu/
|
||||
[13]:https://www.snapchat.com/
|
||||
[14]:https://itsfoss.com/skpe-alpha-linux/
|
||||
[15]:http://electron.atom.io/
|
||||
[16]:http://www.infoworld.com/article/3099194/security/wire-open-sources-messaging-client-woos-developers.html
|
||||
[17]:https://techcrunch.com/2016/08/25/whatsapp-to-share-user-data-with-facebook-for-ad-targeting-heres-how-to-opt-out/
|
||||
[18]:http://www.ibtimes.co.uk/wire-worlds-most-private-messaging-app-offers-total-encryption-calls-texts-1548964
|
||||
[19]:https://wire.com/
|
||||
[20]:https://www.skype.com/en/
|
||||
[21]:https://itsfoss.com/wp-content/uploads/2016/10/wire-on-desktop-linux.jpeg
|
||||
|
@ -0,0 +1,113 @@
|
||||
在 Linux 下使用 TCP 封装器来加强网络服务安全
|
||||
===========
|
||||
|
||||
在这篇文章中,我们将会讲述什么是 TCP 封装器(TCP wrappers)以及如何在一台 Linux 服务器上配置他们来[限制网络服务的权限][7]。在开始之前,我们必须澄清 TCP 封装器并不能消除对于正确[配置防火墙][6]的需要。
|
||||
|
||||
就这一点而言,你可以把这个工具看作是一个[基于主机的访问控制列表][5],而且并不能作为你的系统的[终极安全措施][4]。通过使用一个防火墙和 TCP 封装器,而不是只偏爱其中的一个,你将会确保你的服务不会被出现单点故障。
|
||||
|
||||
### 正确理解 hosts.allow 和 hosts.deny 文件
|
||||
|
||||
当一个网络请求到达你的主机的时候,TCP 封装器会使用 `hosts.allow` 和 `hosts.deny` (按照这样的顺序)来决定客户端是否应该被允许使用一个提供的服务。.
|
||||
|
||||
在默认情况下,这些文件内容是空的,或者被注释掉,或者根本不存在。所以,任何请求都会被允许通过 TCP 过滤器而且你的系统被置于依靠防火墙来提供所有的保护。因为这并不是我们想要的。由于在一开始我们就介绍过的原因,清确保下面两个文件都存在:
|
||||
|
||||
```
|
||||
# ls -l /etc/hosts.allow /etc/hosts.deny
|
||||
|
||||
```
|
||||
|
||||
两个文件的编写语法规则是一样的:
|
||||
|
||||
```
|
||||
<services> : <clients> [: <option1> : <option2> : ...]
|
||||
|
||||
```
|
||||
|
||||
在文件中,
|
||||
|
||||
1. `services` 指当前规则对应的服务,是一个逗号分割的列表。
|
||||
2. `clients` 指被规则影响的主机名或者 IP 地址,逗号分割的。下面的通配符也可以接受:
|
||||
1. `ALL` 表示所有事物,应用于`clients`和`services`。
|
||||
2. `LOCAL` 表示匹配在正式域名中没有完全限定主机名(FQDN)的机器,例如 `localhost`。
|
||||
3. `KNOWN` 表示主机名,主机地址,或者用户是已知的(即可以通过 DNS 或其它服务解析到)。
|
||||
4. `UNKNOWN` 和 `KNOWN` 相反。
|
||||
5. `PARANOID` 如果进行反向 DNS 查找彼此返回了不同的地址,那么连接就会被断开(首先根据 IP 去解析主机名,然后根据主机名去获得 IP 地址)。
|
||||
3. 最后,一个冒号分割的动作列表表示了当一个规则被触发的时候会采取什么操作。
|
||||
|
||||
你应该记住 `/etc/hosts.allow` 文件中允许一个服务接入的规则要优先于 `/etc/hosts.deny` 中的规则。另外还有,如果两个规则应用于同一个服务,只有第一个规则会被纳入考虑。
|
||||
|
||||
不幸的是,不是所有的网络服务都支持 TCP 过滤器,为了查看一个给定的服务是否支持他们,可以执行以下命令:
|
||||
|
||||
```
|
||||
# ldd /path/to/binary | grep libwrap
|
||||
|
||||
```
|
||||
|
||||
如果以上命令执行以后得到了以下结果,那么它就可以支持 TCP 过滤器,`sshd` 和 `vsftpd` 作为例子,输出如下所示。
|
||||
|
||||
[][3]
|
||||
|
||||
*查找 TCP 过滤器支持的服务*
|
||||
|
||||
### 如何使用 TCP 过滤器来限制服务的权限
|
||||
|
||||
当你编辑 `/etc/hosts.allow` 和 `/etc/hosts.deny` 的时候,确保你在最后一个非空行后面通过回车键来添加一个新的行。
|
||||
|
||||
为了使得 [SSH 和 FTP][2] 服务只允许 `localhost` 和 `192.168.0.102` 并且拒绝所有其他用户,在 `/etc/hosts.deny` 添加如下内容:
|
||||
|
||||
```
|
||||
sshd,vsftpd : ALL
|
||||
ALL : ALL
|
||||
|
||||
```
|
||||
|
||||
而且在 `/etc/hosts.allow` 文件中添加如下内容:
|
||||
|
||||
```
|
||||
sshd,vsftpd : 192.168.0.102,LOCAL
|
||||
|
||||
```
|
||||
|
||||
这些更改会立刻生效并且不需要重新启动。
|
||||
|
||||
在下图中你会看到,在最后一行中删掉 `LOCAL` 后,FTP 服务器会对于 `localhost` 不可用。在我们添加了通配符以后,服务又变得可用了。
|
||||
|
||||
[][1]
|
||||
|
||||
*确认 FTP 权限*
|
||||
|
||||
为了允许所有服务对于主机名中含有 `example.com` 都可用,在 `hosts.allow` 中添加如下一行:
|
||||
|
||||
```
|
||||
ALL : .example.com
|
||||
|
||||
```
|
||||
|
||||
而为了禁止 `10.0.1.0/24` 的机器访问 `vsftpd` 服务,在 `hosts.deny` 文件中添加如下一行:
|
||||
```
|
||||
vsftpd : 10.0.1.
|
||||
|
||||
```
|
||||
|
||||
在最后的两个例子中,注意到客户端列表每行开头和结尾的点。这是用来表示 “所有名字或者 IP 中含有那个字符串的主机或客户端”
|
||||
|
||||
这篇文章对你有用吗?你有什么问题或者评论吗?请你尽情在下面留言交流。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: http://www.tecmint.com/secure-linux-tcp-wrappers-hosts-allow-deny-restrict-access/
|
||||
|
||||
作者:[Gabriel Cánepa][a]
|
||||
译者:[LinuxBars](https://LinuxBar.org)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:http://www.tecmint.com/author/gacanepa/
|
||||
[1]:http://www.tecmint.com/wp-content/uploads/2016/10/Verify-FTP-Access.png
|
||||
[2]:http://www.tecmint.com/block-ssh-and-ftp-access-to-specific-ip-and-network-range/
|
||||
[3]:http://www.tecmint.com/wp-content/uploads/2016/10/Find-Supported-Services-in-TCP-Wrapper.png
|
||||
[4]:http://www.tecmint.com/linux-server-hardening-security-tips/
|
||||
[5]:https://linux.cn/article-3966-1.html
|
||||
[6]:https://linux.cn/article-4425-1.html
|
||||
[7]:https://linux.cn/article-7719-1.html
|
@ -0,0 +1,143 @@
|
||||
怎样在 RHEL、CentOS 和 Fedora 上安装 Git 及设置 Git 账号
|
||||
=========
|
||||
|
||||
对于新手来说,Git 是一个自由、开源、高效的分布式版本控制系统(VCS),它是基于速度、高性能以及数据一致性而设计的,以支持从小规模到大体量的软件开发项目。
|
||||
|
||||
Git 是一个可以让你追踪软件改动、版本回滚以及创建另外一个版本的目录和文件的软件仓库。
|
||||
|
||||
Git 主要是用 C 语言来写的,混杂了少量的 Perl 脚本和各种 shell 脚本。它主要在 Linux 内核上运行,并且有以下列举的卓越的性能:
|
||||
|
||||
- 易于上手
|
||||
- 运行速度飞快,且大部分操作在本地进行,因此,它极大的提升了那些需要与远程服务器通信的集中式系统的速度。
|
||||
- 高效
|
||||
- 提供数据一致性检查
|
||||
- 支持低开销的本地分支
|
||||
- 提供非常便利的暂存区
|
||||
- 可以集成其它工具来支持多种工作流
|
||||
|
||||
在这篇操作指南中,我们将介绍在 CentOS/RHEL 7/6 和 Fedora 20-24 Linux 发行版上安装 Git 的必要步骤以及怎么配置 Git,以便于你可以快速开始工作。
|
||||
|
||||
### 使用 Yum 安装 Git
|
||||
|
||||
我们将从系统默认的仓库安装 Git,并通过运行以下 [YUM 包管理器][8] 的更新命令来确保你系统的软件包都是最新的:
|
||||
|
||||
```
|
||||
# yum update
|
||||
```
|
||||
|
||||
接着,通过以下命令来安装 Git:
|
||||
|
||||
```
|
||||
# yum install git
|
||||
```
|
||||
|
||||
在 Git 成功安装之后,你可以通过以下命令来显示 Git 安装的版本:
|
||||
|
||||
```
|
||||
# git --version
|
||||
```
|
||||
|
||||

|
||||
|
||||
*检查 Git 安装的版本*
|
||||
|
||||
注意:从系统默认仓库安装的 Git 会是比较旧的版本。如果你想拥有最新版的 Git,请考虑使用以下说明来编译源代码进行安装。
|
||||
|
||||
### 从源代码安装 Git
|
||||
|
||||
开始之前,你首先需要从系统默认仓库安装所需的软件依赖包,以及从源代码构建二进制文件所需的实用工具:
|
||||
|
||||
```
|
||||
# yum groupinstall "Development Tools"
|
||||
# yum install gettext-devel openssl-devel perl-CPAN perl-devel zlib-devel
|
||||
```
|
||||
|
||||
安装所需的软件依赖包之后,转到官方的 [Git 发布页面][6],抓取最新版的 Git 并使用下列命令编译它的源代码:
|
||||
|
||||
```
|
||||
# wget https://github.com/git/git/archive/v2.10.1.tar.gz -O git.tar.gz
|
||||
# tar -zxf git.tar.gz
|
||||
# cd git-2.10.1/
|
||||
# make configure
|
||||
# ./configure --prefix=/usr/local
|
||||
# make install
|
||||
# git --version
|
||||
```
|
||||
|
||||

|
||||
|
||||
*检查 Git 的安装版本*
|
||||
|
||||
**推荐阅读:** [Linux 下 11 个最好用的 Git 客户端和 Git 仓库查看器][4]。
|
||||
|
||||
### 在 Linux 设置 Git 账户
|
||||
|
||||
在这个环节中,我们将介绍如何使用正确的用户信息(如:姓名、邮件地址)和 `git config` 命令来设置 Git 账户,以避免出现提交错误。
|
||||
|
||||
注意:确保将下面的 `username` 替换为在你的系统上创建和使用的 Git 用户的真实名称。
|
||||
|
||||
你可以使用下面的 [useradd 命令][3] 创建一个 Git 用户,其中 `-m` 选项用于在 `/home` 目录下创建用户主目录,`-s` 选项用于指定用户默认的 shell。
|
||||
|
||||
```
|
||||
# useradd -m -s /bin/bash username
|
||||
# passwd username
|
||||
```
|
||||
|
||||
现在,将新用户添加到 `wheel` 用户组以启用其使用 `sudo` 命令的权限:
|
||||
|
||||
```
|
||||
# usermod username -aG wheel
|
||||
```
|
||||
|
||||

|
||||
|
||||
*创建 Git 用户账号*
|
||||
|
||||
然后通过以下命令使用新用户配置 Git:
|
||||
|
||||
```
|
||||
# su username
|
||||
$ sudo git config --global user.name "Your Name"
|
||||
$ sudo git config --global user.email "you@example.com"
|
||||
```
|
||||
|
||||
现在通过下面的命令校验 Git 的配置。
|
||||
|
||||
```
|
||||
$ sudo git config --list
|
||||
```
|
||||
|
||||
如果配置没有错误的话,你应该能够看到类似以下详细信息的输出:
|
||||
|
||||
```
|
||||
user.name=username
|
||||
user.email= username@some-domian.com
|
||||
```
|
||||
|
||||

|
||||
|
||||
*在 Linux 设置 Git 用户*
|
||||
|
||||
### 总结
|
||||
|
||||
在这个简单的教程中,我们已经了解怎么在你的 Linux 系统上安装 Git 以及配置它。我相信你应该可以驾轻就熟。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: http://www.tecmint.com/install-git-centos-fedora-redhat/
|
||||
|
||||
作者:[Aaron Kili][a]
|
||||
译者:[OneNewLife](https://github.com/OneNewLife)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:http://www.tecmint.com/author/aaronkili/
|
||||
[1]:http://www.tecmint.com/wp-content/uploads/2016/10/Setup-Git-Account.png
|
||||
[2]:http://www.tecmint.com/wp-content/uploads/2016/10/Create-Git-User-Account.png
|
||||
[3]:http://www.tecmint.com/add-users-in-linux/
|
||||
[4]:http://www.tecmint.com/best-gui-git-clients-git-repository-viewers-for-linux/
|
||||
[5]:http://www.tecmint.com/wp-content/uploads/2016/10/Check-Git-Source-Version.png
|
||||
[6]:https://github.com/git/git/releases
|
||||
[7]:http://www.tecmint.com/wp-content/uploads/2016/10/Check-Git-Version.png
|
||||
[8]:https://linux.cn/article-2272-1.html
|
@ -0,0 +1,166 @@
|
||||
删除一个目录下部分类型之外的所有文件的三种方法
|
||||
=========
|
||||
|
||||
有的时候,你可能会遇到这种情况,你需要删除一个目录下的所有文件,或者只是简单的通过删除除了一些指定类型(以指定扩展名结尾)之外的文件来清理一个目录。
|
||||
|
||||
在这篇文章,我们将会向你展现如何通过 `rm`、 `find` 和 `globignore` 命令删除一个目录下除了指定文件扩展名或者类型的之外的文件。
|
||||
|
||||
在我们进一步深入之前,让我们开始简要的了解一下 Linux 中的一个重要的概念 —— 文件名模式匹配,它可以让我们解决眼前的问题。
|
||||
|
||||
在 Linux 下,一个 shell 模式是一个包含以下特殊字符的字符串,称为通配符或者元字符:
|
||||
|
||||
1. `*` – 匹配 0 个或者多个字符
|
||||
2. `?` – 匹配任意单个字符
|
||||
3. `[序列]` – 匹配序列中的任意一个字符
|
||||
4. `[!序列]` – 匹配任意一个不在序列中的字符
|
||||
|
||||
我们将在这儿探索三种可能的办法,包括:
|
||||
|
||||
### 使用扩展模式匹配操作符删除文件
|
||||
|
||||
下来列出了不同的扩展模式匹配操作符,这些模式列表是一个用 `|` 分割包含一个或者多个文件名的列表:
|
||||
|
||||
1. `*(模式列表)` – 匹配 0 个或者多个出现的指定模式
|
||||
2. `?(模式列表)` – 匹配 0 个或者 1 个出现的指定模式
|
||||
4. `@(模式列表)` – 匹配 1 个或者多个出现的指定模式
|
||||
5. `!(模式列表)` – 匹配除了一个指定模式之外的任何内容
|
||||
|
||||
为了使用它们,需要像下面一样打开 extglob shell 选项:
|
||||
|
||||
```
|
||||
# shopt -s extglob
|
||||
|
||||
```
|
||||
|
||||
**1. 输入以下命令,删除一个目录下除了 filename 之外的所有文件**
|
||||
|
||||
```
|
||||
$ rm -v !("filename")
|
||||
```
|
||||

|
||||
|
||||
*删除 Linux 下除了一个文件之外的所有文件*
|
||||
|
||||
**2. 删除除了 filename1 和 filename2 之外的所有文件**
|
||||
|
||||
```
|
||||
$ rm -v !("filename1"|"filename2")
|
||||
```
|
||||

|
||||
|
||||
*在 Linux 下删除除了一些文件之外的所有文件*
|
||||
|
||||
**3. 下面的例子显示如何通过交互模式删除除了 `.zip` 之外的所有文件**
|
||||
|
||||
```
|
||||
$ rm -i !(*.zip)
|
||||
```
|
||||
|
||||

|
||||
|
||||
*在 Linux 下删除除了 Zip 文件之外的所有文件*
|
||||
|
||||
**4. 接下来,通过如下的方式你可以删除一个目录下除了所有的`.zip` 和 `.odt` 文件的所有文件,并且在删除的时候,显示正在删除的文件:**
|
||||
|
||||
```
|
||||
$ rm -v !(*.zip|*.odt)
|
||||
```
|
||||

|
||||
|
||||
*删除除了指定文件扩展的所有文件*
|
||||
|
||||
一旦你已经执行了所有需要的命令,你还可以使用如下的方式关闭 extglob shell 选项。
|
||||
|
||||
```
|
||||
$ shopt -u extglob
|
||||
```
|
||||
|
||||
### 使用 Linux 下的 find 命令删除文件
|
||||
|
||||
在这种方法下,我们可以[只使用 find 命令][5]的适当的选项或者采用管道配合 `xargs` 命令,如下所示:
|
||||
|
||||
```
|
||||
$ find /directory/ -type f -not -name 'PATTERN' -delete
|
||||
$ find /directory/ -type f -not -name 'PATTERN' -print0 | xargs -0 -I {} rm {}
|
||||
$ find /directory/ -type f -not -name 'PATTERN' -print0 | xargs -0 -I {} rm [options] {}
|
||||
```
|
||||
|
||||
**5. 下面的命令将会删除当前目录下除了 `.gz` 之外的所有文件**
|
||||
|
||||
```
|
||||
$ find . -type f -not -name '*.gz' -delete
|
||||
```
|
||||

|
||||
|
||||
*find 命令 —— 删除 .gz 之外的所有文件*
|
||||
|
||||
**6. 使用管道和 xargs,你可以通过如下的方式修改上面的例子:**
|
||||
|
||||
```
|
||||
$ find . -type f -not -name '*gz' -print0 | xargs -0 -I {} rm -v {}
|
||||
```
|
||||

|
||||
|
||||
*使用 find 和 xargs 命令删除文件*
|
||||
|
||||
**7. 让我们看一个额外的例子,下面的命令行将会删除掉当前目录下除了 `.gz`、 `.odt` 和 `.jpg` 之外的所有文件:**
|
||||
|
||||
```
|
||||
$ find . -type f -not \(-name '*gz' -or -name '*odt' -or -name '*.jpg' \) -delete
|
||||
```
|
||||

|
||||
|
||||
*删除除了指定扩展文件的所有文件*
|
||||
|
||||
### 通过 bash 中的 GLOBIGNORE 变量删除文件
|
||||
|
||||
然而,最后的方法,只适用于 bash。 `GLOBIGNORE` 变量存储了一个路径名展开(pathname expansion)功能的忽略模式(或文件名)列表,以冒号分隔。
|
||||
|
||||
为了使用这种方法,切换到要删除文件的目录,像下面这样设置 `GLOBIGNORE` 变量:
|
||||
|
||||
```
|
||||
$ cd test
|
||||
$ GLOBIGNORE=*.odt:*.iso:*.txt
|
||||
```
|
||||
|
||||
在这种情况下,除了 `.odt`、 `.iso` 和 `.txt` 之外的所有文件,都将从当前目录删除。
|
||||
|
||||
现在,运行如下的命令清空这个目录:
|
||||
|
||||
```
|
||||
$ rm -v *
|
||||
```
|
||||
|
||||
之后,关闭 `GLOBIGNORE` 变量:
|
||||
|
||||
```
|
||||
$ unset GLOBIGNORE
|
||||
```
|
||||

|
||||
|
||||
*使用 bash 变量 GLOBIGNORE 删除文件*
|
||||
|
||||
注:为了理解上面的命令行采用的标识的意思,请参考我们在每一个插图中使用的命令对应的 man 手册。
|
||||
|
||||
就这些了!如果你知道有实现相同目录的其他命令行技术,不要忘了通过下面的反馈部分分享给我们。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: http://www.tecmint.com/delete-all-files-in-directory-except-one-few-file-extensions/
|
||||
|
||||
作者:[Aaron Kili][a]
|
||||
译者:[yangmingming](https://github.com/yangmingming)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: http://www.tecmint.com/author/aaronkili/
|
||||
[1]:http://www.tecmint.com/wp-content/uploads/2016/10/Delete-Files-Using-Bash-GlobIgnore.png
|
||||
[2]:http://www.tecmint.com/wp-content/uploads/2016/10/Remove-All-Files-Except-File-Extensions.png
|
||||
[3]:http://www.tecmint.com/wp-content/uploads/2016/10/Remove-Files-Using-Find-and-Xargs-Command.png
|
||||
[4]:http://www.tecmint.com/wp-content/uploads/2016/10/Remove-All-Files-Except-gz-Files.png
|
||||
[5]:http://www.tecmint.com/35-practical-examples-of-linux-find-command/
|
||||
[6]:http://www.tecmint.com/wp-content/uploads/2016/10/Delete-All-Files-Except-Certain-File-Extensions.png
|
||||
[7]:http://www.tecmint.com/wp-content/uploads/2016/10/Delete-All-Files-Except-Zip-Files-in-Linux.png
|
||||
[8]:http://www.tecmint.com/wp-content/uploads/2016/10/Delete-All-Files-Except-Few-Files-in-Linux.png
|
||||
[9]:http://www.tecmint.com/wp-content/uploads/2016/10/DeleteAll-Files-Except-One-File-in-Linux.png
|
@ -0,0 +1,238 @@
|
||||
怎样在 CentOS 里下载 RPM 包及其所有依赖包
|
||||
========
|
||||
|
||||

|
||||
|
||||
前几天我尝试去创建一个仅包含了我们经常在 CentOS 7 下使用的软件的本地仓库。当然,我们可以使用 curl 或者 wget 下载任何软件包,然而这些命令并不能下载要求的依赖软件包。你必须去花一些时间而且手动的去寻找和下载被安装的软件所依赖的软件包。然而,我们并不是必须这样。在这个简短的教程中,我将会带领你以两种方式下载软件包及其所有依赖包。我已经在 CentOS 7 下进行了测试,不过这些相同的步骤或许在其他基于 RPM 管理系统的发行版上也可以工作,例如 RHEL,Fedora 和 Scientific Linux。
|
||||
|
||||
### 方法 1 利用 “Downloadonly” 插件下载 RPM 软件包及其所有依赖包
|
||||
|
||||
我们可以通过 yum 命令的 “Downloadonly” 插件下载 RPM 软件包及其所有依赖包。
|
||||
|
||||
为了安装 Downloadonly 插件,以 root 身份运行以下命令。
|
||||
|
||||
```
|
||||
yum install yum-plugin-downloadonly
|
||||
```
|
||||
|
||||
现在,运行以下命令去下载一个 RPM 软件包。
|
||||
|
||||
```
|
||||
yum install --downloadonly <package-name>
|
||||
```
|
||||
|
||||
默认情况下,这个命令将会下载并把软件包保存到 `/var/cache/yum/` 的 `rhel-{arch}-channel/packageslocation` 目录,不过,你也可以下载和保存软件包到任何位置,你可以通过 `–downloaddir` 选项来指定。
|
||||
|
||||
```
|
||||
yum install --downloadonly --downloaddir=<directory> <package-name>
|
||||
```
|
||||
|
||||
例子:
|
||||
|
||||
```
|
||||
yum install --downloadonly --downloaddir=/root/mypackages/ httpd
|
||||
```
|
||||
|
||||
终端输出:
|
||||
|
||||
```
|
||||
Loaded plugins: fastestmirror
|
||||
Loading mirror speeds from cached hostfile
|
||||
* base: centos.excellmedia.net
|
||||
* epel: epel.mirror.angkasa.id
|
||||
* extras: centos.excellmedia.net
|
||||
* updates: centos.excellmedia.net
|
||||
Resolving Dependencies
|
||||
--> Running transaction check
|
||||
---> Package httpd.x86_64 0:2.4.6-40.el7.centos.4 will be installed
|
||||
--> Processing Dependency: httpd-tools = 2.4.6-40.el7.centos.4 for package: httpd-2.4.6-40.el7.centos.4.x86_64
|
||||
--> Processing Dependency: /etc/mime.types for package: httpd-2.4.6-40.el7.centos.4.x86_64
|
||||
--> Processing Dependency: libaprutil-1.so.0()(64bit) for package: httpd-2.4.6-40.el7.centos.4.x86_64
|
||||
--> Processing Dependency: libapr-1.so.0()(64bit) for package: httpd-2.4.6-40.el7.centos.4.x86_64
|
||||
--> Running transaction check
|
||||
---> Package apr.x86_64 0:1.4.8-3.el7 will be installed
|
||||
---> Package apr-util.x86_64 0:1.5.2-6.el7 will be installed
|
||||
---> Package httpd-tools.x86_64 0:2.4.6-40.el7.centos.4 will be installed
|
||||
---> Package mailcap.noarch 0:2.1.41-2.el7 will be installed
|
||||
--> Finished Dependency Resolution
|
||||
|
||||
Dependencies Resolved
|
||||
|
||||
=======================================================================================================================================
|
||||
Package Arch Version Repository Size
|
||||
=======================================================================================================================================
|
||||
Installing:
|
||||
httpd x86_64 2.4.6-40.el7.centos.4 updates 2.7 M
|
||||
Installing for dependencies:
|
||||
apr x86_64 1.4.8-3.el7 base 103 k
|
||||
apr-util x86_64 1.5.2-6.el7 base 92 k
|
||||
httpd-tools x86_64 2.4.6-40.el7.centos.4 updates 83 k
|
||||
mailcap noarch 2.1.41-2.el7 base 31 k
|
||||
|
||||
Transaction Summary
|
||||
=======================================================================================================================================
|
||||
Install 1 Package (+4 Dependent packages)
|
||||
|
||||
Total download size: 3.0 M
|
||||
Installed size: 10 M
|
||||
Background downloading packages, then exiting:
|
||||
(1/5): apr-1.4.8-3.el7.x86_64.rpm | 103 kB 00:00:01
|
||||
(2/5): apr-util-1.5.2-6.el7.x86_64.rpm | 92 kB 00:00:01
|
||||
(3/5): mailcap-2.1.41-2.el7.noarch.rpm | 31 kB 00:00:01
|
||||
(4/5): httpd-tools-2.4.6-40.el7.centos.4.x86_64.rpm | 83 kB 00:00:01
|
||||
(5/5): httpd-2.4.6-40.el7.centos.4.x86_64.rpm | 2.7 MB 00:00:09
|
||||
---------------------------------------------------------------------------------------------------------------------------------------
|
||||
Total 331 kB/s | 3.0 MB 00:00:09
|
||||
exiting because "Download Only" specified
|
||||
```
|
||||
|
||||

|
||||
|
||||
现在去你指定的目录位置下,你将会看到那里有下载好的软件包和依赖的软件。在我这种情况下,我已经把软件包下载到 `/root/mypackages/` 目录下。
|
||||
|
||||
让我们来查看一下内容。
|
||||
|
||||
```
|
||||
ls /root/mypackages/
|
||||
```
|
||||
|
||||
样本输出:
|
||||
|
||||
```
|
||||
apr-1.4.8-3.el7.x86_64.rpm
|
||||
apr-util-1.5.2-6.el7.x86_64.rpm
|
||||
httpd-2.4.6-40.el7.centos.4.x86_64.rpm
|
||||
httpd-tools-2.4.6-40.el7.centos.4.x86_64.rpm
|
||||
mailcap-2.1.41-2.el7.noarch.rpm
|
||||
```
|
||||
|
||||
[][5]
|
||||
|
||||
正如你在上面输出所看到的, httpd软件包已经被依据所有依赖性下载完成了 。
|
||||
|
||||
请注意,这个插件适用于 `yum install/yum update`, 但是并不适用于 `yum groupinstall`。默认情况下,这个插件将会下载仓库中最新可用的软件包。然而你可以通过指定版本号来下载某个特定的软件版本。
|
||||
|
||||
例子:
|
||||
|
||||
```
|
||||
yum install --downloadonly --downloaddir=/root/mypackages/ httpd-2.2.6-40.el7
|
||||
```
|
||||
|
||||
此外,你也可以如下一次性下载多个包:
|
||||
|
||||
```
|
||||
yum install --downloadonly --downloaddir=/root/mypackages/ httpd vsftpd
|
||||
```
|
||||
|
||||
### 方法 2 使用 “Yumdownloader” 工具来下载 RPM 软件包及其所有依赖包
|
||||
|
||||
“Yumdownloader” 是一款简单,但是却十分有用的命令行工具,它可以一次性下载任何 RPM 软件包及其所有依赖包。
|
||||
|
||||
以 root 身份运行如下命令安装 “Yumdownloader” 工具。
|
||||
|
||||
```
|
||||
yum install yum-utils
|
||||
```
|
||||
一旦安装完成,运行如下命令去下载一个软件包,例如 httpd。
|
||||
|
||||
```
|
||||
yumdownloader httpd
|
||||
```
|
||||
|
||||
为了根据所有依赖性下载软件包,我们使用 `--resolve` 参数:
|
||||
|
||||
```
|
||||
yumdownloader --resolve httpd
|
||||
```
|
||||
|
||||
默认情况下,Yumdownloader 将会下载软件包到当前工作目录下。
|
||||
|
||||
为了将软件下载到一个特定的目录下,我们使用 `--destdir` 参数:
|
||||
|
||||
```
|
||||
yumdownloader --resolve --destdir=/root/mypackages/ httpd
|
||||
```
|
||||
|
||||
或者,
|
||||
|
||||
```
|
||||
yumdownloader --resolve --destdir /root/mypackages/ httpd
|
||||
```
|
||||
|
||||
终端输出:
|
||||
|
||||
```
|
||||
Loaded plugins: fastestmirror
|
||||
Loading mirror speeds from cached hostfile
|
||||
* base: centos.excellmedia.net
|
||||
* epel: epel.mirror.angkasa.id
|
||||
* extras: centos.excellmedia.net
|
||||
* updates: centos.excellmedia.net
|
||||
--> Running transaction check
|
||||
---> Package httpd.x86_64 0:2.4.6-40.el7.centos.4 will be installed
|
||||
--> Processing Dependency: httpd-tools = 2.4.6-40.el7.centos.4 for package: httpd-2.4.6-40.el7.centos.4.x86_64
|
||||
--> Processing Dependency: /etc/mime.types for package: httpd-2.4.6-40.el7.centos.4.x86_64
|
||||
--> Processing Dependency: libaprutil-1.so.0()(64bit) for package: httpd-2.4.6-40.el7.centos.4.x86_64
|
||||
--> Processing Dependency: libapr-1.so.0()(64bit) for package: httpd-2.4.6-40.el7.centos.4.x86_64
|
||||
--> Running transaction check
|
||||
---> Package apr.x86_64 0:1.4.8-3.el7 will be installed
|
||||
---> Package apr-util.x86_64 0:1.5.2-6.el7 will be installed
|
||||
---> Package httpd-tools.x86_64 0:2.4.6-40.el7.centos.4 will be installed
|
||||
---> Package mailcap.noarch 0:2.1.41-2.el7 will be installed
|
||||
--> Finished Dependency Resolution
|
||||
(1/5): apr-util-1.5.2-6.el7.x86_64.rpm | 92 kB 00:00:01
|
||||
(2/5): mailcap-2.1.41-2.el7.noarch.rpm | 31 kB 00:00:02
|
||||
(3/5): apr-1.4.8-3.el7.x86_64.rpm | 103 kB 00:00:02
|
||||
(4/5): httpd-tools-2.4.6-40.el7.centos.4.x86_64.rpm | 83 kB 00:00:03
|
||||
(5/5): httpd-2.4.6-40.el7.centos.4.x86_64.rpm | 2.7 MB 00:00:19
|
||||
```
|
||||
|
||||

|
||||
|
||||
让我们确认一下软件包是否被下载到我们指定的目录下。
|
||||
|
||||
```
|
||||
ls /root/mypackages/
|
||||
```
|
||||
|
||||
终端输出:
|
||||
|
||||
```
|
||||
apr-1.4.8-3.el7.x86_64.rpm
|
||||
apr-util-1.5.2-6.el7.x86_64.rpm
|
||||
httpd-2.4.6-40.el7.centos.4.x86_64.rpm
|
||||
httpd-tools-2.4.6-40.el7.centos.4.x86_64.rpm
|
||||
mailcap-2.1.41-2.el7.noarch.rpm
|
||||
```
|
||||
|
||||

|
||||
|
||||
不像 Downloadonly 插件,Yumdownload 可以下载一组相关的软件包。
|
||||
|
||||
```
|
||||
yumdownloader "@Development Tools" --resolve --destdir /root/mypackages/
|
||||
```
|
||||
|
||||
在我看来,我喜欢 Yumdownloader 更胜于 Yum 的 Downloadonly 插件。但是,两者都是十分简单易懂而且可以完成相同的工作。
|
||||
|
||||
这就是今天所有的内容,如果你觉得这份引导教程有用,清在你的社交媒体上面分享一下去让更多的人知道。
|
||||
|
||||
干杯!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.ostechnix.com/download-rpm-package-dependencies-centos/
|
||||
|
||||
作者:[SK][a]
|
||||
译者:[LinuxBars](https://github.com/LinuxBars)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: http://ostechnix.tradepub.com/free/w_make272/prgm.cgi?a=1
|
||||
[2]:http://www.ostechnix.com/wp-content/uploads/2016/10/root@server1_005.png
|
||||
[3]:http://www.ostechnix.com/wp-content/uploads/2016/10/root@server1_004-1.png
|
||||
[4]:http://ostechnix.tradepub.com/free/w_make272/prgm.cgi?a=1
|
||||
[5]:http://www.ostechnix.com/wp-content/uploads/2016/10/root@server1_003-1.png
|
||||
[6]:http://www.ostechnix.com/wp-content/uploads/2016/10/root@server1_001.png
|
||||
[7]:https://www.ostechnix.com/author/sk/
|
@ -0,0 +1,119 @@
|
||||
如何在后台运行 Linux 命令并且将进程脱离终端
|
||||
=================
|
||||
|
||||
在本指南中,我们将会阐明一个在 [Linux 系统中进程管理][8]的简单但是重要的概念,那就是如何从它的控制终端完全脱离一个进程。
|
||||
|
||||
当一个进程与终端关联在一起时,可能会出现两种问题:
|
||||
|
||||
1. 你的控制终端充满了很多输出数据或者错误及诊断信息
|
||||
2. 如果发生终端关闭的情况,进程连同它的子进程都将会终止
|
||||
|
||||
为了解决上面两个问题,你需要从一个控制终端完全脱离一个进程。在我们实际上解决这个问题之前,让我们先简要的介绍一下,如何在后台运行一个进程。
|
||||
|
||||
### 如何在后台开始一个 Linux 进程或者命令行
|
||||
|
||||
如果一个进程已经运行,例如下面的 [tar 命令行的例子][7],简单的按下 `Ctrl+Z` 就可以停止它(LCTT 译注:这里说的“停止”,不是终止,而是“暂停”的意思),然后输入命令 `bg` 就可以继续以一个任务在后台运行了。
|
||||
|
||||
你可以通过输入 `jobs` 查看所有的后台任务。但是,标准输入(STDIN)、标准输出(STDOUT)和标准错误(STDERR)依旧掺杂到控制台中。
|
||||
|
||||
```
|
||||
$ tar -czf home.tar.gz .
|
||||
$ bg
|
||||
$ jobs
|
||||
|
||||
```
|
||||
|
||||

|
||||
|
||||
*在后台运行 Linux 命令*
|
||||
|
||||
你也可以直接使用符号 `&` 在后台运行一个进程:
|
||||
|
||||
```
|
||||
$ tar -czf home.tar.gz . &
|
||||
$ jobs
|
||||
|
||||
```
|
||||
|
||||

|
||||
|
||||
*在后台开始一个 Linux 进程*
|
||||
|
||||
看一下下面的这个例子,虽然 [tar 命令][4]是作为一个后台任务开始的,但是错误信息依旧发送到终端,这表示,进程依旧和控制终端关联在一起。
|
||||
|
||||
```
|
||||
$ tar -czf home.tar.gz . &
|
||||
$ jobs
|
||||
|
||||
```
|
||||
|
||||

|
||||
|
||||
*运行在后台的 Linux 进程信息*
|
||||
|
||||
### 退出控制台之后,保持 Linux 进程的运行
|
||||
|
||||
我们将使用 `disown` 命令,它在一个进程已经运行并且被放在后台之后使用,它的作用是从 shell 的活动任务列表中移走一个 shell 任务,因此,对于该任务,你将再也不能使用 `fg` 、 `bg` 命令了。
|
||||
|
||||
而且,当你关闭控制控制终端,这个任务将不会挂起(暂停)或者向任何一个子任务发送 SIGHUP 信号。
|
||||
|
||||
让我们看一下先下面的这个使用 bash 中内置命令 `disown` 的例子。
|
||||
|
||||
```
|
||||
$ sudo rsync Templates/* /var/www/html/files/ &
|
||||
$ jobs
|
||||
$ disown -h %1
|
||||
$ jobs
|
||||
|
||||
```
|
||||
|
||||

|
||||
|
||||
*关闭终端之后,保持 Linux 进程运行*
|
||||
|
||||
你也可以使用 `nohup` 命令,这个命令也可以在用户退出 shell 之后保证进程在后台继续运行。
|
||||
|
||||
```
|
||||
$ nohup tar -czf iso.tar.gz Templates/* &
|
||||
$ jobs
|
||||
|
||||
```
|
||||
|
||||

|
||||
|
||||
*关闭 shell 之后把 Linux 进程置于后台*
|
||||
|
||||
### 从控制终端脱离一个 Linux 进程
|
||||
|
||||
因此,为了彻底从控制终端脱离一个程序,对于图形用户界面 (GUI) 的程序例如 firefox 来说,使用下面的命令行格式会更有效:
|
||||
|
||||
```
|
||||
$ firefox </dev/null &>/dev/null &
|
||||
|
||||
```
|
||||
|
||||
在 Linux 上,/dev/null 是一个特殊的文件设备,它会忽略所有的写在它上面的数据,上述命令,输入来源和输出发送目标都是 /dev/null。
|
||||
|
||||
作为结束陈述,运行一个连接到控制终端的进程,作为用户你将会在你的终端上看到这个进程数据的许多行的输出,也包含错误信息。同样,当你关闭一个控制终端,你的进程和子进程都将会终止。
|
||||
|
||||
重要的是,对于这个主题任何的问题或者观点,通过下面的评论联系我们。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: http://www.tecmint.com/run-linux-command-process-in-background-detach-process/
|
||||
|
||||
作者:[Aaron Kili][a]
|
||||
译者:[yangmingming](https://github.com/yangmingming)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: http://www.tecmint.com/author/aaronkili/
|
||||
[1]:http://www.tecmint.com/wp-content/uploads/2016/10/Put-Linux-Process-in-Background.png
|
||||
[2]:http://www.tecmint.com/wp-content/uploads/2016/10/Keep-Linux-Processes-Running.png
|
||||
[3]:http://www.tecmint.com/wp-content/uploads/2016/10/Linux-Process-Running-in-Background-Message.png
|
||||
[4]:https://linux.cn/article-7802-1.html
|
||||
[5]:http://www.tecmint.com/wp-content/uploads/2016/10/Start-Linux-Process-in-Background.png
|
||||
[6]:http://www.tecmint.com/wp-content/uploads/2016/10/Run-Linux-Command-in-Background.png
|
||||
[7]:https://linux.cn/article-7802-1.html
|
||||
[8]:http://www.tecmint.com/monitor-linux-processes-and-set-process-limits-per-user/
|
@ -0,0 +1,73 @@
|
||||
苹果新的文件系统 APFS 比 HFS+ 强在哪里?
|
||||
===============
|
||||
|
||||

|
||||
|
||||
如果你一直关注苹果最新版的 macOS 的消息,你可能已经注意到苹果文件系统 APFS。这是不太让人感冒的话题之一。然而,它是支撑了操作系统用户体验的核心结构。APFS 将在 2017 年之前完成,不过你现在可以在 Sierra(最新版的 macOS) 上面体验一番开发者预览版。
|
||||
|
||||
### 特色与改进
|
||||
|
||||
先快速科普一下,**文件系统**是操作系统用于存储和检索数据的基本结构,不同的文件系统采用不同的方式来实现这个任务。随着计算机变得越来越快,新生代的文件系统已经从计算机速度的提升中获益,以提供新功能和适应现代存储需求。
|
||||
|
||||
HFS+,作为今天新一代 Mac 的附带文件系统,已经 18 岁了。它的祖先 HFS 比 Tom Cruise 的兄弟情影片“壮志凌云”还要老。它有点像一辆老丰田。它仍然可以工作(也许惊人的好),但是它不再得到人们的嘉奖。
|
||||
|
||||
APFS 不完全是 HFS+ 的升级版,因为相对现在而言,它是一个大幅度的飞跃。虽然这对苹果用户来说是一个重大的升级,但似乎这看起来更像是苹果赶上了其它系统,而不是超越了它们。然而,更新还进展得非常慢。
|
||||
|
||||
### 克隆和数据完整性
|
||||
|
||||

|
||||
|
||||
APFS 使用称为写时复制(copy-on-write)的方案来生成重复文件的即时克隆。在 HFS+ 下,当用户复制文件的时候,每一个比特(二进制中的“位”)都会被复制。而 APFS 则通过操作元数据并分配磁盘空间来创建克隆。但是,在修改复制的文件之前都不会复制任何比特。当克隆体与原始副本分离的时候,那些改动(并且只有那些改动)才会被保存。
|
||||
|
||||
写时复制还提高了数据的完整性。在其它系统下,如果你卸载卷导致覆写操作挂起的话,你可能会发现你的文件系统有一部分与其它部分不同步。写时复制则通过将改动写入到可用的磁盘空间而不是覆盖旧文件来避免这个问题。直到写入操作成功完成前,旧文件都是正式版本。只有当新文件被成功复制时,旧文件才会被清除。
|
||||
|
||||
### 系统快照
|
||||
|
||||

|
||||
|
||||
快照是写时复制架构给你带来的一个主要的升级。快照是文件系统在某个时间点的一个只读的可装载映像。随着文件系统发生改动,只有改动的比特会被更改。这可以让备份更简单,更可靠。考虑到时间机器(一个苹果出品的备份工具)已经成为硬链接的痛点,这可能是一个重大的升级。
|
||||
|
||||
### 输入/输出的服务质量(QoS)
|
||||
|
||||
你可能已经在你的路由器说明书看到了服务质量(QoS)这个名词。QoS 优先分配带宽使用以避免降低优先任务的速度。在你的路由器上,它采用用户定义的规则来为指定任务提供最大的带宽。据报道,苹果的 QoS 会优先考虑用户操作,例如活跃窗口。而诸如时间机器备份这些后台任务将会被降级。所以,这意味着更少的闲暇时光了?
|
||||
|
||||
### 本地加密
|
||||
|
||||

|
||||
|
||||
在后斯诺登时代,加密成为众所关注的了。越来越多的苹果产品正在强调其系统安全性。内置强大的加密机制并不让人感到意外。包括 APFS 在内,苹果正在采用更加细致入微的加密方案,要么不加密,要么就将加密进行到底。用户可以使用单个密钥来为所有数据加密,或者使用多个加密密钥分别锁定单个文件和文件夹。当然,你也可以不加密,只要你对坏蛋无所忌惮。
|
||||
|
||||
### 固态硬盘和闪存优化
|
||||
|
||||

|
||||
|
||||
闪存优化已经被列为 APFS 的一个亮点功能,不过它的实现并没有那么振奋人心。苹果选择将一些典型的固态硬盘芯片的处理功能迁移到操作系统,而没有深度系统集成的优势。这更像是让文件系统感知固态硬盘,而不是为它们做优化。
|
||||
|
||||
### 动态分区调整
|
||||
|
||||

|
||||
|
||||
APFS 驱动器的逻辑分区可以动态调整自身大小。用户只需指定所需分区的数量,然后文件系统会在运行时进行磁盘分配。每个分区只占用其用于存储文件的磁盘空间。剩余的磁盘空间会由任何分区获取。这种设计很整洁,不过比起其它文件系统,这更像是元文件夹。
|
||||
|
||||
### 结论
|
||||
|
||||
这是否重要?对于开发者和高级用户来说真是棒极了。对于一般的 Mac 用户应该没有太多的外部差异。虽然升级是重大的举措,但仍然存在一些缺失的部分。本地压缩显然还没有,对用户数据进行的校验也没有。当然,2017 年还没到,一切皆有可能,让我们拭目以待。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.maketecheasier.com/apple-file-system-better-than-hfs/
|
||||
|
||||
作者:[Alexander Fox][a]
|
||||
译者:[OneNewLife](https://github.com/OneNewLife)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:https://www.maketecheasier.com/author/alexfox-2-2-2/
|
||||
[1]:https://www.maketecheasier.com/apple-file-system-better-than-hfs/#respond
|
||||
[3]:https://www.maketecheasier.com/schedule-windows-empty-recycle-bin/
|
||||
[4]:https://www.maketecheasier.com/manage-automatic-wordpress-updates/
|
||||
[5]:mailto:?subject=What%20is%20Apple%20File%20System%20and%20Why%20is%20it%20Better%20than%20HFS+?&body=https%3A%2F%2Fwww.maketecheasier.com%2Fapple-file-system-better-than-hfs%2F
|
||||
[6]:http://twitter.com/share?url=https%3A%2F%2Fwww.maketecheasier.com%2Fapple-file-system-better-than-hfs%2F&text=What+is+Apple+File+System+and+Why+is+it+Better+than+HFS%2B%3F
|
||||
[7]:http://www.facebook.com/sharer.php?u=https%3A%2F%2Fwww.maketecheasier.com%2Fapple-file-system-better-than-hfs%2F
|
||||
[8]:https://www.maketecheasier.com/category/mac-tips/
|
@ -0,0 +1,202 @@
|
||||
如何在 Arch Linux 的终端里设定 WiFi 网络
|
||||
===
|
||||
|
||||

|
||||
|
||||
如果你使用的是其他 [Linux 发行版][16] 而不是 [Arch][15] CLI,那么可能会不习惯在终端里设置 WiFi。尽管整个过程有点简单,不过我还是要讲一下。在这篇文章里,我将带领新手们通过一步步的设置向导,把你们的 Arch Linux 接入到你的 WiFi 网络里。
|
||||
|
||||
在 Linux 里有很多程序来设置无线连接,我们可以用 **ip** 和 **iw** 来配置因特网连接,但是对于新手来说有点复杂。所以我们会使用 **netctl** 命令,这是一个基于命令行的工具,用来通过配置文件来设置和管理网络连接。
|
||||
|
||||
注意:所有的设定都需要 root 权限,或者你也可以使用 sudo 命令来完成。
|
||||
|
||||
### 搜索网络
|
||||
|
||||
运行下面的命令来查看你的网络接口:
|
||||
|
||||
```
|
||||
iwconfig
|
||||
```
|
||||
|
||||
运行如下命令启用你的网络接口,如果没有启用的话:
|
||||
|
||||
```
|
||||
ip link set interface up
|
||||
```
|
||||
|
||||
运行下面的命令搜索可用的 WiFi 网络。可以向下翻页来查看。
|
||||
|
||||
```
|
||||
iwlist interface scan | less
|
||||
```
|
||||
|
||||
**注意:** 命令里的 interface 是之前用 **iwconfig** 获取到的实际网络接口。
|
||||
|
||||
扫描完,如果不使用该接口可以运行如下命令关闭:
|
||||
|
||||
```
|
||||
ip link set interface down
|
||||
```
|
||||
|
||||
### 使用 netctl 配置 Wi-Fi:
|
||||
|
||||
在使用 `netctl` 设置连接之前,你必须先检查一下你的网卡在 Linux 下的兼容性。
|
||||
|
||||
运行命令:
|
||||
|
||||
```
|
||||
lspci -k
|
||||
```
|
||||
|
||||
这条命令是用来检查内核是否加载了你的无线网卡驱动。输出必须是像这样的:
|
||||
|
||||

|
||||
|
||||
如果内核没有加载驱动,你就必须使用有线连接来安装一下。这里是 Linux 无线网络的官方维基页面:[https://wireless.wiki.kernel.org/][11]。
|
||||
|
||||
如果你的无线网卡和 Linux 兼容,你可以使用 `netctl configuration`。
|
||||
|
||||
`netctl` 使用配置文件,这是一个包含连接信息的文件。创建这个文件有简单和困难两种方式。
|
||||
|
||||
#### 简单方式 – Wifi-menu
|
||||
|
||||
如果你想用 `wifi-menu`,必须安装 `dialog`。
|
||||
|
||||
1. 运行命令: `wifi-menu`
|
||||
2. 选择你的网络
|
||||
|
||||

|
||||
3. 输入正确的密码并等待
|
||||
|
||||

|
||||
|
||||
如果没有连接失败的信息,你可以用下面的命令确认下:
|
||||
|
||||
```
|
||||
ping -c 3 www.google.com
|
||||
```
|
||||
|
||||
哇!如果你看到正在 ping,意味着网络设置成功。你现在已经在 Arch Linux 下连上 WiFi 了。如果有任何问题,可以倒回去重来。也许漏了什么。
|
||||
|
||||
#### 困难方式
|
||||
|
||||
比起上面的 `wifi-menu` 命令,这种方式会难一点点,所以我叫做困难方式。在上面的命令里,网络配置会自动生成。而在困难方式里,我们将手动修改配置文件。不过不要担心,也没那么难。那我们开始吧!
|
||||
|
||||
1. 首先第一件事,你必须要知道网络接口的名字,通常会是 `wlan0` 或 `wlp2s0`,但是也有很多例外。要确认你自己的网络接口,输入 `iwconfig` 命令并记下来。
|
||||
|
||||
[][8]
|
||||
|
||||
2. 运行命令:
|
||||
|
||||
```
|
||||
cd /etc/netctl/examples
|
||||
```
|
||||
|
||||
在这个目录里,有很多不同的配置文件例子。
|
||||
|
||||
3. 拷贝将用到的配置文件例子到 `/etc/netctl/your_profile`
|
||||
|
||||
```
|
||||
cp /etc/netctl/examples/wireless-wpa /etc/netctl/your_profile
|
||||
```
|
||||
|
||||
4. 你可以用这个命令来查看配置文件内容: `cat /etc/netctl/your_profile`
|
||||
|
||||

|
||||
|
||||
5. 用 `vi` 或者 `nano` 编辑你的配置文件的下面几个部分:
|
||||
|
||||
```
|
||||
nano /etc/netctl/your_profile
|
||||
```
|
||||
|
||||
- `Interface`:比如说 `wlan0`
|
||||
- `ESSID`:你的无线网络名字
|
||||
- `key`:你的无线网络密码
|
||||
|
||||
**注意:**
|
||||
|
||||
如果你不知道怎么用 `nano`,打开文件后,编辑要修改的地方,完了按 `ctrl+o`,然后回车,然后按 `ctrl+x`。
|
||||
|
||||

|
||||
|
||||
### 运行 netctl
|
||||
|
||||
1. 运行命令:
|
||||
```
|
||||
cd /etc/netctl
|
||||
ls
|
||||
```
|
||||
|
||||
你一定会看到 `wifi-menu` 生成的配置文件,比如 `wlan0-SSID`;或者你选择了困难方式,你一定会看到你自己创建的配置文件。
|
||||
|
||||
2. 运行命令启动连接配置:`netctl start your_profile`。
|
||||
|
||||
3. 用下面的命令测试连接:
|
||||
|
||||
```
|
||||
ping -c 3 www.google.com
|
||||
```
|
||||
输出看上去像这样:
|
||||

|
||||
|
||||
4. 最后,你必须运行下面的命令:`netctl enable your_profile`。
|
||||
|
||||
```
|
||||
netctl enable your_profile
|
||||
```
|
||||
这样将创建并激活一个 systemd 服务,然后开机时自动启动。然后欢呼吧!你在你的 Arch Linux 里配置好 wifi 网络啦。
|
||||
|
||||
### 其他工具
|
||||
|
||||
你还可以使用其他程序来设置无线连接:
|
||||
|
||||
iw:
|
||||
|
||||
1. `iw dev wlan0 link` – 状态
|
||||
2. `iw dev wlan0 scan` – 搜索网络
|
||||
3. `iw dev wlan0 connect your_essid` – 连接到开放网络
|
||||
4. `iw dev wlan0 connect your_essid key your_key` - 使用 16 进制密钥连接到 WEP 加密的网络
|
||||
|
||||
wpa_supplicant
|
||||
|
||||
- [https://wiki.archlinux.org/index.php/WPA_supplicant][4]
|
||||
|
||||
Wicd
|
||||
|
||||
- [https://wiki.archlinux.org/index.php/wicd][3]
|
||||
|
||||
NetworkManager
|
||||
|
||||
- [https://wiki.archlinux.org/index.php/NetworkManager][2]
|
||||
|
||||
### 总结
|
||||
|
||||
会了吧!我提供了在 **Arch Linux** 里接入 WiFI 网络的三种方式。这里有一件事我再强调一下,当你执行第一条命令的时候,请记住你的网络接口名字。在接下来搜索网络的命令里,请使用你的网络接口名字比如 `wlan0` 或 `wlp2s0`(上一个命令里得到的),而不是用 interface 这个词。如果你碰到任何问题,可以在下面的评论区里直接留言给我。然后别忘了在你的朋友圈里和大家分享这篇文章哦。谢谢!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: http://www.linuxandubuntu.com/home/how-to-setup-a-wifi-in-arch-linux-using-terminal
|
||||
|
||||
作者:[Mohd Sohail][a]
|
||||
译者:[zpl1025](https://github.com/zpl1025)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: http://www.linuxandubuntu.com/contact-us.html
|
||||
[1]:http://www.linuxandubuntu.com/uploads/2/1/1/5/21152474/wifi-menu-to-setup-wifi-in-arch_orig.png
|
||||
[2]:https://wiki.archlinux.org/index.php/NetworkManager
|
||||
[3]:https://wiki.archlinux.org/index.php/wicd
|
||||
[4]:https://wiki.archlinux.org/index.php/WPA_supplicant
|
||||
[5]:http://www.linuxandubuntu.com/uploads/2/1/1/5/21152474/check-internet-connection-in-arch-linux_orig.png
|
||||
[6]:http://www.linuxandubuntu.com/uploads/2/1/1/5/21152474/edit-network-profile-in-arch_orig.png
|
||||
[7]:http://www.linuxandubuntu.com/uploads/2/1/1/5/21152474/view-network-profile-in-arch-linux_orig.png
|
||||
[8]:http://www.linuxandubuntu.com/uploads/2/1/1/5/21152474/scan-wifi-networks-in-arch-linux-cli_orig.png
|
||||
[9]:http://www.linuxandubuntu.com/uploads/2/1/1/5/21152474/wifi-menu-type-wifi-password-in-arch_orig.png?605
|
||||
[10]:http://www.linuxandubuntu.com/home/5-best-arch-linux-based-linux-distributions
|
||||
[11]:https://wireless.wiki.kernel.org/
|
||||
[12]:http://www.linuxandubuntu.com/uploads/2/1/1/5/21152474/arch-wifi-find-kernel-compatibility_orig.png
|
||||
[13]:http://www.linuxandubuntu.com/home/arch-linux-take-your-linux-knowledge-to-next-level-review
|
||||
[14]:http://www.linuxandubuntu.com/home/category/arch-linux
|
||||
[15]:http://www.linuxandubuntu.com/home/arch-linux-take-your-linux-knowledge-to-next-level-review
|
||||
[16]:http://linuxandubuntu.com/home/category/distros
|
@ -0,0 +1,64 @@
|
||||
两款免费的 Linux 桌面录制工具:SimpleScreenRecorder 和 Kazam
|
||||
====
|
||||
|
||||
> 桌面录制工具可以帮做我们快速高效的制作教学视频和在线示范。
|
||||
|
||||

|
||||
|
||||
一图胜千言,但一段视频演示则可以让你不用大费口舌。我是一个“视觉学习者”,亲眼目睹一件事情的发生对我的学习大有裨益。我也曾观察发现,如果学生实际看到应用程序的设置流程或者代码的编写过程,他们就能从中受益良多。所以,录屏工具是制作教学视频的绝佳工具。在本文中我将介绍一下两款开源桌面录制工具: [SimpleScreenRecorder][4] 和 [Kazam][3]。
|
||||
|
||||
### SimpleScreenRecorder
|
||||
|
||||
使用 SimpleScreenRecorder 能够轻松录制桌面动作,它拥有直观的用户界面以及多样的编码方式,如 MP4、OGG、[Matroska][2] 或 [WebM][1] 格式。 SimpleScreenRecorder 遵从 GPL 协议发行,运行在 Linux 上。
|
||||
|
||||
在安装运行 SimpleScreenRecorder 后,你可以轻松选择录制整个桌面、指定窗口或者一个自定义的区域。我比较偏爱最后这种方式,因为这样我可以使我的学生把注意力集中在我想让他们注意的地方。你还可以在设置中选择是否隐藏光标、调整录制帧率(默认帧率为 30fps)、视频压缩比例或者调整音频后端(如 ALSA、JACK 或 PusleAudio)。
|
||||
|
||||
由于 SimpleScreenRecorder 使用了 libav/ffmpeg 库进行编码,故而支持多种文件格式和视频编码方式。可以使用不同的配置文件(编码更快的配置文件意味着更大的体积),包括 YouTube 和 1000kbps – 3000kbps 的 LiveStream。
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
配置完毕后,单击“开始录制”按钮或者使用自定义的快捷键就可以轻松开始录制屏幕啦~
|
||||
|
||||

|
||||
|
||||
你还能在设置中开启提示音功能,它会开始录制和录制结束时给你声音的提示。屏幕录制完成后,你可以对视频文件进行编辑或者直接上传到 YouTube、Vimeo 等视频网站上。
|
||||
|
||||
SimpleScreenRecorder 的[官方网站][4]上还有大量说明文档,其中包括设置、录制、上传等方面的帮助手册和针对多种Linux发行版的安装说明。
|
||||
|
||||
### Kazam
|
||||
|
||||
Kazam 桌面录制工具同样是遵循 GPL 协议的软件。同时和 SimpleScreenRecorder 一样,Kazam 易于上手,界面直观。安装运行 Kazam 之后,你可以设置选择录制整个桌面、指定窗口或是一个自定义的区域。(LCTT 译注:关于自定义区域录制一部分的内容与 SimpleScreenRecorder 介绍中的内容基本相似,略过) ,你还可以选择记录鼠标的移动轨迹。我最中意 Kazam 的一点是延时录制的功能,这在制作视频教程的时候必不可少。
|
||||
|
||||
在“文件|设置”菜单下可以轻松对 Kazam 进行个性化设置,比如可以选择扬声器或是麦克风中的音源、关闭倒计时提示等等。
|
||||
|
||||

|
||||
|
||||
在设置页的第二个选项卡中可以进行视频录制设置。Kazam 默认录制帧率为 15fps,编码格式为 H264(MP4)。其它可供选择的格式有 VP8(WEBM)、HUFFYUV、Lossless JPEG 以及 RAW AVI。录制好的文件会以附加一个预设的前缀来命名,并自动保存在默认目录下,你可以随时修改这些设置。
|
||||
|
||||

|
||||
|
||||
设置屏幕截图同样很简单。你可以选择 Nikon D80 或 Canon 7D 的快门音效,也可以干脆关掉他们。截图文件是自动存放的。除非你关闭这一功能。
|
||||
|
||||

|
||||
|
||||
录制好的视频将会存储在你选定的目录下,随时可以上传到你喜欢的视频分享网站或是教程网站上。
|
||||
|
||||
是时候利用 Linux 和录屏工具让你的课堂焕然一新了!如果你还有其他的屏幕录制工具或是使用技巧,记得在评论里与我交流哦~
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/education/16/10/simplescreenrecorder-and-kazam
|
||||
|
||||
作者:[Don Watkins][a]
|
||||
译者:[HaohongWANG](https://github.com/HaohongWANG)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/don-watkins
|
||||
[1]:https://www.webmproject.org/
|
||||
[2]:https://www.matroska.org/technical/whatis/index.html
|
||||
[3]:https://launchpad.net/kazam
|
||||
[4]:http://www.maartenbaert.be/simplescreenrecorder/
|
@ -0,0 +1,70 @@
|
||||
7-Zip vs WinRAR vs WinZIP: 最好的文件压缩工具对比
|
||||
==================
|
||||
|
||||

|
||||
|
||||
在拳击界里有阿里、弗雷泽和福尔曼。在游戏机界里有任天堂、索尼和微软,在 PC 压缩软件领域里有7-Zip、WinRAR 和 WinZIP。我要发动这个软件的对决吗?也许,不管怎么说它一直是一个重要的软件。
|
||||
|
||||
这三个程序有同样的功能,你可以获取一堆你电脑上的文件然后打包压缩它们到一个归档,压缩它们的文件大小,直到有人决定取出它们。它们都易于使用,但是哪个做的更好?我拿它们做了一个测试来找出答案。
|
||||
|
||||
注意:虽然还有很多其它的压缩格式,但 Winzip、7Zip 和 WinRAR 是三个 Windows 上最流行的压缩工具。那就是为什么我们只对比这三个工具。
|
||||
|
||||
注意:为了测试,我压缩了一堆未压缩的视频文件,总计占用 1.3GB 的空间。我还使用最好的压缩设置来测试它们而不是默认的设置。对于每个项目,我描述了如何使这些设置。
|
||||
|
||||
### 7-Zip 出了免费这一大招
|
||||
|
||||
值得一说的是,开源的 7-Zip 是免费的,没有附加条件的这一块已经拥有优势。WinRAR 本质上是免费的,除了你必须忍受每次打开它时恼人的提示告诉你试用过期了。(你付款主要是为了摆脱这个提示。)而另一方面,WinZip 在试用期结束后会锁定你。
|
||||
|
||||
### WinZip
|
||||
|
||||
在今天的世界里,我们莫名其妙地期望的一切与软件相关的都是免费的,与我们的预期相悖,WinZip 大胆的在试用期后收费 £25.95。不过,也许是因为它比竞争对手做得更好,才让其标上这么大胆的价格标签?让我们来看看。
|
||||
|
||||
WinZip 有一个选项可以把文件压缩成 .zipx 格式,它生成拥有比 .zip 和其它竞争者更高的压缩比。要做到这一点,选择并右键单击要压缩文件,然后单击“WinZip - >添加到压缩”文件。当 WinZip 打开后,选择“压缩类型”下的“.Zipx”,然后开始压缩。
|
||||
|
||||
这里是我们使用两种 WinZip 压缩方法的结果:
|
||||
|
||||
* .Zip: 855MB (34% 压缩)
|
||||
* .Zipx: 744MB (43% 压缩)
|
||||
|
||||

|
||||
|
||||
### WinRAR
|
||||
|
||||
WinRAR 压缩的文件是 RAR 格式(这是它自己独有的名字),也有一些技巧可以获得最大的压缩。
|
||||
|
||||
一旦你选择要压缩文件,右击它们,请单击“添加到压缩文件”,然后勾选“创建可靠的归档”复选框。下一步,单击“压缩方式”的下拉列表,将其更改为“最佳”。WinRAR 的还有一个叫做 RAR5 的明显增强的压缩方法,所以我测试了这一点,以及标准的压缩方法。下面是我们得到的:
|
||||
|
||||
* .rar: 780MB (40% 压缩)
|
||||
* .rar5: 778MB (40% 压缩)
|
||||
|
||||

|
||||
|
||||
### 7-Zip
|
||||
|
||||
它没有评估版或付费版,但是随之而来的压缩质量如何?要正确测试它,选择要压缩文件,右击它们,选择“添加到压缩文件”,然后选择7-Zip。
|
||||
|
||||
在新的窗口中更改压缩方法 LZMA2(如果你有一个 4 核或更强的 CPU),压缩级别设置为极端,然后压缩!这里的结果:
|
||||
|
||||
* .7z: 758MB (42% 压缩)
|
||||
|
||||

|
||||
|
||||
### 结论
|
||||
|
||||
基于以上结果,我将继续坚持使用 7-zip。和技术上的“赢家” WinZip 比,这 1% 差别的压缩水平不足以为此花钱。
|
||||
|
||||

|
||||
|
||||
或许你并不想下载任何第三方软件,在这种情况下,你可以使用 Windows 的内置压缩工具。要使用它,只需右键单击任何你想压缩的文件,选择“发送到”,然后“压缩文件夹”。它只把文件压缩到 892 MB的水平(31%),但它更便捷快速,而且是免费和内置的,所以我们还有抱怨吗?
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.maketecheasier.com/7-zip-vs-winrar-vs-winzip/
|
||||
|
||||
作者:[Robert Zak][a]
|
||||
译者:[wyangsun](https://github.com/wyangsun)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://www.maketecheasier.com/author/robzak/
|
@ -0,0 +1,117 @@
|
||||
在 Linux 上检测硬盘上的坏道和坏块
|
||||
===
|
||||
|
||||
让我们从坏道和坏块的定义开始说起,它们是一块磁盘或闪存上不再能够被读写的部分,一般是由于磁盘表面特定的[物理损坏][7]或闪存晶体管失效导致的。
|
||||
|
||||
随着坏道的继续积累,它们会对你的磁盘或闪存容量产生令人不快或破坏性的影响,甚至可能会导致硬件失效。
|
||||
|
||||
同时还需要注意的是坏块的存在警示你应该开始考虑买块新磁盘了,或者简单地将坏块标记为不可用。
|
||||
|
||||
因此,在这篇文章中,我们通过几个必要的步骤,使用特定的[磁盘扫描工具][6]让你能够判断 Linux 磁盘或闪存是否存在坏道。
|
||||
|
||||
以下就是步骤:
|
||||
|
||||
### 在 Linux 上使用坏块工具检查坏道
|
||||
|
||||
坏块工具可以让用户扫描设备检查坏道或坏块。设备可以是一个磁盘或外置磁盘,由一个如 `/dev/sdc` 这样的文件代表。
|
||||
|
||||
首先,通过超级用户权限执行 [fdisk 命令][5]来显示你的所有磁盘或闪存的信息以及它们的分区信息:
|
||||
|
||||
```
|
||||
$ sudo fdisk -l
|
||||
|
||||
```
|
||||
|
||||
[][4]
|
||||
|
||||
*列出 Linux 文件系统分区*
|
||||
|
||||
然后用如下命令检查你的 Linux 硬盘上的坏道/坏块:
|
||||
|
||||
```
|
||||
$ sudo badblocks -v /dev/sda10 > badsectors.txt
|
||||
|
||||
```
|
||||
|
||||
[][3]
|
||||
|
||||
*在 Linux 上扫描硬盘坏道*
|
||||
|
||||
上面的命令中,badblocks 扫描设备 `/dev/sda10`(记得指定你的实际设备),`-v` 选项让它显示操作的详情。另外,这里使用了输出重定向将操作结果重定向到了文件 `badsectors.txt`。
|
||||
|
||||
如果你在你的磁盘上发现任何坏道,卸载磁盘并像下面这样让系统不要将数据写入回报的扇区中。
|
||||
|
||||
你需要执行 `e2fsck`(针对 ext2/ext3/ext4 文件系统)或 `fsck` 命令,命令中还需要用到 `badsectors.txt` 文件和设备文件。
|
||||
|
||||
`-l` 选项告诉命令将在指定的文件 `badsectors.txt` 中列出的扇区号码加入坏块列表。
|
||||
|
||||
```
|
||||
------------ 针对 for ext2/ext3/ext4 文件系统 ------------
|
||||
$ sudo e2fsck -l badsectors.txt /dev/sda10
|
||||
|
||||
或
|
||||
|
||||
------------ 针对其它文件系统 ------------
|
||||
$ sudo fsck -l badsectors.txt /dev/sda10
|
||||
|
||||
```
|
||||
|
||||
### 在 Linux 上使用 Smartmontools 工具扫描坏道
|
||||
|
||||
这个方法对带有 S.M.A.R.T(Self-Monitoring, Analysis and Reporting Technology,自我监控分析报告技术)系统的现代磁盘(ATA/SATA 和 SCSI/SAS 硬盘以及固态硬盘)更加的可靠和高效。S.M.A.R.T 系统能够帮助检测,报告,以及可能记录它们的健康状况,这样你就可以找出任何可能出现的硬件失效。
|
||||
|
||||
你可以使用以下命令安装 `smartmontools`:
|
||||
|
||||
```
|
||||
------------ 在基于 Debian/Ubuntu 的系统上 ------------
|
||||
$ sudo apt-get install smartmontools
|
||||
|
||||
------------ 在基于 RHEL/CentOS 的系统上 ------------
|
||||
$ sudo yum install smartmontools
|
||||
|
||||
```
|
||||
|
||||
安装完成之后,使用 `smartctl` 控制磁盘集成的 S.M.A.R.T 系统。你可以这样查看它的手册或帮助:
|
||||
|
||||
```
|
||||
$ man smartctl
|
||||
$ smartctl -h
|
||||
|
||||
```
|
||||
|
||||
然后执行 `smartctrl` 命令并在命令中指定你的设备作为参数,以下命令包含了参数 `-H` 或 `--health` 以显示 SMART 整体健康自我评估测试结果。
|
||||
|
||||
```
|
||||
$ sudo smartctl -H /dev/sda10
|
||||
|
||||
```
|
||||
|
||||
[][2]
|
||||
|
||||
*检查 Linux 硬盘健康*
|
||||
|
||||
上面的结果指出你的硬盘很健康,近期内不大可能发生硬件失效。
|
||||
|
||||
要获取磁盘信息总览,使用 `-a` 或 `--all` 选项来显示关于磁盘所有的 SMART 信息,`-x` 或 `--xall` 来显示所有关于磁盘的 SMART 信息以及非 SMART 信息。
|
||||
|
||||
在这个教程中,我们覆盖了有关[磁盘健康诊断][1]的重要话题,你可以下面的反馈区来分享你的想法或提问,并且记得多回来看看。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: http://www.tecmint.com/check-linux-hard-disk-bad-sectors-bad-blocks/
|
||||
|
||||
|
||||
作者:[Aaron Kili][a]
|
||||
译者:[alim0x](https://github.com/alim0x)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: http://www.tecmint.com/author/aaronkili/
|
||||
[1]:http://www.tecmint.com/defragment-linux-system-partitions-and-directories/
|
||||
[2]:http://www.tecmint.com/wp-content/uploads/2016/10/Check-Linux-Hard-Disk-Health.png
|
||||
[3]:http://www.tecmint.com/wp-content/uploads/2016/10/Scan-Hard-Disk-Bad-Sectors-in-Linux.png
|
||||
[4]:http://www.tecmint.com/wp-content/uploads/2016/10/List-Linux-Filesystem-Partitions.png
|
||||
[5]:http://www.tecmint.com/fdisk-commands-to-manage-linux-disk-partitions/
|
||||
[6]:http://www.tecmint.com/ncdu-a-ncurses-based-disk-usage-analyzer-and-tracker/
|
||||
[7]:http://www.tecmint.com/defragment-linux-system-partitions-and-directories/
|
@ -0,0 +1,122 @@
|
||||
如何在 Ubuntu 命令行下管理浏览器书签
|
||||
=======
|
||||
|
||||

|
||||
|
||||
浏览器书签虽然不常被提及,但是作为互联网浏览的一部分。没有好的书签功能,网站链接可能会丢失,下次再不能访问。这就是为什么一个好的书签管理器很重要。
|
||||
|
||||
所有的现代浏览器都提供了一些形式的管理工具,虽然它们严格上来讲功能较少。如果你已经厌倦了这些内置在浏览器中的主流工具,你或许想要寻找一个替代品。这里介绍 **Buku**:一个命令行下的书签管理器。它不仅可以管理你的书签,还可以给它们加密,将它们保存在一个数据库中等等。下面是如何安装它。
|
||||
|
||||
### 安装
|
||||
|
||||

|
||||
|
||||
Buku 不是非常流行。因此,用户需要自己编译它。然而,在 Ubuntu 上安装实际上很简单。打开终端并且使用 apt 安装`git` 和 `python3`,这两个工具在构建中很关键。
|
||||
|
||||
```
|
||||
sudo apt python3-cryptography python3-bs4
|
||||
```
|
||||
|
||||
装完所需的工具后,就可以拉取源码了。
|
||||
|
||||
```
|
||||
git clone https://github.com/jarun/Buku/.
|
||||
cd Buku
|
||||
```
|
||||
|
||||
最后要安装它,只需要运行 `make` 命令。在这之后就可以在终端中输入 `buku`来运行 Buku 了。
|
||||
|
||||
```
|
||||
sudo make install
|
||||
```
|
||||
|
||||
**注意**:虽然这份指导针对的是 Ubuntu,但是 Buku 可以在任何 Linux 发行版中用相似的方法安装。
|
||||
|
||||
### 导入书签
|
||||
|
||||

|
||||
|
||||
要将书签直接导入 Buku 中,首先从浏览器中将书签导出成一个 html 文件。接着,输入下面的命令:
|
||||
|
||||
```
|
||||
buku -i bookmarks.html
|
||||
```
|
||||
|
||||
最后,导入的书签会添加到 Buku 的数据库中。
|
||||
|
||||
### 导出书签
|
||||
|
||||

|
||||
|
||||
导出书签和导入一样简单。要导出所有的书签,使用下面的命令:
|
||||
|
||||
```
|
||||
buku -e bookmarks.html
|
||||
```
|
||||
|
||||
它会和其他书签管理器一样,将数据库中所有的书签导出成一个 html 文件。之后就可以用它做你任何要做的事情了!
|
||||
|
||||
### 打开书签
|
||||
|
||||

|
||||
|
||||
要打开一个书签,首先要搜索。这需要用 `-s` 选项。运行下面的命令来搜索:
|
||||
|
||||
```
|
||||
buku -s searchterm
|
||||
```
|
||||
|
||||
接着一旦找到匹配的结果,输入旁边的数字,书签将会在默认的浏览器中打开了。
|
||||
|
||||
### 加密
|
||||
|
||||
不像其他的书签管理器,Buku 可以加密你的数据。这对拥有“敏感”书签的用户而言很有用的功能。要加密数据库,使用 `-l` 标志来创建一个密码。
|
||||
|
||||
```
|
||||
buku -l
|
||||
```
|
||||
|
||||

|
||||
|
||||
数据库加锁后,没有输入密码将不能打开书签。要解密它,使用 `-k` 选项。
|
||||
|
||||
```
|
||||
buku -k
|
||||
```
|
||||
|
||||

|
||||
|
||||
### 其他功能
|
||||
|
||||
这个书签管理器有许多不同的功能。要了解其他的功能,使用 `--help` 选项。当使用这个选项后,所有的选项以及每个功能详细内容都会列出来。这个非常有用,由于用户经常忘记东西,并且有时可以打开一个备忘单也不错。
|
||||
|
||||
```
|
||||
buku --help
|
||||
```
|
||||
|
||||

|
||||
|
||||
### 总结
|
||||
|
||||
即使这个工具不是浏览器的一部分,它的功能比任何现在管理器提供的功能多。尽管事实是它在命令行中运行,但是也有很好的竞争力。书签对大部分人来言并不重要,但是哪些不喜欢现有选择以及喜欢 Linux 命令行的应该看一下 Buku。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.maketecheasier.com/manage-browser-bookmarks-ubuntu-command-line/
|
||||
|
||||
作者:[Derrik Diener][a]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://www.maketecheasier.com/author/derrikdiener/
|
||||
[1]:https://www.maketecheasier.com/manage-browser-bookmarks-ubuntu-command-line/#comments
|
||||
[2]:https://www.maketecheasier.com/author/derrikdiener/
|
||||
[3]:https://support.google.com/adsense/troubleshooter/1631343
|
||||
[4]:https://www.maketecheasier.com/hidden-google-games/
|
||||
[5]:https://www.maketecheasier.com/change-app-permissions-windows10/
|
||||
[6]:mailto:?subject=How%20to%20Manage%20Browser%20Bookmarks%20from%20the%20Ubuntu%20Command%20Line&body=https%3A%2F%2Fwww.maketecheasier.com%2Fmanage-browser-bookmarks-ubuntu-command-line%2F
|
||||
[7]:http://twitter.com/share?url=https%3A%2F%2Fwww.maketecheasier.com%2Fmanage-browser-bookmarks-ubuntu-command-line%2F&text=How+to+Manage+Browser+Bookmarks+from+the+Ubuntu+Command+Line
|
||||
[8]:http://www.facebook.com/sharer.php?u=https%3A%2F%2Fwww.maketecheasier.com%2Fmanage-browser-bookmarks-ubuntu-command-line%2F
|
||||
[9]:https://www.maketecheasier.com/category/linux-tips/
|
@ -0,0 +1,108 @@
|
||||
如何按最后修改时间对 ls 命令的输出进行排序
|
||||
============================================================
|
||||
|
||||
Linux 用户常常做的一个事情是,是在命令行[列出目录内容][1]。
|
||||
|
||||
我们已经知道,[ls][2] 和 [dir][3] 是两个可用在列出目录内容的 Linux 命令,前者是更受欢迎的,在大多数情况下,是用户的首选。
|
||||
|
||||
我们列出目录内容时,可以按照不同的标准进行排序,例如文件名、修改时间、添加时间、版本或者文件大小。可以通过指定一个特别的参数来使用这些文件的属性进行排序。
|
||||
|
||||
在这个简洁的 [ls 命令指导][4]中,我们将看看如何通过上次修改时间(日期和时分秒)[排序 ls 命令的输出结果][5] 。
|
||||
|
||||
让我们由执行一些基本的 [ls 命令][6]开始。
|
||||
|
||||
### Linux 基本 ls 命令
|
||||
|
||||
1、 不带任何参数运行 ls 命令将列出当前工作目录的内容。
|
||||
|
||||
```
|
||||
$ ls
|
||||
```
|
||||
|
||||

|
||||
|
||||
*列出工作目录的内容*
|
||||
|
||||
2、要列出任何目录的内容,例如 /etc 目录使用如下命令:
|
||||
|
||||
```
|
||||
$ ls /etc
|
||||
```
|
||||

|
||||
|
||||
*列出工作目录 /etc 的内容*
|
||||
|
||||
3、一个目录总是包含一些隐藏的文件(至少有两个),因此,要展示目录中的所有文件,使用`-a`或`-all`标志:
|
||||
|
||||
```
|
||||
$ ls -a
|
||||
```
|
||||
|
||||

|
||||
|
||||
*列出工作目录的隐藏文件*
|
||||
|
||||
4、你还可以打印输出的每一个文件的详细信息,例如文件权限、链接数、所有者名称和组所有者、文件大小、最后修改的时间和文件/目录名称。
|
||||
|
||||
这是由` -l `选项来设置,这意味着一个如下面的屏幕截图般的长长的列表格式。
|
||||
|
||||
```
|
||||
$ ls -l
|
||||
```
|
||||

|
||||
|
||||
*长列表目录内容*
|
||||
|
||||
### 基于日期和基于时刻排序文件
|
||||
|
||||
5、要在目录中列出文件并[对最后修改日期和时间进行排序][11],在下面的命令中使用`-t`选项:
|
||||
|
||||
```
|
||||
$ ls -lt
|
||||
```
|
||||
|
||||

|
||||
|
||||
*按日期和时间排序ls输出内容*
|
||||
|
||||
6、如果你想要一个基于日期和时间的逆向排序文件,你可以使用`-r`选项来工作,像这样:
|
||||
|
||||
```
|
||||
$ ls -ltr
|
||||
```
|
||||
|
||||

|
||||
|
||||
*按日期和时间排序的逆向输出*
|
||||
|
||||
我们将在这里结束,但是,[ls 命令][14]还有更多的使用信息和选项,因此,应该特别注意它或看看其它指南,比如《[每一个用户应该知道 ls 的命令技巧][15]》或《[使用排序命令][16]》。
|
||||
|
||||
最后但并非最不重要的,你可以通过以下反馈部分联系我们。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: http://www.tecmint.com/sort-ls-output-by-last-modified-date-and-time
|
||||
|
||||
作者:[Aaron Kili][a]
|
||||
译者:[zky001](https://github.com/zky001)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]:http://www.tecmint.com/author/aaronkili/
|
||||
[1]:http://www.tecmint.com/file-and-directory-management-in-linux/
|
||||
[2]:http://www.tecmint.com/15-basic-ls-command-examples-in-linux/
|
||||
[3]:http://www.tecmint.com/linux-dir-command-usage-with-examples/
|
||||
[4]:http://www.tecmint.com/tag/linux-ls-command/
|
||||
[5]:http://www.tecmint.com/sort-command-linux/
|
||||
[6]:http://www.tecmint.com/15-basic-ls-command-examples-in-linux/
|
||||
[7]:http://www.tecmint.com/wp-content/uploads/2016/10/List-Content-of-Working-Directory.png
|
||||
[8]:http://www.tecmint.com/wp-content/uploads/2016/10/List-Contents-of-Directory.png
|
||||
[9]:http://www.tecmint.com/wp-content/uploads/2016/10/List-Hidden-Files-in-Directory.png
|
||||
[10]:http://www.tecmint.com/wp-content/uploads/2016/10/ls-Long-List-Format.png
|
||||
[11]:http://www.tecmint.com/find-and-sort-files-modification-date-and-time-in-linux/
|
||||
[12]:http://www.tecmint.com/wp-content/uploads/2016/10/Sort-ls-Output-by-Date-and-Time.png
|
||||
[13]:http://www.tecmint.com/wp-content/uploads/2016/10/Sort-ls-Output-Reverse-by-Date-and-Time.png
|
||||
[14]:http://www.tecmint.com/tag/linux-ls-command/
|
||||
[15]:http://www.tecmint.com/linux-ls-command-tricks/
|
||||
[16]:http://www.tecmint.com/linux-sort-command-examples/
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user