Merge pull request #46 from LCTT/master

update 2017-05-15
This commit is contained in:
cinlen_0x05 2017-05-15 21:43:31 +08:00 committed by GitHub
commit 6ad99590ac
13 changed files with 1148 additions and 1162 deletions

View File

@ -0,0 +1,117 @@
如何在 Vim 中使用模式行进行文件特定的设置
============================================================
虽然[插件][4]毫无疑问是 Vim 最大的优势,然而,还有其它一些功能,使得它成为当今 Linux 用户中最强大、功能最丰富的文本编辑器/IDE 之一。其中一个功能就是可以根据文件做特定的设置。我们可以使用该编辑器的模式行Modeline特性来实现该功能。
在这篇文章中,我将讨论如何使用 Vim 的[模式行Modeline][5]特性来简单的理解一些例子。
在开始之前,值得提醒一下,这篇教程中提及的所有例子、命令和指令都已经在 Ubuntu 16.04 中使用 Vim 7.4 版本测试过。
### VIM 模式行
#### 用法
正如上面已经提到的, Vim 的模式行特性让你能够进行特定于文件的更改。比如,假设你想把项目中的一个特定文件中的所有制表符用空格替换,并且确保这个更改不会影响到其它所有文件。这是模式行帮助你完成你想做的事情的一个理想情况。
因此,你可以考虑将下面这一行加入文件的开头或结尾来完成这件事。
```
# vim: set expandtab:
```
LCTT 译注:模式行就是一行以注释符,如 `#`、`//`、`/*` 开头,间隔一个空格,以 `vim:` 关键字触发的设置命令。可参看http://vim.wikia.com/wiki/Modeline_magic
如果你是在 Linux 系统上尝试上面的练习来测试用例,很有可能它将不会像你所期望的那样工作。如果是这样,也不必担心,因为某些情况下,模式行特性需要先激活才能起作用(出于安全原因,在一些系统比如 Debian、Ubuntu、GGentoo 和 OSX 上默认情况下禁用)。
为了启用该特性,打开 `.vimrc` 文件(位于 `home` 目录),然后加入下面一行内容:
```
set modeline
```
现在,无论何时你在该文件输入一个制表符然后保存时(文件中已输入 `expandtab` 模式行命令的前提下),都会被自动转换为空格。
让我们考虑另一个用例。假设在 Vim 中, 制表符默认设置为 4 个空格,但对于某个特殊的文件,你想把它增加到 8 个。对于这种情况,你需要在文件的开头或末尾加上下面这行内容:
```
// vim: noai:ts=8:
```
现在,输入一个制表符,你会看到,空格的数量为 8 个。
你可能已经注意到我刚才说的,这些模式行命令需要加在靠近文件的顶部或底部。如果你好奇为什么是这样,那么理由是该特性以这种方式设计的。下面这一行(来自 Vim 官方文件)将会解释清楚:
> “模式行不能随意放在文件中的任何位置:它需要放在文件中的前几行或最后几行。`modelines` 变量控制 Vim 检查模式行在文件中的确切位置。请查看 `:help modelines` 。默认情况下,设置为 5 行。”
下面是 `:help modelines` 命令(上面提到的)输出的内容:
> 如果 `modeline` 已启用并且 `modelines` 给出了行数,那么便在相应位置查找 `set` 命令。如果 `modeline` 禁用或 `modelines` 设置的行数为 0 则不查找。
尝试把模式行命令置于超出 5 行的范围(距离文件底部和顶部的距离均超过 5 行),你会发现, 制表符将会恢复为 Vim 默认数目的空格 — 在我的情况里是 4 个空格。
然而,你可以按照自己的意愿改变默认行数,只需在你的 `.vimrc` 文件中加入下面一行命令
```
set modelines=[新值]
```
比如,我把值从 5 增加到了 10 。
```
set modelines=10
```
这意味着,现在我可以把模式行命令置于文件前 10 行或最后 10 行的任意位置。
继续,无论何时,当你在编辑一个文件的时候,你可以输入下面的命令(在 Vim 编辑器的命令模式下输入)来查看当前与命令行相关的设置以及它们最新的设置。
```
:verbose set modeline? modelines?
```
比如,在我的例子中,上面的命令产生了如下所示的输出:
```
modeline
Last set from ~/.vimrc
modelines=10
Last set from ~/.vimrc
```
关于 Vim 的模式行特性,你还需要知道一些重要的点:
* 默认情况下,当 Vim 以非兼容(`nocompatible`)模式运行时该特性是启用的,但需要注意的是,在一些发行版中,出于安全考虑,系统的 `vimrc` 文件禁用了该选项。
* 默认情况下,当以 root 权限编辑文件时,该特性被禁用(如果你是使用 `sudo` 方式打开该文件,那么该特性依旧能够正常工作)。
* 通过 `set` 来设置模式行,其结束于第一个冒号,而非反斜杠。不使用 `set`,则后面的文本都是选项。比如,`/* vim: noai:ts=4:sw=4 */` 是一个无效的模式行。
LCTT 译注:关于模式行中的 `set`,上述描述指的是:如果用 `set` 来设置,那么当发现第一个 `:` 时,表明选项结束,后面的 `*/` 之类的为了闭合注释而出现的文本均无关;而如果不用 `set` 来设置,那么以 `vim:` 起头的该行所有内容均视作选项。
#### 安全考虑
令人沮丧的是, Vim 的模式行特性可能会造成安全性问题。事实上,在过去,已经报道过多个和模式行相关的问题,包括 [shell 命令注入][6][任意命令执行][7]和[无授权访问][8]等。我知道,这些问题发生在很早的一些时候,现在应该已经修复好了,但是,这提醒了我们,模式行特性有可能会被黑客滥用。
### 结论
模式行可能是 Vim 编辑器的一个高级命令,但是它并不难理解。毫无疑问,它的学习曲线会有一些复杂,但是不需多问也知道,该特性是多么的有用。当然,出于安全考虑,在启用并使用该选项前,你需要对自己的选择进行权衡。
你有使用过模式行特性吗?你的体验是什么样的?记得在下面的评论中分享给我们。
--------------------------------------------------------------------------------
via: https://www.howtoforge.com/tutorial/vim-modeline-settings/
作者:[Ansh][a]
译者:[ucasFL](https://github.com/ucasFL)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://www.howtoforge.com/tutorial/vim-modeline-settings/
[1]:https://www.howtoforge.com/tutorial/vim-modeline-settings/#usage
[2]:https://www.howtoforge.com/tutorial/vim-modeline-settings/#vim-modeline
[3]:https://www.howtoforge.com/tutorial/vim-modeline-settings/#conclusion
[4]:https://linux.cn/article-7901-1.html
[5]:http://vim.wikia.com/wiki/Modeline_magic
[6]:https://tools.cisco.com/security/center/viewAlert.x?alertId=13223
[7]:http://usevim.com/2012/03/28/modelines/
[8]:https://tools.cisco.com/security/center/viewAlert.x?alertId=5169

View File

@ -0,0 +1,108 @@
CentOS 上最佳的第三方仓库
============================================================
![CentOS](https://www.linux.com/sites/lcom/files/styles/rendered_file/public/centos.png?itok=YRMQVk7U "CentOS")
> 从 Software Collections、EPEL 和 Remi 获得可靠的 CentOS 新版软件。
在 Red Hat 企业 LinuxRHEL 上,提供那些早已老掉牙的软件已经是企业级软件厂商的传统了。这倒不是因为他们懒,而确实是用户需要。很多公司像看待家具一样看待软件:我买一张桌子,能用一辈子,软件不应该也这样吗?
CentOS 作为 RHEL 的复制品有着同样的遭遇。虽然 Red Hat 还在为这些被厂商抛弃的过时软件提供支持、修补安全漏洞等,但如果你的应用依赖新版软件,你就得想办法了。 我在这个问题上不止一次碰壁。 LAMP 组合里任一个组件都需要其它所有组件能与其兼容,这有时就显得很麻烦。 比如说去年我就被 RHEL/CentOS 折腾得够呛。REHL/CentOS 第 6 版最高支持 PHP 5.3 ,第 7 版支持到 PHP 5.4 。而 PHP 5.3 早在 2014 年 8 月就到达 EOLEnd Of Life) ,不再被厂商支持了, PHP 5.4 的 EOL 在 2015 年 9 月, 5.5 则是 2016 年 7 月。 有太多古老的软件版本,包括 MySQL、Python 等,它们应该像木乃伊一样被展示在博物馆里,但它们却活在你的系统上。
那么,可怜的管理员们该怎么办呢?如果你跑着 RHEL/CentOS ,那应该先试试 [Software Collections][3],因为这是 Red Hat 唯一支持的新软件包源。 [Software Collections][3] 为 CentOS 设立了专门的仓库,安装和管理都和其它第三方仓库一样。但如果你用的是 RHEL 的,情况就有点不同了,具体请参考 [RHEL 的解决方法][4]。[Software Collections][3] 同样支持 Fedora 和 Scientific Linux 。
### 安装 Software Collections
在 CentOS 6/7 上安装 Software Collections 的命令如下:
```
$ sudo yum install centos-release-scl
```
`centos-release-scl-rh` 可能作为依赖包被同时安装。
然后就可以像平常一样搜索、安装软件包了:
```
$ yum search php7
[...]
rh-php70.x86_64 : Package that installs PHP 7.0
[...]
$ sudo yum install rh-php70
```
最后一件事就是启用你的新软件包:
```
$ scl enable rh-php70 bash
$ php -v
PHP 7.0.10
```
此命令会开启一个新的 bash 并配置好环境变量以便运行新软件包。 如果需要的话,你还得安装对应的扩展包,比如对于 Python 、PHP、MySQL 等软件包,有些配置文件也需要修改以指向新版软件(比如 Apache )。
这些 SCL 软件包在重启后不会激活。SCL 的设计初衷就是在不影响原有配置的前提下,让新旧软件能一起运行。不过你可以通过 `~/.bashrc` 加载 SCL 提供的 `enable` 脚本来实现自动启用。 SCL 的所有软件包都安装在 `/opt` 下, 以我们的 PHP 7 为例,在 `~/.bashrc` 里加入一行:
```
source /opt/rh/rh-php70/enable
```
以后相应的软件包就能在重启后自动启用了。有新软件保驾护航,你终于可以专注于自己的业务了。
### 列出可用软件包
那么,到底 Software Collections 里都是些什么呢? centos-release-scl 里有一些由社区维护的额外的软件包。除了在 [CentOS Wiki][5] 查看软件包列表外,你还可以使用 Yum 。我们先来看看安装了哪些仓库:
```
$ yum repolist
[...]
repo id repo name
base/7/x86_64 CentOS-7 - Base
centos-sclo-rh/x86_64 CentOS-7 - SCLo rh
centos-sclo-sclo/x86_64 CentOS-7 - SCLo sclo
extras/7/x86_64 CentOS-7 - Extras
updates/7/x86_64 CentOS-7 - Updates
```
Yum 没有专门用来打印某一个仓库中所有软件包的命令,所以你得这样来: LCTT 译注:实际上有,`yum repo-pkgs REPO list`,需要 root 权限dnf 同)
```
$ yum --disablerepo "*" --enablerepo centos-sclo-rh \
list available | less
```
`--disablerepo` 与 `--enablerepo` 选项的用法没有详细的文档,这里简单说下。 实际上在这个命令里你并没有禁用或启用什么东西,而只是将你的搜索范围限制在某一个仓库内。 此命令会打印出一个很长的列表,所以我们用管道传递给 `less` 输出。
### EPEL
强大的 Fedora 社区为 Feora 及所有 RHEL 系的发行版维护着 [EPELExtra Packages for Enterprise Linux][6] 。 里面包含一些最新软件包以及一些未被发行版收纳的软件包。安装 EPEL 里的软件就不用麻烦 `enable` 脚本了,直接像平常一样用。你还可以用 `--disablerepo` 和 `--enablerepo` 选项指定从 EPEL 里安装软件包:
```
$ sudo yum --disablerepo "*" --enablerepo epel install [package]
```
### Remi Collet
Remi Collet 在 [Remi 的 RPM 仓库][7] 里维护着大量更新的和额外的软件包。需要先安装 EPEL ,因为 Remi 仓库依赖它。
CentOS wiki 上有较完整的仓库列表:[更多的第三方仓库][8] ,用哪些,不用哪些,里面都有建议。
--------------------------------------------------------------------------------
via: https://www.linux.com/learn/intro-to-linux/2017/2/best-third-party-repositories-centos
作者:[CARLA SCHRODER][a]
译者:[Dotcra](https://github.com/Dotcra)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://www.linux.com/users/cschroder
[1]:https://www.linux.com/licenses/category/creative-commons-attribution
[2]:https://www.linux.com/files/images/centospng
[3]:https://www.softwarecollections.org/en/
[4]:https://access.redhat.com/solutions/472793
[5]:https://wiki.centos.org/SpecialInterestGroup/SCLo/CollectionsList
[6]:https://fedoraproject.org/wiki/EPEL
[7]:http://rpms.remirepo.net/
[8]:https://wiki.centos.org/AdditionalResources/Repositories

View File

@ -1,91 +0,0 @@
# rusking translating
What a Linux Desktop Does Better
============================================================
![linux-desktop-advantages](http://www.linuxinsider.com/article_images/story_graphics_xlarge/xl-2017-linux-1.jpg)
![](http://www.linuxinsider.com/images/2015/image-credit-adobe-stock_130x15.gif)
After I [resolved to adopt Linux][3], my confidence grew slowly but surely. Security-oriented considerations were compelling enough to convince me to switch, but I soon discovered many more advantages to the Linux desktop.
For those still unsure about making the transition, or those who have done so but may not know everything their system can do, I'll showcase here some of the Linux desktop's advantages.
### You Can't Beat Free!
First and foremost, Linux is literally free. Neither the operating system nor any of the programs you run will cost you a dime. Beyond the obvious financial benefit of getting software for free, Linux allows users to  _be_  free by affording access to the basic tools of modern computer use -- such as word processing and photo editing -- which otherwise might be unavailable due to the cost barrier.
Microsoft Office, which sets the de facto standard formats for documents of nearly every kind, demands a US$70 per year subscription. However, you can run [LibreOffice][4] for free while still handling documents in all the same formats with ease.
Free software also gives you the chance to try new programs, and with them new ways of pursuing business and leisure, without their prospective costs forcing you to make a commitment.
Instead of painstakingly weighing the merits of Mac or Windows and then taking a leap of faith, you can consider a vast spectrum of choices offered by[hundreds of distributions][5] -- basically, different flavors of Linux -- by trying each in turn until you find the one that's right for you.
Linux can even save money on hardware, as some manufacturers -- notably Dell -- offer a discount for buying a computer with Linux preinstalled. They can charge less because they don't have to pass on the cost of licensing Windows from Microsoft.
### You Can Make It Your Own
There is practically nothing in Linux that can't be customized. Among the projects central to the Linux ecosystem are desktop environments -- that is, collections of basic user programs and visual elements, like status bars and launchers, that make up the user interface.
Some Linux distributions come bundled with a desktop environment. Ubuntu is paired with the Unity desktop, for example. Others, such as with Debian, give you a choice at installation. In either case, users are free to change to any one they like.
Most distributions officially support (i.e., vouch for compatibility) dozens of the most popular desktops, which makes finding the one you like best that much simpler. Within the pantheon of desktops, you can find anything from glossy modern interfaces like KDE Plasma or [Gnome][6], to simple and lightweight ones like Xfce and MATE. Within each of these, you can personalize your setup further by changing the themes, system trays and menus, choosing from galleries of other users' screens for inspiration.
The customization possibilities go well beyond aesthetics. If you prize system stability, you can run a distribution like Mint, which offers dependable hardware support and ensures smooth updates.
On the other hand, if you want to live on the cutting edge, you can install an OS like Arch Linux, which gives you the latest update to each program as soon as developers release it.
If you'd rather take the middle path and stick with a stable foundation while running a few programs on the bleeding edge, you can download the source code -- that is, the code files written by the program's developers -- and compile them yourself. That requires running the source code through a utility to translate them into files of 1s and 0s (called "binaries") for your computer to execute.
The Linux system is yours to tweak in whatever ways work best for you.
### Lock It Down
This versatility lends itself well to a third major advantage to Linux: security.
To start with, while there are viruses for Linux, the number pales in comparison even to those for Mac. More importantly, the fact that the code for the core OS framework is open source -- and thus transparent to evaluation -- means there are fewer vulnerabilities in your basic system.
While proprietary (i.e., non-open source) OSes sometimes are criticized as maliciously compromising user security, they pose just as great a threat due to poorly implemented, opaque processes.
For instance, lots of Windows computers by default [do not check the cryptographic signatures][7] -- the mathematically guaranteed seals of authenticity -- on OS updates.
With Linux, you can implement as much fine-grained control over signature checking as you choose, and the major distributions enforce safe default settings. This kind of accountability arises directly from the transparency of Linux's open source development model.
Rolling release distributions like Arch add even more security, as critical patches are available almost as soon as they are approved. You would be hard-pressed to find a single mainstream OS that offers daily updates, but with Linux there are dozens.
### It's a Natural Development Platform
With a Linux desktop, developers -- or anyone interested in programming -- have the added benefit of Linux's great development tools. Among the best compiling tools around are the GNU C Compiler, or GCC, and GNU Autoconf, both key foundations of Linux.
Linux comfortably supports dozens of programming languages available in most default repositories, which are the pools of pre-compiled software available to a distribution.
Much of the Internet's infrastructure and many connected devices run on Linux -- from servers to smart devices such as security cameras and thermostats. Coding for these devices on Linux makes testing that much easier. If you have a computer-related project, Linux has everything you need to get the job done.
### Community Is at the Heart of Everything Linux
Finally, Linux has a tightly knit and friendly community. Because Linux is a relatively niche desktop OS, with around 3 percent market share, those who use it want prospective newcomers to stick around.
User forums, especially for beginner-friendly distributions like Ubuntu, include comprehensive guides to walk you through the basics and troubleshoot issues. Because power users tend to prefer Linux, wiki pages for distributions often contain thorough documentation -- often applicable across distributions -- to enable users to pursue even the most esoteric projects.
There are even casual Linux forums and [Reddit][8] threads for everything from comparing different software to showing off desktop themes. Taken together, this makes for a community with more camaraderie than I ever experienced as a Windows user.
Immersing myself in the world of Linux for just over two years has convinced me that it offers something for everyone. I hope this brief sampling of its advantages gives you a sense of what you might discover in a Linux desktop. But don't just take my word for it -- the real fun is finding out for yourself!
--------------------------------------------------------------------------------
via: http://www.linuxinsider.com/story/84326.html?rss=1
作者:[Jonathan Terrasi ][a]
译者:[译者ID](https://github.com/译者ID)
校对:[校对者ID](https://github.com/校对者ID)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:http://www.linkedin.com/company/ect-news-network
[1]:http://www.linuxinsider.com/story/84326.html?rss=1#
[2]:http://www.linuxinsider.com/perl/mailit/?id=84326
[3]:http://www.linuxinsider.com/story/84286.html
[4]:http://www.libreoffice.org/
[5]:https://en.wikipedia.org/wiki/Linux_distribution
[6]:http://en.wikipedia.org/wiki/GNOME
[7]:https://duo.com/blog/out-of-box-exploitation-a-security-analysis-of-oem-updaters
[8]:http://www.reddit.com/

View File

@ -1,324 +0,0 @@
<header class="post-header" style="text-rendering: optimizeLegibility; font-family: &quot;Noto Serif&quot;, Georgia, Cambria, &quot;Times New Roman&quot;, Times, serif; font-size: 20px; text-align: start; background-color: rgb(255, 255, 255);">[How to use slice capacity and length in Go][14]
============================================================</header>
<aside class="post-side" style="text-rendering: optimizeLegibility; position: fixed; top: 80px; left: 0px; width: 195px; padding-right: 5px; padding-left: 5px; text-align: right; z-index: 300; font-family: &quot;Noto Serif&quot;, Georgia, Cambria, &quot;Times New Roman&quot;, Times, serif; font-size: 20px;"></aside>
Quick pop quiz - what does the following code output?
```
vals := make([]int, 5)
for i := 0; i < 5; i++ {
vals = append(vals, i)
}
fmt.Println(vals)
```
_[Cheat and run it on the Go Playground][1]_
If you guessed `[0 0 0 0 0 0 1 2 3 4]` you are correct.
_Wait, what?_ Why isn't it `[0 1 2 3 4]`?
Don't worry if you got the pop quiz wrong. This is a fairly common mistake when transitioning into Go and in this post we are going to cover both why the output isn't what you expected along with how to utilize the nuances of Go to make your code more efficient.
### Slices vs Arrays
In Go there are both arrays and slices. This can be confusing at first, but once you get used to it you will love it. Trust me.
There are many differences between slices and arrays, but the primary one we want to focus on in this article is that the size of an array is part of its type, whereas slices can have a dynamic size because they are wrappers around arrays.
What does this mean in practice? Well, let's say we have the array `val a [10]int`. This array has a fixed size and that can't be changed. If we were to call `len(a)` it would always return 10, because that size is part of the type. As a result, if you suddenly need more than 10 items in your array you have to create a new object with an entirely different type, such as `val b [11]int`, and then copy all of your values from `a` over to `b`.
While having arrays with set sizes is valuable in specific cases, generally speaking this isn't what developers want. Instead, they want to work with something similar to an array in Go, but with the ability to grow over time. One crude way to do this would be to create an array that is much bigger than it needs to be and then to treat a subset of the array as your array. An example of this is shown in the code below.
```
var vals [20]int
for i := 0; i < 5; i++ {
vals[i] = i * i
}
subsetLen := 5
fmt.Println("The subset of our array has a length of:", subsetLen)
// Add a new item to our array
vals[subsetLen] = 123
subsetLen++
fmt.Println("The subset of our array has a length of:", subsetLen)
```
_[Run it on the Go Playground][2]_
With this code we have an array with a set size of 20, but because we are only using a subset our code can pretend that the length of the array is 5, and then 6 after we add a new item to our array.
This is (very roughly speaking) how slices work. They wrap an array with a set size, much like our array in the previous example has a set size of 20.
They also keep track of the subset of the array that is available for your program to use - this is the `length` attribute, and it is similar to the `subsetLen` variable in the previous example.
Finally, a slice also has a `capacity`, which is similar to the total length of our array (20) in the previous example. This is useful because it tells you how large your subset can grow before it will no longer fit in the array that is backing the slice. When this does happen, a new array will need to be allocated, but all of this logic is hidden behind the `append` function.
In short, combining slices with the `append` function gives us a type that is very similar to arrays, but is capable of growing over time to handle more elements.
Let's look at the previous example again, but this time we will use a slice instead of an array.
```
var vals []int
for i := 0; i < 5; i++ {
vals = append(vals, i)
fmt.Println("The length of our slice is:", len(vals))
fmt.Println("The capacity of our slice is:", cap(vals))
}
// Add a new item to our array
vals = append(vals, 123)
fmt.Println("The length of our slice is:", len(vals))
fmt.Println("The capacity of our slice is:", cap(vals))
// Accessing items is the same as an array
fmt.Println(vals[5])
fmt.Println(vals[2])
```
_[Run it on the Go Playground][3]_
We can still access elements in our slice just like we would arrays, but by using a slice and the `append` function we no longer have to think about the size of the backing array. We are still able to figure these things out by using the `len` and `cap` functions, but we don't have to worry too much about them. Neat, right?
### Back to the pop quiz
With that in mind, let's look back at our pop quiz code to see what went wrong.
```
vals := make([]int, 5)
for i := 0; i < 5; i++ {
vals = append(vals, i)
}
fmt.Println(vals)
```
When calling `make` we are permitted to pass in up to 3 arguments. The first is the type that we are allocating, the second is the `length` of the type, and the third is the `capacity` of the type (_this parameter is optional_).
By passing in the arguments `make([]int, 5)` we are telling our program that we want to create a slice with a length of 5, and the capacity is defaulted to the length provided - 5 in this instance.
While this might seem like what we wanted at first, the important distinction here is that we told our slice that we wanted to set both the `length` and `capacity` to 5, and then we proceeded to call the `append` function which assumes you want to add a new element _after_ the initial 5, so it will increase the capacity and start adding new elements at the end of the slice.
You can actually see the capacity changing if you add a `Println()` statement to your code.
```
vals := make([]int, 5)
fmt.Println("Capacity was:", cap(vals))
for i := 0; i < 5; i++ {
vals = append(vals, i)
fmt.Println("Capacity is now:", cap(vals))
}
fmt.Println(vals)
```
_[Run it on the Go Playground][4]_
As a result, we end up getting the output `[0 0 0 0 0 0 1 2 3 4]` instead of the desired `[0 1 2 3 4]`.
How do we fix it? Well, there are several ways to do this, so we are going to cover two of them and you can pick whichever makes the most sense in your situation.
### Write directly to indexes instead of using `append`
The first fix is to leave the `make` call unchanged and explicitly state the index that you want to set each element to. Doing this, we would get the following code:
```
vals := make([]int, 5)
for i := 0; i < 5; i++ {
vals[i] = i
}
fmt.Println(vals)
```
_[Run it on the Go Playground][5]_
In this case the value we are setting happens to be the same as the index we want to use, but you can also keep track of the index independently.
For example, if you wanted to get the keys of a map you could use the following code.
```
package main
import "fmt"
func main() {
fmt.Println(keys(map[string]struct{}{
"dog": struct{}{},
"cat": struct{}{},
}))
}
func keys(m map[string]struct{}) []string {
ret := make([]string, len(m))
i := 0
for key := range m {
ret[i] = key
i++
}
return ret
}
```
_[Run it on the Go Playground][6]_
This works well because we know that the exact length of the slice we return will be the same as the length of the map, so we can initialize our slice with that length and then assign each element to an appropriate index. The downside to this approach is that we have to keep track of `i` so that we know what index to place every value in.
This leads us to the second approach we are going to cover...
### Use `0` as your length and specify your capacity instead
Rather than keeping track of which index we want to add our values to, we can instead update our `make` call and provide it with two arguments after the slice type. The first, the length of our new slice, will be set to `0`, as we haven't added any new elements to our slice. The second, the capacity of our new slice, will be set to the length of the map parameter because we know that our slice will eventually have that many strings added to it.
This will still construct the same array behind the scenes as the previous example, but now when we call `append` it will know to place items at the start of our slice because the length of the slice is 0.
```
package main
import "fmt"
func main() {
fmt.Println(keys(map[string]struct{}{
"dog": struct{}{},
"cat": struct{}{},
}))
}
func keys(m map[string]struct{}) []string {
ret := make([]string, 0, len(m))
for key := range m {
ret = append(ret, key)
}
return ret
}
```
_[Run it on the Go Playground][7]_
### Why do we bother with capacity at all if `append` handles it?
The next thing you might be asking is, "Why are we even telling our program a capacity if the `append` function can handle increasing the capacity of my slice for me?"
The truth is, in most cases you don't need to worry about this too much. If it makes your code significantly more complicated, just initialize your slice with `var vals []int` and let the `append`function handle the heavy lifting for you.
But this case is different. It isn't an instance where declaring the capacity is difficult; In fact, it is actually quite easy to determine what the final capacity of our slice needs to be because we know it will map directly to the provided map. As a result, we can declare the capacity of our slice when we initialize it and save our program from needing to perform unnecessary memory allocations.
If you want to see what the extra memory allocations look like, run the following code on the Go Playground. Every time capacity increases our program needed to do another memory allocation.
```
package main
import "fmt"
func main() {
fmt.Println(keys(map[string]struct{}{
"dog": struct{}{},
"cat": struct{}{},
"mouse": struct{}{},
"wolf": struct{}{},
"alligator": struct{}{},
}))
}
func keys(m map[string]struct{}) []string {
var ret []string
fmt.Println(cap(ret))
for key := range m {
ret = append(ret, key)
fmt.Println(cap(ret))
}
return ret
}
```
_[Run it on the Go Playground][8]_
Now compare this to the same code but with a predefined capacity.
```
package main
import "fmt"
func main() {
fmt.Println(keys(map[string]struct{}{
"dog": struct{}{},
"cat": struct{}{},
"mouse": struct{}{},
"wolf": struct{}{},
"alligator": struct{}{},
}))
}
func keys(m map[string]struct{}) []string {
ret := make([]string, 0, len(m))
fmt.Println(cap(ret))
for key := range m {
ret = append(ret, key)
fmt.Println(cap(ret))
}
return ret
}
```
_[Run it on the Go Playground][9]_
In the first code sample our capacity starts at `0`, and then increases to `1`, `2`, `4`, and then finally `8`, meaning we had to allocate a new array 5 different times, and on top of that the final array used to back our slice has a capacity of `8`, which is bigger than we ultimately needed.
On the other hand, our second sample starts and ends with the same capacity (`5`) and only needs to allocate it once at the start of the `keys()` function. We also avoid wasting any extra memory and return a slice with the perfect size array backing it.
### Don't over-optimize
As I said before, I typically wouldn't encourage anyone to worry about minor optimizations like this, but in cases where it is really obvious what the final size should be I strongly encourage you to try to set an appropriate capacity or length for your slices.
Not only does it help improve the performance of your application, but it can also help clarify your code a bit by explicitly stating the relationship between the size of your input and the size of your output.
### In summary...
> Hi there! I write a lot about Go, web development, and other topics I find interesting.
>
> If you want to stay up to date with my writing, please [sign up for my mailing list][10]. I'll send you a FREE sample of my upcoming book, Web Development with Go, and an occasional email when I publish a new article (usually 1-2 per week).
>
> Oh, and I promise I don't spam. I hate it as much as you do :)
This article is not meant to be an exhaustive discussion on the differences between slices or arrays, but instead is meant to serve as a brief introduction into how capacity and length affect your slices, and what purpose they serve in the grand scheme of things.
For further reading, I highly recommend the following articles from the Go Blog:
* [Go Slices: usage and internals][11]
* [Arrays, slices (and strings): The mechanics of 'append'][12]
* [Slice Tricks][13]
--------------------------------------------------------------------------------
作者简介:
Jon is a software consultant and the author of the book Web Development with Go. Prior to that he founded EasyPost, a Y Combinator backed startup, and worked at Google.
https://www.usegolang.com
--------------------------------------------------------------------------------
via: https://www.calhoun.io/how-to-use-slice-capacity-and-length-in-go
作者:[Jon Calhoun][a]
译者:[译者ID](https://github.com/译者ID)
校对:[校对者ID](https://github.com/校对者ID)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://www.calhoun.io/hire-me
[1]:https://play.golang.org/p/7PgUqBdZ6Z
[2]:https://play.golang.org/p/Np6-NEohm2
[3]:https://play.golang.org/p/M_qaNGVbC-
[4]:https://play.golang.org/p/d6OUulTYM7
[5]:https://play.golang.org/p/JI8Fx3fJCU
[6]:https://play.golang.org/p/kIKxkdX35B
[7]:https://play.golang.org/p/h5hVAHmqJm
[8]:https://play.golang.org/p/fDbAxtAjLF
[9]:https://play.golang.org/p/nwT8X9-7eQ
[10]:https://www.calhoun.io/how-to-use-slice-capacity-and-length-in-go/?utm_source=golangweekly&utm_medium=email#mailing-list-form
[11]:https://blog.golang.org/go-slices-usage-and-internals
[12]:https://blog.golang.org/slices
[13]:https://github.com/golang/go/wiki/SliceTricks
[14]:https://www.calhoun.io/how-to-use-slice-capacity-and-length-in-go/

View File

@ -1,120 +0,0 @@
ucasFL translating
How to make file-specific setting changes in Vim using Modeline
============================================================
### On this page
1. [VIM Modeline][2]
1. [Usage][1]
2. [Conclusion][3]
While [plugins][4] are no doubt one of Vim's biggest strengths, there are several other functionalities that make it one of the most powerful and feature-rich text editors/IDEs available to Linux users today. One of these functionalities is the ability to make file-specific setting changes. This ability can be accessed using the editor's Modeline feature.
In this article, we will discuss how you can use Vim's [Modeline][5] feature using easy to understand examples.
But before we start doing that, it's worth mentioning that all the examples, commands, and instructions mentioned in this tutorial have been tested on Ubuntu 16.04, and the Vim version we've used is 7.4.
### VIM Modeline
### Usage
As we've already mentioned, Vim's Modeline feature lets you make file-specific changes. For example, suppose you want to replace all the tabs used in a particular file of your project with spaces, and make sure that all other files aren't affected by this change. This is an ideal use-case where Modeline helps you in what you want to do.
So, what you can do is, you can put the following line in the beginning or end of the file in question:
```
# vim: set expandtab:
```
There are high chances that if you try doing the aforementioned exercise to test the use-case on your Linux machine, things won't work as expected. If that's the case, worry not, as the Modeline feature needs to be activated first in some cases (it's disabled by default on systems such as Debian, Ubuntu, Gentoo, and OSX for security reasons).
To enable the feature, open the .vimrc file (located in your home directory), and then add the following line to it:
```
set modeline
```
Now, whenever you enter a tab and save the file (where the expandtab modeline command was entered), the tab will automatically convert into white spaces.
Let's consider another use-case. Suppose the default tab space in Vim is set to 4, but for a particular file, you want to increase it to 8. For this, you need to add the following line in the beginning or the end of the file:
```
// vim: noai:ts=8:
```
Now try entering a tab and you'll see that the number of spaces it covers will be 8. 
You might have noticed me saying that these modeline commands need to be entered somewhere near the top or the bottom of the file. If you're wondering why this is so, the reason is that the feature is designed this way. The following lines (taken from the official Vim documentation) should make this more clear:
"The modeline cannot be anywhere in the file: it must be in the first or last few lines. The exact location where vim checks for the modeline is controlled by the `modelines` variable; see :help modelines. By default, it is set to 5 lines."
And here's what the :help modelines command (referred to in the above lines) says:
If 'modeline' is on 'modelines' gives the number of lines that is checked for set commands. If 'modeline' is off or 'modelines' is zero no lines are checked.
Try and put the modeline command beyond the default 5 lines (either from the bottom or from the top) range, and you'll notice that tab spaces will revert to the Vim default - in my case that's 4 spaces.
However, you can change this behavior if you want, using the following command in your .vimrc file. 
```
set modelines=[new-value]
```
For example, I increased the value from 5 to 10.
```
set modelines=10
```
This means that now I can put the modeline command anywhere between first or last 10 lines of the file.
Moving on, at any point in time, while editing a file, you can enter the following (with the Vim editor in the command mode) to see the current modeline-related settings as well as where they were last set.
```
:verbose set modeline? modelines?
```
For example, in my case, the above command produced the following output:
```
modeline
Last set from ~/.vimrc
modelines=10
Last set from ~/.vimrc
```
Here are some of the important points you need to know about Vim's Modeline feature:
* This feature is enabled by default for Vim running in nocompatible (non Vi-compatible) mode, but some notable distributions of Vim disable this option in the system vimrc for security.
* The feature is disabled by default when editing as root (if you've opened the file using 'sudo' then there's no issue - the feature works).
* With '`set'`, the modeline ends at the first colon not following a backslash. And without '`set'`, no text can follow the options. For example, **/* vim: noai:ts=4:sw=4 */** is an invalid modeline.
### Security Concerns
Sadly, Vim's Modeline feature can be used to compromise security. In fact, multiple security-related Modeline issues have been reported in the past, including [shell command injection][6], [arbitrary commands execution][7], [unauthorized access][8], and more. Agreed, most of these are old, and would have been fixed by now, but it does give an idea that the Modeline feature could be misused by hackers.
### Conclusion
Modeline may be an advanced feature of the Vim editor, but it's not very difficult to understand. There's no doubt that a bit of learning curve involved, but that's not much to ask for given how useful the feature is. Of course, there are security concerns, which means that you should weigh your options before enabling and using the feature.
Have you ever used the Modeline feature? How was your experience? Share with us (and the whole HowtoForge community) in the comments below.
--------------------------------------------------------------------------------
via: https://www.howtoforge.com/tutorial/vim-modeline-settings/
作者:[ Ansh][a]
译者:[译者ID](https://github.com/译者ID)
校对:[校对者ID](https://github.com/校对者ID)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://www.howtoforge.com/tutorial/vim-modeline-settings/
[1]:https://www.howtoforge.com/tutorial/vim-modeline-settings/#usage
[2]:https://www.howtoforge.com/tutorial/vim-modeline-settings/#vim-modeline
[3]:https://www.howtoforge.com/tutorial/vim-modeline-settings/#conclusion
[4]:https://www.howtoforge.com/tutorial/vim-editor-plugins-for-software-developers-3/
[5]:http://vim.wikia.com/wiki/Modeline_magic
[6]:https://tools.cisco.com/security/center/viewAlert.x?alertId=13223
[7]:http://usevim.com/2012/03/28/modelines/
[8]:https://tools.cisco.com/security/center/viewAlert.x?alertId=5169

View File

@ -1,109 +0,0 @@
Dotcra translating
Best Third-Party Repositories for CentOS
============================================================
![CentOS](https://www.linux.com/sites/lcom/files/styles/rendered_file/public/centos.png?itok=YRMQVk7U "CentOS")
>Get reliable up-to-date packages for CentOS from the Software Collections repository, EPEL, and Remi.[Creative Commons Attribution][1]
Red Hat Enterprise Linux, in the grand tradition of enterprise software vendors, packages and supports old mold long after it should be dead and buried. They don't do this out of laziness, but because that is what their customers want. A lot of businesses view software the same way they see furniture: you buy a desk once and keep it forever, and software is just like a desk.
CentOS, as a RHEL clone, suffers from this as well. Red Hat supports deprecated software that is no longer supported by upstream -- presumably patching security holes and keeping it working. But that is not good enough when you are running a software stack that requires newer versions. I have bumped into this numerous times running web servers on RHEL and CentOS. LAMP stacks are not forgiving, and every piece of the stack must be compatible with all of the others. For example, last year I had ongoing drama with RHEL/CentOS because version 6 shipped with PHP 5.3, and version 7 had PHP 5.4\. PHP 5.3 was end-of-life in August, 2014 and unsupported by upstream. PHP 5.4 went EOL in Sept. 2015, and 5.5 in July 2016\. MySQL, Python, and many other ancient packages that should be on display in museums as mummies also ship in these releases.
So, what's a despairing admin to do? If you run both RHEL and CentOS turn first to the [Software Collections][3], as this is only Red Hat-supported source of updated packages. There is a Software Collections repository for CentOS, and installing and managing it is similar to any third-party repository, with a couple of unique twists. (If you're running RHEL, the procedure is different, as it is for all software management; you must do it [the RHEL way][4].) Software Collections also supports Fedora and Scientific Linux.
### Installing Software Collections
Install Software Collections on CentOS 6 and 7 with this command:
```
$ sudo yum install centos-release-scl
```
Then use Yum to search for and install packages in the usual way:
```
$ yum search php7
[...]
rh-php70.x86_64 : Package that installs PHP 7.0
[...]
$ sudo yum install rh-php70
```
This may also pull in `centos-release-scl-rh` as a dependency.
There is one more step, and that is enabling your new packages:
```
$ scl enable rh-php70 bash
$ php -v
PHP 7.0.10
```
This runs a script that loads the new package and changes your environment, and you should see a change in your prompt. You must also install the appropriate connectors for the new package if necessary, for example for Python, PHP, and MySQL, and update configuration files (e.g., Apache) to use the new version.
The SCL package will not be active after reboot. SCL is designed to run your old and new versions side-by-side and not overwrite your existing configurations. You can start your new packages automatically by sourcing their `enable` scripts in `.bashrc`. SCL installs everything into `opt`, so add this line to `.bashrc` for our PHP 7 example:
```
source /opt/rh/rh-php70/enable
```
It will automatically load and be available at startup, and you can go about your business cloaked in the warm glow of fresh up-to-date software.
### Listing Available Packages
So, what exactly do you get in Software Collections on CentOS? There are some extra community-maintained packages in `centos-release-scl`. You can see package lists in the [CentOS Wiki][5], or use Yum. First, let's see all our installed repos:
```
$ yum repolist
[...]
repo id repo name
base/7/x86_64 CentOS-7 - Base
centos-sclo-rh/x86_64 CentOS-7 - SCLo rh
centos-sclo-sclo/x86_64 CentOS-7 - SCLo sclo
extras/7/x86_64 CentOS-7 - Extras
updates/7/x86_64 CentOS-7 - Updates
```
Yum does not have a simple command to list packages in a single repo, so you have to do this:
```
$ yum --disablerepo "*" --enablerepo centos-sclo-rh \
list available | less
```
This use of the `--disablerepo` and `--enablerepo` options is not well documented. You're not really disabling or enabling anything, but only limiting your search query to a single repo. It spits out a giant list of packages, and that is why we pipe it through `less`.
### EPEL
The excellent Fedora peoples maintain the [EPEL, Extra Packages for Enterprise Linux][6] repository for Fedora and all RHEL-compatible distributions. This contains updated package versions and software that is not included in the stock distributions. Install software from EPEL in the usual way, without having to bother with enable scripts. Specify that you want packages from EPEL using the `--disablerepo` and `--enablerepo` options:
```
$ sudo yum --disablerepo "*" --enablerepo epel install [package]
```
### Remi Collet
Remi Collet maintains a large collection of updated and extra packages at [Remi's RPM repository][7]. Install EPEL first as Remi's repo depends on it.
The CentOS wiki has a list of [additional third-party repositories][8] to use, and some to avoid.
--------------------------------------------------------------------------------
via: https://www.linux.com/learn/intro-to-linux/2017/2/best-third-party-repositories-centos
作者:[CARLA SCHRODER][a]
译者:[译者ID](https://github.com/译者ID)
校对:[校对者ID](https://github.com/校对者ID)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://www.linux.com/users/cschroder
[1]:https://www.linux.com/licenses/category/creative-commons-attribution
[2]:https://www.linux.com/files/images/centospng
[3]:https://www.softwarecollections.org/en/
[4]:https://access.redhat.com/solutions/472793
[5]:https://wiki.centos.org/SpecialInterestGroup/SCLo/CollectionsList
[6]:https://fedoraproject.org/wiki/EPEL
[7]:http://rpms.remirepo.net/
[8]:https://wiki.centos.org/AdditionalResources/Repositories

View File

@ -1,3 +1,4 @@
ucasFL translating
WRITE MARKDOWN WITH 8 EXCEPTIONAL OPEN SOURCE EDITORS
============================================================

View File

@ -1,412 +0,0 @@
being translated by zhousiyu325
How to control GPIO pins and operate relays with the Raspberry Pi
============================================================
> Learn how to operate relays and control GPIO pins with the Pi using PHP and a temperature sensor.
![How to control GPIO pins and operate relays with the Raspberry Pi](https://opensource.com/sites/default/files/styles/image-full-size/public/images/life/raspberry_pi_day_lead_0.jpeg?itok=lCxmviRD "How to control GPIO pins and operate relays with the Raspberry Pi")
>Image by : opensource.com
Ever wondered how to control items like your fans, lights, and more using your phone or computer from anywhere?
I was looking to control my Christmas lights using any mobile phone, tablet, laptop... simply by using a Raspberry Pi. Let me show you how to operate relays and control GPIO pins with the Pi using PHP and a temperature sensor. I put them all together using AJAX.
### Hardware requirements
* Raspberry Pi
* SD Card with Raspbian installed (any SD card would work, but I prefer to use a 32GB class 10 card)
* Power adapter
* Jumper wires (female to female and male to female)
* Relay board (I use a 12V relay board with for relays)
* DS18B20 temperature probe
* Wi-Fi adapter for Raspberry Pi
* Router (for Internet access, you need to have a port-forwarding supported router)
* 10K-ohm resistor
### Software requirements
* Download and install Raspbian on your SD Card
* Working Internet connection
* Apache web server
* PHP
* WiringPi
* SSH client on a Mac or Windows client
### General configurations and setup
1\. Insert the SD card into Raspberry Pi and connect it to the router using an Ethernet cable
2\. Connect the Wi-Fi Adapter.
3\. Now SSH to Pi and edit the **interfaces** file using:
**sudo nano /etc/network/interfaces**
This will open the file in an editor called **nano**. It is a very simple text editor that is easy to approach and use. If you're not familiar to a Linux-based operating systems, just use the arrow keys.
After opening the file in **nano** you will see a screen like this:
![File editor nano](https://opensource.com/sites/default/files/putty_0.png "File editor nano")
4\. To configure your wireless network, modify the file as follows:
**iface lo inet loopback**
**iface eth0 inet dhcp**
**allow-hotplug wlan0**
**auto wlan0**
**iface wlan0 inet dhcp**
**   wpa-ssid "Your Network SSID"**
**   wpa-psk "Your Password"**
5\. Press CTRL + O to save it, and then CTRL + X to exit the editor.
At this point, everything is configured and all you need to do is reload the network interfaces by running:
**sudo service networking reload**
(Warning: if you are connected using a remote connection it will disconnect now.)
### Software configurations
### Installing Apache Web Server
Apache is a popular web server application you can install on the Raspberry Pi to allow it to serve web pages. On its own, Apache can serve HTML files over HTTP, and with additional modules it can serve dynamic web pages using scripting languages such as PHP.
Install Apache by typing the following command on the command line:
**sudo apt-get install apache2 -y**
Once the installation is complete, type in the IP Address of your Pi to test the server. If you get the next image, then you have installed and set up your server successfully.
![Successful server setup](https://opensource.com/sites/default/files/itworks.png "Successful server setup")
To change this default page and add your own html file, go to **var/www/html**:
**cd /var/www/html**
To test this, add any file to this folder.
### Installing PHP
PHP is a preprocessor, meaning this is code that runs when the server receives a request for a web page. It runs, works out what needs to be shown on the page, then sends that page to the browser. Unlike static HTML, PHP can show different content under different circumstances. Other languages are capable of this, but since WordPress is written in PHP it's what you need to use this time. PHP is a very popular language on the web, with large projects like Facebook and Wikipedia written in it.
Install the PHP and Apache packages with the following command:
**sudo apt-get install php5 libapache2-mod-php5 -y**
### Testing PHP
Create the file **index.php**:
**sudo nano index.php**
Put some PHP content in it:
**<?php echo "hello world"; ?>**
Save the file. Next, delete "index.html" because it takes precedence over "index.php":
**sudo rm index.html**
Refresh your browser. You should see “hello world.” This is not dynamic, but it is still served by PHP. If you see the raw PHP above instead of “hello world,” reload and restart Apache with:
**sudo /etc/init.d/apache2 reload**
**sudo /etc/init.d/apache2 restart**
### Installing WiringPi
WiringPi is maintained under **git** for ease of change tracking; however, you have a plan B if youre unable to use **git** for whatever reason. (Usually your firewall will be blocking you, so do check that first!)
If you do not have **git** installed, then under any of the Debian releases (e.g., Raspbian), you can install it with:
**sudo apt-get install git-core**
If you get any errors here, make sure your Pi is up to date with the latest version of Raspbian:
**sudo apt-get update sudo apt-get upgrade**
To obtain WiringPi using **git**:
**sudo git clone git://git.drogon.net/wiringPi**
If you have already used the clone operation for the first time, then:
**cd wiringPi git pull origin**
It will fetch an updated version, and then you can re-run the build script below.
To build/install there is a new simplified script:
**cd wiringPi ./build**
The new build script will compile and install it all for you. It does use the **sudo** command at one point, so you may wish to inspect the script before running it.
### Testing WiringPi
Run the **gpio** command to check the installation:
**gpio -v gpio readall**
This should give you some confidence that its working OK.
### Connecting DS18B20 To Raspberry Pi
* The Black wire on your probe is for GND
* The Red wire is for VCC
* The Yellow wire is the GPIO wire
![GPIO image](https://opensource.com/sites/default/files/gpio_0.png "GPIO image")
Connect:
* VCC to 3V Pin 1
* GPIO wire to Pin 7 (GPIO 04)
* Ground wire to any GND Pin 9
### Software Configuration
For using DS18B20 temperature sensor module with PHP, you need to activate the kernel module for the GPIO pins on the Raspberry Pi and the DS18B20 by executing the commands:
**sudo modprobe w1-gpio**
**sudo modprobe w1-therm**
You do not want to do that manually every time the Raspberry reboots, so you want to enable these modules on every boot. This is done by adding the following lines to the file **/etc/modules**:
**sudo nano /etc/modules/**
Add the following lines to it:
**w1-gpio**
**w1-therm**
To test this, type in:
**cd /sys/bus/w1/devices/**
Now type **ls. **
You should see your device information. In the device drivers, your DS18B20 sensor should be listed as a series of numbers and letters. In this case, the device is registered as 28-000005e2fdc3\. You then need to access the sensor with the cd command, replacing my serial number with your own: **cd 28-000005e2fdc3. **
The DS18B20 sensor periodically writes to the **w1_slave** file, so you simply use the cat command to read it**: cat w1_slave.**
This yields the following two lines of text, with the output **t=** showing the temperature in degrees Celsius. Place a decimal point after the first two digits (e.g., the temperature reading I received is 30.125 degrees Celsius).
### Connecting the relay
1\. Take two jumper wires and connect one of them to the GPIO 24 (Pin18) on the Pi and the other one to the GND Pin. You may refer the following diagram.
2\. Now connect the other ends of the wire to the relay board. Connect the GND to the GND on the relay and GPIO Output wire to the relay channel pin number, which depends on the relay that you are using. Remember theGNDgoes to GND on the relay and GPIO Output goes to the relay input pin.
![Headers](https://opensource.com/sites/default/files/headers.png "Headers")
Caution! Be very careful with the relay connections with Pi because if it causes a backflow of current, you with have a short circuit.
3\. Now connect the power supply to the relay, either using 12V power adapter or by connecting the VCC Pin to 3.3V or 5V on the Pi.
### Controlling the relay using PHP
Let's create a PHP script to control the GPIO pins on the Raspberry Pi, with the help of the WiringPi software.
1\. Create a file in the Apache servers root web directory. Navigate using:
**cd ../../../**
**cd var/www/html/**
2\. Create a new folder called Home:
**sudo mkdir Home**
3\. Create a new PHP file called **on.php**:
**sudo nano on.php**
4\. Add the following code to it:
```
<?php
          system(“ gpio-g mode 24 out “) ;
          system(“ gpio-g write 24 1”) ;
?>
```
5\. Save the file using CTRL + O and exit using CTRL + X
In the code above, in the first line you've set the GPIO Pin 24 to output mode using the command:
```
system(“ gpio-g mode 24 out “) ;
```
In the second line, youve turned on the GPIO Pin 24, Using “1,” where “1” in binary refers to ON and “0” Means OFF.
6\. To turn off the relay, create another file called **off.php** and replace “1” with “0.”
```
<?php
system(“ gpio-g mode 24 out “) ;
system(“ gpio-g write 24 0”) ;
?>
```
7\. If you have your relay connected to the Pi, visit your web browser and type in the IP Address of your Pi followed by the directory name and file name:       
**http://{IPADDRESS}/home/on.php**
This will turn ON the relay.
8\. To turn it OFF, open the page called **off.php**,
**http://{IPADDRESS}/home/off.php**
Now you need to control both these things from a single page without refreshing or visiting the pages individually. For that you'll use AJAX.
9\. Create a new HTML file and add this code to it.
```
[html + php + ajax codeblock]
<html>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script type="text/javascript">// <![CDATA[
$(document).ready(function() {
$('#on').click(function(){
var a= new XMLHttpRequest();
a.open("GET", "on.php"); a.onreadystatechange=function(){
if(a.readyState==4){ if(a.status ==200){
 } else alert ("http error"); } }
a.send();
});
});
$(document).ready(function()
{ $('#Off').click(function(){
var a= new XMLHttpRequest();
a.open("GET", "off.php");
a.onreadystatechange=function(){
if(a.readyState==4){
if(a.status ==200){
 } else alert ("http error"); } }
a.send();
});
});
</script>
<button id="on" type="button"> Switch Lights On </button>
<button id="off" type="button"> Switch Lights Off </button>
```
10\. Save the file, go to your web browser, and open that page. Youll see two buttons, which will turn lights on and off. Based on the same idea, you can create a beautiful web interface using bootstrap and CSS skills.
### Viewing temperature on this web page
1\. Create a file called **temperature.php**:
```
sudo nano temperature.php
```
2\. Add the following code to it, replace 10-000802292522 with your device ID:
```
<?php
//File to read
$file = '/sys/devices/w1_bus_master1/10-000802292522/w1_slave';
//Read the file line by line
$lines = file($file);
//Get the temp from second line
$temp = explode('=', $lines[1]);
//Setup some nice formatting (i.e., 21,3)
$temp = number_format($temp[1] / 1000, 1, ',', '');
//And echo that temp
echo $temp . " °C";
?>
```
3\. Go to the HTML file that you just created, and create a new **<div>** with the **id** “screen”: **<div id=“screen”></div>.**
4\. Add the following code after the **<body>** tag or at the end of the document:
```
<script>
$(document).ready(function(){
setInterval(function(){
$("#screen").load('temperature.php')
}, 1000);
});
</script>
```
In this, **#screen** is the **id** of **<div>** in which you want to display the temperature. It loads the **temperature.php** file every 1000 milliseconds.
I have used bootstrap to make a beautiful panel for displaying temperature. You can add multiple icons and glyphicons as well to make it more attractive.
This was just a basic system that controls a relay board and displays the temperature. You can develop it even further by creating event-based triggers based on timings, temperature readings from the thermostat, etc.
--------------------------------------------------------------------------------
作者简介:
Abdul Hannan Mustajab - I'm 17 years old and live in India. I am pursuing an education in science, math, and computer science. I blog about my projects at spunkytechnology.com. I've been working on AI based IoT using different micro controllers and boards .
--------
via: https://opensource.com/article/17/3/operate-relays-control-gpio-pins-raspberry-pi
作者:[ Abdul Hannan Mustajab][a]
译者:[译者ID](https://github.com/译者ID)
校对:[校对者ID](https://github.com/校对者ID)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://opensource.com/users/mustajabhannan
[1]:http://www.php.net/system
[2]:http://www.php.net/system
[3]:http://www.php.net/system
[4]:http://www.php.net/system
[5]:http://www.php.net/system
[6]:http://www.php.net/file
[7]:http://www.php.net/explode
[8]:http://www.php.net/number_format
[9]:https://opensource.com/article/17/3/operate-relays-control-gpio-pins-raspberry-pi?rate=RX8QqLzmUb_wEeLw0Ee0UYdp1ehVokKZ-JbbJK_Cn5M
[10]:https://opensource.com/user/123336/feed
[11]:https://opensource.com/users/mustajabhannan

View File

@ -1,106 +0,0 @@
hkurj translating
How to Find Difference Between Two Directories Using Diff and Meld Tools
============================================================
In an earlier article, we reviewed [9 best file comparison and difference (Diff) tools for Linux][1] and in this article, we will describe how to find the difference between two directories in Linux.
Normally, to [compare two files in Linux][2], we use the diff  a simple and original Unix command-line tool that shows you the difference between two computer files; compares files line by line and it is easy to use, comes with pre-installed on most if not all Linux distributions.
The question is how do we get the difference between two directories in Linux? Here, we want to know what files/subdirectories are common in the two directories, those that are present in one directory but not in the other.
The conventional syntax for running diff is as follows:
```
$ diff [OPTION]… FILES
$ diff options dir1 dir2
```
By default, its output is ordered alphabetically by file/subdirectory name as shown in the screenshot below. In this command, the `-q` switch tells diff to report only when files differ.
```
$ diff -q directory-1/ directory-2/
```
[
![Difference Between Two Directories](http://www.tecmint.com/wp-content/uploads/2017/05/Difference-Between-Two-Directories.png)
][3]
Difference Between Two Directories
Again diff doesnt go into the subdirectories, but we can use the `-r` switch to read the subdirectories as well like this.
```
$ diff -qr directory-1/ directory-2/
```
### Using Meld Visual Diff and Merge Tool
There is a cool graphical option called meld (a visual diff and merge tool for the GNOME Desktop) for those who enjoy using the mouse, you can install it as follows.
```
$ sudo apt install meld [Debian/Ubuntu systems]
$ sudo yum install meld [RHEL/CentOS systems]
$ sudo dnf install meld [Fedora 22+]
```
Once you have installed it, search for “meld” in the Ubuntu Dash or Linux Mint Menu, in Activities Overview in Fedora or CentOS desktop and launch it.
You will see the Meld interface below, where you can choose file or directory comparison as well as version control view. Click on directory comparison and move to the next interface.
[
![Meld Comparison Tool](http://www.tecmint.com/wp-content/uploads/2017/05/Meld-Comparison-Tool.png)
][4]
Meld Comparison Tool
Select the directories you want to compare, note that you can add a third directory by checking the option “3-way Comparison”.
[
![Select Comparison Directories](http://www.tecmint.com/wp-content/uploads/2017/05/Select-Comparison-Directories.png)
][5]
Select Comparison Directories
Once you selected the directories, click on “Compare”.
[
![Listing Difference Between Directories](http://www.tecmint.com/wp-content/uploads/2017/05/Listing-Difference-Between-Directories.png)
][6]
Listing Difference Between Directories
In this article, we described how to find the difference between two directories in Linux. If you know any other commandline or gui way dont forget to share your thoughts to this article via the comment section below.
--------------------------------------------------------------------------------
作者简介:
Aaron Kili is a Linux and F.O.S.S enthusiast, an upcoming Linux SysAdmin, web developer, and currently a content creator for TecMint who loves working with computers and strongly believes in sharing knowledge.
-------------------
via: http://www.tecmint.com/compare-find-difference-between-two-directories-in-linux/
作者:[Aaron Kili ][a]
译者:[译者ID](https://github.com/译者ID)
校对:[校对者ID](https://github.com/校对者ID)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:http://www.tecmint.com/author/aaronkili/
[1]:http://www.tecmint.com/best-linux-file-diff-tools-comparison/
[2]:http://www.tecmint.com/freefilesync-compare-synchronize-files-in-ubuntu/
[3]:http://www.tecmint.com/wp-content/uploads/2017/05/Difference-Between-Two-Directories.png
[4]:http://www.tecmint.com/wp-content/uploads/2017/05/Meld-Comparison-Tool.png
[5]:http://www.tecmint.com/wp-content/uploads/2017/05/Select-Comparison-Directories.png
[6]:http://www.tecmint.com/wp-content/uploads/2017/05/Listing-Difference-Between-Directories.png
[7]:http://www.tecmint.com/compare-find-difference-between-two-directories-in-linux/#
[8]:http://www.tecmint.com/compare-find-difference-between-two-directories-in-linux/#
[9]:http://www.tecmint.com/compare-find-difference-between-two-directories-in-linux/#
[10]:http://www.tecmint.com/compare-find-difference-between-two-directories-in-linux/#
[11]:http://www.tecmint.com/compare-find-difference-between-two-directories-in-linux/#comments
[12]:http://www.tecmint.com/author/aaronkili/
[13]:http://www.tecmint.com/10-useful-free-linux-ebooks-for-newbies-and-administrators/
[14]:http://www.tecmint.com/free-linux-shell-scripting-books/

View File

@ -0,0 +1,91 @@
What a Linux Desktop Does Better
============================================================
Linux 桌面系统的优势
![linux-desktop-advantages](http://www.linuxinsider.com/article_images/story_graphics_xlarge/xl-2017-linux-1.jpg)
![](http://www.linuxinsider.com/images/2015/image-credit-adobe-stock_130x15.gif)
当我放弃 Windows [转而使用 Linux 系统][3] 后,我的信心不断增长。出于安全方面的考虑促使我选用 Linux 系统,但是我很快发现了很多使用 Linux 桌面系统的优势。
对于那些还对 Linux 系统犹豫不决,或是那些不甚了解 Linux 系统的用户,我将通过这篇文章给大家介绍一些使用 Linux 桌面系统的优势。
### 免费才是王道
首先, Linux 系统完全免费。你无须为使用的操作系统或软件花费一分钱。除了免费获取软件产生的经济效益之外,你还可以在 Linux 系统中随意使用当前一些很流行的软件——比如文字处理软件和照片编辑软件——但是,由于费用方面的原因,我们可能不太愿意花钱去购买这些软件。
微软的 Office 办公软件几乎是处理各种类型文档的一种标准软件了,但是它每年的费用竟高达 70 美元。然而,你却可以免费使用 [LibreOffice][4] 软件来代替,它同样可以处理各种类型的文档,而且使用也很方便。
免费软件还能让您有机会尝试新的功能,并与它们一起寻求商业发展和操作便捷的新方式,而且你也不需要支付任何预期的费用。
与其费尽周折的去衡量 Mac 或 Windows 系统的优点,你可以考虑下在[上百款不同风格的 Linux 发行版][5]中选择一款最适合自己的操作系统。
Linux 系统甚至在硬件方面也为用户节省了不少钱,比如有些厂商——尤其是戴尔公司——为购买预安装了 Linux 系统的电脑的用户提供打折优惠。这些电脑的价格相对来说比较便宜,因为用户无须再花钱购买微软的 Windows 系统许可证。
### 随心所欲的系统定制
其次,在 Linux 系统中,你可以对系统功能进行任意更改。 Linux 生态系统中的核心项目之一就是桌面环境——它是一些由基础用户程序和可视化元素组成的一个集合,比如状态栏和启动器,这些元素构成了用户与计算机的一个交互界面。
有些 Linux 发行版还预安装了桌面环境。比如, Ubuntu 系统就预安装了 Unity 桌面。其它系统,比如 Debian 会在系统安装的过程中让用户选择需要的桌面环境。总之,在 Linux 系统中,用户都可以随意更换他们喜欢的桌面环境。
大多数的 Linux 发行版都支持(也就是兼容)那些非常流行的桌面环境,因此,找到一款适合自己的桌面系统也非常容易。在桌面系统这个万花筒里,你可以找到界面华丽的系统桌面,比如 KDE Plasma 或者 [Gnome][6],以及轻量级的系统桌面,比如 Xfce 和 MATE 桌面。使用任一款系统桌面,你都可以通过更改主题、系统托盘和菜单,以及根据其它用户的桌面环境来进一步定制自己的桌面环境。
Linux 系统的可定制特性完全超出你的想象力。如果你更看重系统的稳定性,你可以使用 Mint 这个发行版系统,它对硬件的兼容性非常好,而且也能确保系统顺利更新。
除此之外,如果你想使用最简洁的 Linux 系统,你可以安装 Arch Linux ,它提供最新的稳定版系统,并且每一款软件只要开发者发布出来,你就可以进行更新使用。
如果你愿意在源生版的 Linux 系统中运行几个小程序,你可以下载程序的源代码,然后自己进行编译。这就需要你使用工具来编译源代码,生成 01 的二进制文件,这样你的电脑才能运行该软件。
你可以使用自己喜欢的任何方式去折腾属于自己的 Linux 系统。
### 无与伦比的安全性
第三Linux 系统还有一个更重要的特性:安全。
起初,尽管有一些针对 Linux 系统的病毒,但是跟 Mac 系统比起来,已经屈指可数了。更重要的是,实际上 Linux 系统的核心代码是开源的,对用户完全透明,这意味着你的 Linux 系统漏洞更少。
然而,一些专有(未开源)的操作系统被认为是不安全的,因为它们会启动一些不透明的进程,这严重影响了系统的安全性。
比如说, Windows 系统在升级的过程中,默认情况下[不会检查加密签名][7]来验证更新文件的可靠性。
而使用 Linux 系统,你可以在选择更新时通过签名方式进行严格的细粒度控制,大多数的发行版在系统更新时都实行默认的安全设置。这种安全性源自 Linux 系统的开源开发模式。
像 Arch Linux 这种滚动发行版则增加了更多的安全性设置,因为一些重要的补丁一旦可用, Arch Linux 会即时进行验证。你可能很难找到那些每天都提供更新的单一主流操作系统,但是这样的 Linux 发行版却有很多。
### 开箱即用的编程环境
很多开发者或者任何对编程有兴趣的人都得益于 Linux 桌面系统中集成的强大开发工具。其中包括那些最经典的编程工具,比如 GNU C 编译器,或者 GCC 和 GNU Autoconf 工具都是 Linux 系统中一些非常重要的基础工具。
Linux 系统的默认软件库友好地支持数十种编程语言,这个软件库是 Linux 系统中的一个预编译软件池。
很多因特网的基础架构和相关连接设备都运行于 Linux 系统中——从服务器到智能设备,比如安防摄像机和恒温器。在 Linux 系统下开发调试这些设备的软件时非常容易。如果你有一个跟计算机相关的项目, Linux 系统可以完美地支持你完成这个项目。
### 社区是 Linux 系统发展的关键
最后一点, Linux 系统拥有一个紧密且友好型的社区。由于 Linux 在桌面系统中仅占有 3% 左右的市场份额,因此, Linux 社区更希望有更多的潜在用户加入进来。
Linux 系统有很多的用户论坛,尤其是对新手比较友好的 Unbuntu 系统论坛,它包括非常丰富且全面的知识来帮助用户解决一些基本的系统问题。很多高级用户更倾向于使用 Linux 系统,因此那些 Linux 发行版都拥有非常非常详尽维基文档,以指导用户完成高级的系统应用项目。
甚至还有业余的 Linux 论坛和 [Reddit] [8] 讨论区,所涉及的范围包括从对比 Linux 系统各种应用软件到炫耀桌面主题等。总而言之,这是一个比 Windows 用户群更加友善的社区。
我沉浸在 Linux 的世界里两年多了,我更加相信 Linux 系统对每一个用户都有所帮助。我希望这篇文章能够让你了解到 Linux 桌面系统的各种优势。但是真正的乐趣是从中发现自己感兴趣的东西!
--------------------------------------------------------------------------------
via: http://www.linuxinsider.com/story/84326.html?rss=1
作者:[Jonathan Terrasi ][a]
译者:[rusking](https://github.com/rusking)
校对:[校对者ID](https://github.com/校对者ID)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:http://www.linkedin.com/company/ect-news-network
[1]:http://www.linuxinsider.com/story/84326.html?rss=1#
[2]:http://www.linuxinsider.com/perl/mailit/?id=84326
[3]:http://www.linuxinsider.com/story/84286.html
[4]:http://www.libreoffice.org/
[5]:https://en.wikipedia.org/wiki/Linux_distribution
[6]:http://en.wikipedia.org/wiki/GNOME
[7]:https://duo.com/blog/out-of-box-exploitation-a-security-analysis-of-oem-updaters
[8]:http://www.reddit.com/

View File

@ -0,0 +1,324 @@
<header class="post-header" style="text-rendering: optimizeLegibility; font-family: &quot;Noto Serif&quot;, Georgia, Cambria, &quot;Times New Roman&quot;, Times, serif; font-size: 20px; text-align: start; background-color: rgb(255, 255, 255);">[在 Go 中如何使用切片的容量和长度][14]
============================================================</header>
<aside class="post-side" style="text-rendering: optimizeLegibility; position: fixed; top: 80px; left: 0px; width: 195px; padding-right: 5px; padding-left: 5px; text-align: right; z-index: 300; font-family: &quot;Noto Serif&quot;, Georgia, Cambria, &quot;Times New Roman&quot;, Times, serif; font-size: 20px;"></aside>
快速测试 - 下面的代码输出什么?
```
vals := make([]int, 5)
for i := 0; i < 5; i++ {
vals = append(vals, i)
}
fmt.Println(vals)
```
_[在 Go Playground 运行一下][1]_
如果你猜测的是 `[0 0 0 0 0 0 1 2 3 4]`,那你是对的。
_等等什么_ 为什么不是 `[0 1 2 3 4]`?
如果你在测试中做错了,你也不用担心。这是在 Go 过渡的过程中相当常见的错误,在这篇文章中,我们将说明为什么输出不是你预期的,以及如何利用 Go 的细微差别来使你的代码更有效率。
### 切片 vs 数组
在 Go 中同时有数组和切片。这可能令人困惑,但一旦你习惯了,你会喜欢上它。请相信我
切片和数组之间存在许多差异,但我们要在本文中重点介绍的内容是数组的大小是其类型的一部分,而切片可以具有动态大小,因为它们是围绕数组的包装。
这在实践中意味着什么?那么假设我们有数组 `val a [10]int`。该数组具有固定大小,且无法更改。如果我们调用 “len(a)”,它总是返回 10因为这个大小是类型的一部分。因此如果你突然在数组中需要超过 10 个项,则必须创建一个完全不同类型的新对象,例如 `val b [11]int`,然后将所有值从 `a` 复制到 `b`
在特定情况下,含有集合大小的数组是有价值的,但一般而言,这不是开发人员想要的。相反,他们希望在 Go 中使用类似于数组的东西,但是随着时间的推移,它们能够随时增长。一个粗略的方式是创建一个比它需要大得多的数组,然后将数组的一个子集视为数组。下面的代码是个例子。
```
var vals [20]int
for i := 0; i < 5; i++ {
vals[i] = i * i
}
subsetLen := 5
fmt.Println("The subset of our array has a length of:", subsetLen)
// Add a new item to our array
vals[subsetLen] = 123
subsetLen++
fmt.Println("The subset of our array has a length of:", subsetLen)
```
_[在 Go Playground 中运行][2]_
在代码中,我们有一个长度为 20 的数组,但是由于我们只使用一个子集,代码中我们可以假定数组的长度是 5然后在我们向数组中添加一个新的项之后是 6。
这是(非常粗略地说)切片是如何工作的。它们包含一个具有设置大小的数组,就像我们前面的例子中的数组一样,它的大小为 20。
它们还跟踪程序中使用的数组的子集 - 这就是 `append` 属性,它类似于上一个例子中的 `subsetLen` 变量。
最后,一个 slice 还有一个 `capacity`类似于前面例子中我们的数组20的总长度。这是很有用的 因为它会告诉你的子集在无法容纳切片数组之前可以增长的大小。当发生这种情况时,需要分配一个新的数组,但所有这些逻辑都隐藏在 `append` 函数的后面。
简而言之,使用 `append` 函数组合切片给我们一个非常类似于数组的类型,但随着时间的推移,它可以处理更多的元素。
我们再来看一下前面的例子,但是这次我们将使用切片而不是数组。
```
var vals []int
for i := 0; i < 5; i++ {
vals = append(vals, i)
fmt.Println("The length of our slice is:", len(vals))
fmt.Println("The capacity of our slice is:", cap(vals))
}
// Add a new item to our array
vals = append(vals, 123)
fmt.Println("The length of our slice is:", len(vals))
fmt.Println("The capacity of our slice is:", cap(vals))
// Accessing items is the same as an array
fmt.Println(vals[5])
fmt.Println(vals[2])
```
_[在 Go Playground 中运行][3]_
我们仍然可以像数组一样访问我们的切片中的元素,但是通过使用切片和 `append` 函数,我们不再需要考虑背后数组的大小。我们仍然可以通过使用 `len``cap` 函数来计算出这些东西,但是我们不用担心太多。简洁吧?
### 回到测试
记住这点,让我们回顾前面的测试,看下什么出错了。
```
vals := make([]int, 5)
for i := 0; i < 5; i++ {
vals = append(vals, i)
}
fmt.Println(vals)
```
当调用 `make` 时,我们允许最多传入 3 个参数。第一个是我们分配的类型,第二个是类型的 `长度`,第三个是类型的 `容量`_这个参数是可选的_
通过传递参数 `make([]int, 5)`,我们告诉程序我们要创建一个长度为 5 的切片,在这种情况下,默认的容量与长度相同 - 本例中是 5。
虽然这可能看起来像我们想要的那样,这里的重要区别是我们告诉我们的切片,我们要将 `长度``容量` 设置为 5假设你想要在初始的 5 个元素_之后_添加新的元素我们接着调用 `append` 函数,那么它会增加容量的大小,并且会在切片的最后添加新的元素。
如果在代码中添加一条 `Println()` 语句,你可以看到容量的变化。
```
vals := make([]int, 5)
fmt.Println("Capacity was:", cap(vals))
for i := 0; i < 5; i++ {
vals = append(vals, i)
fmt.Println("Capacity is now:", cap(vals))
}
fmt.Println(vals)
```
_[在 Go Playground 中运行][4]_
最后,我们最终得到 `[0 0 0 0 0 0 1 2 3 4]` 的输出而不是希望的 `[0 1 2 3 4]`
如何修复它呢?好的,这有几种方法,我们将讲解两种,你可以选取任何一种在你的场景中最有用的方法。
### 直接使用索引写入而不是 `append`
第一种修复是保留 `make` 调用不变,并且显式地使用索引来设置每个元素。这样,我们就得到如下的代码:
```
vals := make([]int, 5)
for i := 0; i < 5; i++ {
vals[i] = i
}
fmt.Println(vals)
```
_[在 Go Playground 中运行][5]_
在这种情况下,我们设置的值恰好与我们要使用的索引相同,但是你也可以独立跟踪索引。
比如,如果你想要获取 map 的键,你可以使用下面的代码。
```
package main
import "fmt"
func main() {
fmt.Println(keys(map[string]struct{}{
"dog": struct{}{},
"cat": struct{}{},
}))
}
func keys(m map[string]struct{}) []string {
ret := make([]string, len(m))
i := 0
for key := range m {
ret[i] = key
i++
}
return ret
}
```
_[在 Go Playground 中运行][6]_
这样做很好,因为我们知道我们返回的切片的长度将与 map 的长度相同,因此我们可以用该长度初始化我们的切片,然后将每个元素分配到适当的索引中。这种方法的缺点是我们必须跟踪 `i`,以便了解每个索引要设置的值。
这就让我们引出了第二种方法。。。
### 使用 `0` 作为你的长度并指定容量
与其跟踪我们要添加的值的索引,我们可以更新我们的 `make` 调用,并在切片类型之后提供两个参数。第一个,我们的新切片的长度将被设置为 `0`,因为我们还没有添加任何新的元素到切片中。第二个,我们新切片的容量将被设置为 map 参数的长度,因为我们知道我们的切片最终会添加许多字符串。
这会如前面的例子那样仍旧会在背后构建相同的数组,但是现在当我们调用 `append`它会将它们放在切片开始处因为切片的长度是0。
```
package main
import "fmt"
func main() {
fmt.Println(keys(map[string]struct{}{
"dog": struct{}{},
"cat": struct{}{},
}))
}
func keys(m map[string]struct{}) []string {
ret := make([]string, 0, len(m))
for key := range m {
ret = append(ret, key)
}
return ret
}
```
_[在 Go Playground 中运行][7]_
### 如果 `append` 处理它,为什么我们还要担心容量呢?
接下来你可能会问:“如果 `append` 函数可以为我增加切片的容量,那我们为什么要告诉程序容量呢?
事实是,在大多数情况下,你不必担心这太多。如果它使你的代码变得更复杂,只需用 `var vals []int` 初始化你的切片,然后让 `append` 函数处理接下来的事。
但这种情况是不同的。它并不是声明容量是困难的例子,实际上这很容易确定我们的切片的最后容量,因为我们知道它将直接映射到提供的 map 中。因此,当我们初始化它时,我们可以声明切片的容量,并免于让我们程序执行不必要的内存分配。
如果要查看额外的内存分配情况,请在 Go Playground 上运行以下代码。每次增加容量,程序都需要做一次内存分配。
```
package main
import "fmt"
func main() {
fmt.Println(keys(map[string]struct{}{
"dog": struct{}{},
"cat": struct{}{},
"mouse": struct{}{},
"wolf": struct{}{},
"alligator": struct{}{},
}))
}
func keys(m map[string]struct{}) []string {
var ret []string
fmt.Println(cap(ret))
for key := range m {
ret = append(ret, key)
fmt.Println(cap(ret))
}
return ret
}
```
_[在 Go Playground 中运行][8]_
现在将此与相同的代码进行比较, 但具有预定义的容量。
```
package main
import "fmt"
func main() {
fmt.Println(keys(map[string]struct{}{
"dog": struct{}{},
"cat": struct{}{},
"mouse": struct{}{},
"wolf": struct{}{},
"alligator": struct{}{},
}))
}
func keys(m map[string]struct{}) []string {
ret := make([]string, 0, len(m))
fmt.Println(cap(ret))
for key := range m {
ret = append(ret, key)
fmt.Println(cap(ret))
}
return ret
}
```
_[在 Go Playground 中运行][9]_
在第一个代码示例中,我们的容量从 `0` 开始,然后增加到 `1`、 `2`、 `4`, 最后是 `8`,这意味着我们不得不分配 5 次数组,最后一个容纳我们切片的数组的容量是 `8`,这比我们最终需要的要大。
另一方面,我们的第二个例子开始和结束都是相同的容量(`5`),它只需要在 `keys()` 函数的开头分配一次。我们还避免了浪费任何额外的内存,并返回一个能放下这个数组的完美大小的切片。
### 不要过分优化
如前所述,我通常不鼓励任何人担心这样的小优化,但如果最后大小的效果真的很明显,那么我强烈建议你尝试为切片设置适当的容量或长度。
这不仅有助于提高程序的性能,还可以通过明确说明输入的大小和输出的大小之间的关系来帮助澄清你的代码。
### 总结
>你好我写了很多关于Go、Web 开发和其他我觉得有趣的话题。
>
>如果你想跟上最新的文章,请[注册我的邮件列表][10]。我会给你发送我新书的样例、Go 的 Web 开发、以及每当有新文章(通常每周 1-2 次)会给你发送邮件。
>
>哦,我保证不会发垃圾邮件。我像你一样讨厌它 :)
本文并不是对切片或数组之间差异的详细讨论,而是简要介绍了容量和长度如何影响切片,以及它们在方案中的用途。
为了进一步阅读,我强烈推荐 Go 博客中的以下文章:
* [Go Slices使用及内部][11]
* [数组、切片和字符串“append” 的机制][12]
* [切片技巧][13]
--------------------------------------------------------------------------------
作者简介:
Jon 是一名软件顾问,也是 “Web Development with Go” 一书的作者。在此之前,他创立了 EasyPost一家 Y Combinator 支持的创业公司,并在 Google 工作。
https://www.usegolang.com
--------------------------------------------------------------------------------
via: https://www.calhoun.io/how-to-use-slice-capacity-and-length-in-go
作者:[Jon Calhoun][a]
译者:[geekpi](https://github.com/geekpi)
校对:[校对者ID](https://github.com/校对者ID)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://www.calhoun.io/hire-me
[1]:https://play.golang.org/p/7PgUqBdZ6Z
[2]:https://play.golang.org/p/Np6-NEohm2
[3]:https://play.golang.org/p/M_qaNGVbC-
[4]:https://play.golang.org/p/d6OUulTYM7
[5]:https://play.golang.org/p/JI8Fx3fJCU
[6]:https://play.golang.org/p/kIKxkdX35B
[7]:https://play.golang.org/p/h5hVAHmqJm
[8]:https://play.golang.org/p/fDbAxtAjLF
[9]:https://play.golang.org/p/nwT8X9-7eQ
[10]:https://www.calhoun.io/how-to-use-slice-capacity-and-length-in-go/?utm_source=golangweekly&utm_medium=email#mailing-list-form
[11]:https://blog.golang.org/go-slices-usage-and-internals
[12]:https://blog.golang.org/slices
[13]:https://github.com/golang/go/wiki/SliceTricks
[14]:https://www.calhoun.io/how-to-use-slice-capacity-and-length-in-go/

View File

@ -0,0 +1,408 @@
如何用Raspberry Pi控制GOIO引脚并操作继电器
==========================================
> 学习如何用PHP和温度传感器实现Raspberry Pi控制GPIO并操作继电器
![How to control GPIO pins and operate relays with the Raspberry Pi](https://opensource.com/sites/default/files/styles/image-full-size/public/images/life/raspberry_pi_day_lead_0.jpeg?itok=lCxmviRD "How to control GPIO pins and operate relays with the Raspberry Pi")
> 图片来源: opensource.com
你是否曾经想知道怎样使用手机或者电脑在任何地方控制你的风扇和等一些家用电器?
我现在想控制我的圣诞彩灯是使用手机呢还是使用平板电脑呢或者是使用笔记本电脑呢都不是而是仅仅使用一个Raspberry Pi。让我来告诉你如何使用PHP和温度传感器实现Raspberry Pi控制GPIO引脚并操作继电器。我使用AJAX把它们整合在了一起。
### 硬件要求:
* Raspberry Pi
* 安装有Raspbian系统的SD卡(任何一张SD卡都可以但是我更偏向使用一张大小为32GB等级为class 10的SD卡)
* 电源适配器
* 跳线(母对母跳线和公转母跳线)
* 继电器板(我使用一个用于12V继电器的继电器板)
* DS18B20温度传感器
* Raspberry Pi的Wi-Fi适配器
* 路由器(为了访问互联网,你需要有一个拥有端口转发的路由器)
* 10KΩ的电阻
### 软件要求:
* 下载并安装Raspbian系统到你的SD卡
* 有效的互联网连接
* Apache web服务器
* PHP
* WiringPi
* 基于Mac或者Windows的SSH客户端
### 一般的配置和设置
1\. 插入SD卡到Raspberry Pi然后使用以太网网线将它连接到路由器;
2\. 连接WiFi适配器;
3\. 使用SSH方式登录到Raspberry Pi然后使用下面的命令编辑**interfaces**文件:
> **sudo nano /etc/network/interfaces**
这个命令会用一个叫做**nano**的编辑器打开这个文件。它是一个非常简单又易于使用的文本编辑器。如果你不熟悉基于linux的操作系统可以使用键盘上的方向键来操作。
用**nano**打开这个文件后,你会看到这样一个界面:
![File editor nano](https://opensource.com/sites/default/files/putty_0.png "File editor nano")
4\.要配置你的无线网络,按照下面所示修改这个文件:
>**iface lo inet loopback**
>**iface eth0 inet dhcp**
>**allow-hotplug wlan0**
>**auto wlan0**
>**iface wlan0 inet dhcp**
>**   wpa-ssid "Your Network SSID"**
>**   wpa-psk "Your Password"**
5\. 按CTRL+O保存然后按CTRL+X退出编辑器。
到目前为止,一切都已经配置完成,接下来你需要做的就是使用命令重新加载网络:
> **sudo service networking reload**
(警告:如果你是使用远程连接的方式连接的Raspberry Pi连接将会中断。)
### 软件配置
#### 安装Apache web 服务器
Apache是一个受欢迎的服务器应用你可以在Raspberry Pi安装这个程序让它提供网页服务。
Apache原本就可以通过HTTP方式提供HTML文件服务添加其他模块后Apache还可以使用像PHP这样的脚本语言来提供动态网页的服务。
可以在命令行输入下面命令安装Apache:
> **sudo apt-get install apache2 -y**
安装完成后可以在浏览器地址栏输入Raspberry Pi的IP地址来测试web服务器。如果你可以获得下面图片的内容说明你已经成功地安装并设置好了你的服务器。
![Successful server setup](https://opensource.com/sites/default/files/itworks.png "Successful server setup")
要改变这个默认的页面和添加你自己的html文件进入**var/www/html**目录:
> **cd /var/www/html**
添加一些文件来测试是否成功。
### 安装PHP
PHP是一个预处理器这意味着它是当服务器收到网页请求时才会运行的一段代码。它开始运行处理网页上需要被显示的内容然后把网页发送给浏览器。不像静态的HTML,PHP在不同的环境下可以显示不同的内容。其他的语言也可以做到这一点但是由于WordPress是用PHP编写的有些时候你需要使用它。PHP是web上一种非常受欢迎的语言像Facebok和Wikipeadia这样的大型项目都是用PHP编写的。
使用下面的命令安装PHP和Apache软件包
> **sudo apt-get install php5 libapache2-mod-php5 -y**
#### 测试PHP
创建文件:**index.php**:
> **sudo nano index.php**
在里面写入一些PHP内容:
> **<?php echo "hello world"; ?>**
保存文件,接下来删除"index.html",因为它比"index.php"的优先级更高:
> sudo rm index.html
刷新你的浏览器,你会看到"hello world"。这并不是动态的但是它仍然由PHP提供服务。如果你在上面看到提原始的PHP文件而不是"hello world",重新加载和重启Apahce:
> **sudo /etc/init.d/apache2 reload**
> **sudo /etc/init.d/apache2 restart**
### 安装WiringPi
为了可以对代码的更改进行跟踪WiringPi的维护采用git。但假如你因为某些原因而没法使用git还有一种可以替代的方案B。(通常你的防火墙会把你隔离开来,所以请先检查一下你的防火墙的设置情况!)
如果你还没有安装git那么在Debian及其衍生版本中(比如Raspbian),你可以这样安装它:
> **sudo apt-get install git-core**
若是你遇到了一些错误请确保你的Raspberry Pi是最新版本的Raspbian系统
> **sudo apt-get update sudo apt-get upgrade**
使用git获取最WiringPi
> **sudo git clone git://git.drogon.net/wiringPi**
如果你之前已经使用过 clone操作那么可以使用下面命令:
> **cd wiringPi && git pull origin**
这个命令会将会获取更新的版本,你然后可以重新运行下面的构建脚本。
有一个新的简化的脚本来构建和安装:
> cd wiringPi && ./build
这个新的构建脚本将会为你完成编译和安装WiringPi。它曾一度需要使用**sudo**命令,所以在运行这它之前你可能需要检查一下这个脚本。
### 测试WiringPi
运行 **gpio** 命令来检查安装成功与否:
> **gpio -v gpio readall**
这将给你一些信心,软件运行良好。
### 连接DS18B20传感器到Raspberry Pi
* 传感器上的黑线用于GND。
* 红线用于VCC。
* 黄线是GPIO线。
![GPIO image](https://opensource.com/sites/default/files/gpio_0.png "GPIO image")
连线:
* VCC连接3V的1号引脚。
* GPIO线连接7号引脚(GPIO4)。
* 地线连接GND的9号引脚。
### 软件配置
为了用PHP使用DS18B20温度传感器模块你需要执行下面的命令来激活用于Raspberry Pi 上GPIO引脚和DS18B20的内核模块:
> **sudo modprobe w1-gpio**
> **sudo modprobe w1-therm**
你不想每次Raspberry重启后都手动执行上述命令所以你想每次开机能自动启动这些模块。可以在文件**/etc/modules**中添加下面的命令行来做到:
> **sudo nano /etc/modules/**
添加下面的命令行到它里面:
> **w1-gpio**
> **w1-therm**
为了测试,输入:
> cd /sys/bus/w1/devices/
现在输入ls。
你会看到你的设备信息。在设备驱动程序中你的DS18B20传感器应该作为一串字母和数字被列出。在本例中设备被记录为 28-000005e2fdc3。然后你需要使用cd命令来访问传感器用你自己的序列号替代我的: **cd 28-000005e2fdc3. **
DS18B20会周期性的将数据写入文件**w1_slave**所以你只需要使用命令cat来读出数据:**cat w1_slave.**。
这会生成下面的两行文本,输出中**t=** 表示摄氏单位的温度。在前两位数后面加上一个小数点(例如我收到的温度读数是30.125摄氏度)。
### 连接继电器
1\. 取两根跳线把其中一根连接到Pi上的GPIO24(18号引脚),另一根连接GND引脚。你可以参考下面这张图。
2\. 现在将跳线的另一端连接到继电器板。GND连接到继电器上的GND,GPIO输出线连接到继电器的通道引脚号这取决于你正使用的继电器型号。记住将Pi上的GND与继电器上的GND连接连接起来Pi上的GPIO输出连接继电器上的输入引脚。
![Headers](https://opensource.com/sites/default/files/headers.png "Headers")
注意!将继电器连接Pi的时候小心一些因为它可能会导致电流回流这会造成短路。
3\. 现在将电源连接继电器可以使用12V的电源适配器也可以将VCC引脚连接到Pi上的3.3V或5.5V引脚。
### 使用PHP控制继电器
让我们先写一个借助于WiringPi软件用来控制Paspberry Pi上GPIO引脚的PHP脚本。
1\. 在Apache服务器的网站根目录下创建一个文件使用下面命令切换到该目录
> **cd /var/www/html**
2\. 新建一个叫Home的文件夹
> **sudo mkdir Home**
3\. 新建一个叫on.php的脚本
> **sudo nano on.php**
4\. 在脚本中加入下面的代码:
```
<?php
system("gpio-g mode 24 out");
system("gpio-g write 24 1");
?>
```
5\. 使用CTRL+O保存文件CTRL+X退出。
上面的代码中你在第一行使用命令将24号GPIO引脚设置为output模式
> system(“ gpio-g mode 24 out “) ;
在第二行,你使用"1"将24号引脚GPIO打开在二进制中"1"表示打开,"0"表示关闭。
6\. 为了关闭继电器可以创建另外一个off.php文件并用"0"替换"1"。
```
<?php
system(" gpio-g mode 24 out ");
system(" gpio-g write 24 1 ");
?>
```
7\. 如果你已经将继电器连接了Pi可以在浏览器中输入你的Pi的IP地址并在后面加上目录名和文件名来进行访问
>** http://{IPADDRESS}/home/on.php **
这将会打开继电器。
8\. 要关闭它可以访问叫off.php的文件:
>**http://{IPADDRESS}/home/off.php**
现在你需要能够在一个单独 的页面来控制这两样事情而不用单独的刷新或者访问这两个页面。你可以使用AJAX来完成。
9\. 新建一个HTML文件并在其中加入下面代码
```
[html + php + ajax codeblock]
<html>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script type="text/javascript">// <![CDATA[
$(document).ready(function() {
$('#on').click(function(){
var a= new XMLHttpRequest();
a.open("GET", "on.php"); a.onreadystatechange=function(){
if(a.readyState==4){ if(a.status ==200){
 } else alert ("http error"); } }
a.send();
});
});
$(document).ready(function()
{ $('#Off').click(function(){
var a= new XMLHttpRequest();
a.open("GET", "off.php");
a.onreadystatechange=function(){
if(a.readyState==4){
if(a.status ==200){
 } else alert ("http error"); } }
a.send();
});
});
</script>
<button id="on" type="button"> Switch Lights On </button>
<button id="off" type="button"> Switch Lights Off </button>
```
10\. 保存文件进入你的web 浏览器目录然后打开那个网页。你会看到两个按钮它们可以打开和关闭灯泡。基于同样的想法你还可以使用bootstrap和CSS来创建一个更加漂亮的web界面。
### 在这个网页上观察温度
1\. 新建一个temperature.php的文件
```
sudo nano temperature.php
```
2\. 在文件中加入下面的代码用你自己的设备ID替换10-000802292522
```
<?php
//File to read
$file = '/sys/devices/w1_bus_master1/10-000802292522/w1_slave';
//Read the file line by line
$lines = file($file);
//Get the temp from second line
$temp = explode('=', $lines[1]);
//Setup some nice formatting (i.e., 21,3)
$temp = number_format($temp[1] / 1000, 1, ',', '');
//And echo that temp
echo $temp . " °C";
?>
```
3\. 打开你刚刚创建的HTML文件并创建一个新的带有 **id** “screen”的 `<div>`标签
```
<div id="screen"></div>
```
4\. 在这个标签后或者这个文档的尾部下面的代码:
```
<script>
$(document).ready(function(){
setInterval(function(){
$("#screen").load('temperature.php')
}, 1000);
});
</script>
```
其中,`#screen`是标签`<div>`的`id`,你想在它里面显示温度。它会每隔1000毫秒加载一次`temperature.php`文件。
我使用了bootstrap框架来制作一个漂亮的面板来显示温度你还可以加入多个icons和 glyphicons让网页更有吸引力。
这只是一个控制继电器板并显示温度的基础的系统,你可以通过创建基于定时和从恒温器读数等基于事件触发来进一步地对系统进行开发。
--------------------------------------------------------------------------------
作者简介:
Abdul Hannan Mustajab: 我17岁生活在印度。我正在追求科学数学和计算机科学方面的教育。我在spunkytechnology.com上发表关于我的项目的博客。我一直在对使用不同的微控制器和电路板的基于物联网的AI进行研究。
via: https://opensource.com/article/17/3/operate-relays-control-gpio-pins-raspberry-pi
作者:[ Abdul Hannan Mustajab][a]
译者:[译者ID](https://github.com/zhousiyu325)
校对:[校对者ID](https://github.com/校对者ID)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://opensource.com/users/mustajabhannan
[1]:http://www.php.net/system
[2]:http://www.php.net/system
[3]:http://www.php.net/system
[4]:http://www.php.net/system
[5]:http://www.php.net/system
[6]:http://www.php.net/file
[7]:http://www.php.net/explode
[8]:http://www.php.net/number_format
[9]:https://opensource.com/article/17/3/operate-relays-control-gpio-pins-raspberry-pi?rate=RX8QqLzmUb_wEeLw0Ee0UYdp1ehVokKZ-JbbJK_Cn5M
[10]:https://opensource.com/user/123336/feed
[11]:https://opensource.com/users/mustajabhannan

View File

@ -0,0 +1,99 @@
怎么使用Diff和Meld工具得到2个目录之间的不同之处呢
============================================================
在一个之前的一篇文章,我们回顾了[ Linux 下的 9 个最好的文件比较工具][1]在这片文章,我们将会描述在 Linux 下这么找到2个目录之间的不同。
一般,在Linux下比较2个文件,我们会使用diff (一个简单的原版的Unix命令行工具 )来显示2个计算机文件的不同;一行一行的去比较文件,而且很方便使用,几乎在全部的 Linux 发行版都预装了。
问题是在 Linux 下我们怎么才能比较2个目录的不同? 现在,我们想知道2个目录中那些文件/子目录是通用的,那些只存在一个目录。
运行diff常规的语法如下
```
$ diff [OPTION]… FILES
$ diff options dir1 dir2
```
默认情况下,输出是按文件/子文件夹的文件名的字母排序的,如下面截图所示,在这命令“-q”开关是告诉diif只有在文件有差异时报告。
```
$ diff -q directory-1/ directory-2/
```
[
![Difference Between Two Directories](http://www.tecmint.com/wp-content/uploads/2017/05/Difference-Between-Two-Directories.png)
][3]
2个文件之间的差异
再次运行diff并不能进入子文件夹但是我们可以使用'-r'开关和下面一样来读子文件夹。
```
$ diff -qr directory-1/ directory-2/
```
###使用Meld可视化的比较和合并工具
meld是一个很酷的图形化工具一个GNOME桌面下的可视化的比较和合并工具给那些喜欢使用鼠标的人你们能根据下面来安装。
```
$ sudo apt install meld [Debian/Ubuntu systems]
$ sudo yum install meld [RHEL/CentOS systems]
$ sudo dnf install meld [Fedora 22+]
```
一旦你安装了它之后搜索“meld”在 Ubuntu Dash 或者 Linux Mint 菜单也可以是Fedora或者CentOS桌面的Activities Overview然后启动它。
你可以看到在下面看到Meld接口你能和版本控制视图一样选择文件或者文件夹来比较。点击目录比较并移动到下个界面
[
![Meld Comparison Tool](http://www.tecmint.com/wp-content/uploads/2017/05/Meld-Comparison-Tool.png)
][4]
Meld 比较工具
选择你想要比较的文件夹注意你可以勾选“3-way Comparison”选项添加第3个文件夹。
[
![Select Comparison Directories](http://www.tecmint.com/wp-content/uploads/2017/05/Select-Comparison-Directories.png)
][5]
选择比较的文件夹。
一旦你选择好了要比较的文件夹,点击 “Compare”。
[
![Listing Difference Between +](http://www.tecmint.com/wp-content/uploads/2017/05/Listing-Difference-Between-Directories.png)
][6]
看结果出来了吧。
在这片文章我们描述了怎么在Linux下找到找出2个文件夹的不同。如果你知道其他的命令或者图形界面工具不要忘记在下方评论分享你们的想法。
--------------------------------------------------------------------------------
作者简介:
Aaron Kili 是一个Linux和F.O.S.S爱好者即将变成的Linux 系统管理员Web开发者目前是TecMint的内容创建者他喜欢与电脑工作并且非常相信分享知识。
-------------------
via: http://www.tecmint.com/compare-find-difference-between-two-directories-in-linux/
作者:[Aaron Kili ][a]
译者:[译者ID](https://github.com/译者ID)
校对:[校对者ID](https://github.com/校对者ID)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:http://www.tecmint.com/author/aaronkili/
[1]:http://www.tecmint.com/best-linux-file-diff-tools-comparison/
[2]:http://www.tecmint.com/freefilesync-compare-synchronize-files-in-ubuntu/
[3]:http://www.tecmint.com/wp-content/uploads/2017/05/Difference-Between-Two-Directories.png
[4]:http://www.tecmint.com/wp-content/uploads/2017/05/Meld-Comparison-Tool.png
[5]:http://www.tecmint.com/wp-content/uploads/2017/05/Select-Comparison-Directories.png
[6]:http://www.tecmint.com/wp-content/uploads/2017/05/Listing-Difference-Between-Directories.png
[7]:http://www.tecmint.com/compare-find-difference-between-two-directories-in-linux/#
[8]:http://www.tecmint.com/compare-find-difference-between-two-directories-in-linux/#
[9]:http://www.tecmint.com/compare-find-difference-between-two-directories-in-linux/#
[10]:http://www.tecmint.com/compare-find-difference-between-two-directories-in-linux/#
[11]:http://www.tecmint.com/compare-find-difference-between-two-directories-in-linux/#comments
[12]:http://www.tecmint.com/author/aaronkili/
[13]:http://www.tecmint.com/10-useful-free-linux-ebooks-for-newbies-and-administrators/
[14]:http://www.tecmint.com/free-linux-shell-scripting-books/