如何在 Ubuntu 16.04 上安装 OTRS （开源问题单系统）

Summary: OTRS ，即开源问题单ticket申请系统，是一个用于客户服务、帮助台和 IT 服务管理的开源问题单软件。对于那些需要管理票据、投诉、支持请求或其他类型的报告的公司和组织来说，这是一个问题单解决方案。

[OTRS](https://www.otrs.com) ，即开源<ruby> 问题单 <rp>  （ </rp> <rt>  ticket </rt> <rp>  ） </rp></ruby>申请系统，是一个用于客户服务、帮助台和 IT 服务管理的开源问题单软件。该软件是用 Perl 和 javascript 编写的。对于那些需要管理票据、投诉、支持请求或其他类型的报告的公司和组织来说，这是一个问题单解决方案。OTRS 支持包括 MySQL、PostgreSQL、Oracle 和 SQL Server 在内的多个数据库系统，它是一个可以安装在 Windows 和 Linux 上的多平台软件。

![](/data/attachment/album/201706/02/002835o3lba37az40sn7w7.png)

在本教程中，我将介绍如何在 Ubuntu 16.04 上安装和配置 OTRS。我将使用 PostgreSQL 作为 OTRS 的数据库，将 Apache Web 服务器用作 Web 服务器。

**先决条件**

* Ubuntu 16.04。
* 最小 2GB 的内存。
* root 权限

### 步骤 1 - 安装 Apache 和 PostgreSQL

在第一步中，我们将安装 Apache Web 服务器以及 PostgreSQL。我们将从 ubuntu 仓库中使用最新的版本。

使用 SSH 登录到你的 Ubuntu 服务器中：

```
ssh root@192.168.33.14

```

更新 Ubuntu 仓库。

```
sudo apt-get update

```

使用 apt 安装 Apache2 以及 PostgreSQL：

```
sudo apt-get install -y apache2 libapache2-mod-perl2 postgresql

```

通过检查服务器端口确保 Apache 以及 PostgreSQL 运行了。

```
netstat -plntu

```

![Install Apache and PostgreSQL](/data/attachment/album/201706/02/003032tkfmmhsmkczllk5q.png)

你可以看到 80 端口被 apache 使用了，5432 端口被 postgresql 数据库使用了。

### 步骤 2 - 安装 Perl 模块

OTRS 基于 Perl，因此我们需要安装一些 OTRS 需要的 Perl 模块。

使用这个 apt 命令安装 perl 模块：

```
sudo apt-get install -y libapache2-mod-perl2 libdbd-pg-perl libnet-dns-perl libnet-ldap-perl libio-socket-ssl-perl libpdf-api2-perl libsoap-lite-perl libgd-text-perl libgd-graph-perl libapache-dbi-perl libarchive-zip-perl libcrypt-eksblowfish-perl libcrypt-ssleay-perl libencode-hanextra-perl libjson-xs-perl libmail-imapclient-perl libtemplate-perl libtext-csv-xs-perl libxml-libxml-perl libxml-libxslt-perl libpdf-api2-simple-perl libyaml-libyaml-perl

```

安装完成后，我们需要为 apache 激活 Perl 模块，接着重启 apache 服务。

```
a2enmod perl
systemctl restart apache2

```

接下来，使用下面的命令检查模块是否已经加载了：

```
apachectl -M | sort

```

![Enable Apache Perl Module](/data/attachment/album/201706/02/003034r2xq945mpnjmok9p.png)

你可以在 “Loaded Modules” 部分下看到 **perl\_module**。

### 步骤 3 - 为 OTRS 创建新用户

OTRS 是一个基于 web 的程序并且运行与 apache web 服务器下。为了安全，我们需要以普通用户运行它，而不是 root 用户。

使用 useradd 命令创建一个 `otrs` 新用户：

```
useradd -r -d /opt/otrs -c 'OTRS User' otrs

```

* `-r`：将用户作为系统用户。
* `-d /opt/otrs`：在 `/opt/otrs` 下放置新用户的主目录。
* `-c`：备注。

接下来，将 `otrs` 用户加入到 `www-data` 用户组，因为 apache 运行于 `www-data` 用户及用户组。

```
usermod -a -G www-data otrs

```

在 `/etc/passwd` 文件中已经有 `otrs` 用户了。

```
grep -rin otrs /etc/passwd

```

![Create new user for OTRS](/data/attachment/album/201706/02/003035yq4bzj8wbov88lfw.png)

OTRS 的新用户已经创建了。

### 步骤 4 - 创建和配置数据库

在这节中，我们会为 OTRS 系统创建一个新 PostgreSQL 数据库，并对 PostgreSQL 数据库的配置做一些小的更改。

登录到 `postgres` 用户并访问 PostgreSQL shell。

```
su - postgres
psql

```

创建一个新的角色 `otrs`，密码是 `myotrspw`，并且是非特权用户。

```
create user otrs password 'myotrspw' nosuperuser;

```

接着使用 `otrs` 用户权限创建一个新的 `otrs` 数据库：

```
create database otrs owner otrs;
\q

```

接下来为 `otrs` 角色验证编辑 PostgreSQL 配置文件。

```
vim /etc/postgresql/9.5/main/pg_hba.conf

```

在 84 行后粘贴下面的配置：

```
local   otrs            otrs                                    password
host    otrs            otrs            127.0.0.1/32            password

```

保存文件并退出 vim

![Database Authentication OTRS](/data/attachment/album/201706/02/003036wbum160m6374qe1m.png)

使用 `exit` 回到 root 权限并重启 PostgreSQL：

```
exit
systemctl restart postgresql

```

PostgreSQL 已经为 OTRS 的安装准备好了。

![Configure PostgreSQL for OTRS](/data/attachment/album/201706/02/003041y8tetlu8tw94m891.png)

### 步骤 5 - 下载和配置 OTRS

在本教程中，我们会使用 OTRS 网站中最新的版本。

进入 `/opt` 目录并使用 `wget` 命令下载 OTRS 5.0：

```
cd /opt/
wget http://ftp.otrs.org/pub/otrs/otrs-5.0.16.tar.gz

```

展开该 otrs 文件，重命名目录并更改所有 otrs 的文件和目录的所属人为 `otrs`。

```
tar -xzvf otrs-5.0.16.tar.gz
mv otrs-5.0.16 otrs
chown -R otrs:otrs otrs

```

接下来，我们需要检查系统并确保可以安装 OTRS 了。

使用下面的 otrs 脚本命令检查 OTRS 安装需要的系统软件包：

```
/opt/otrs/bin/otrs.CheckModules.pl

```

确保所有的结果是对的，这意味着我们的服务器可以安装 OTRS 了。

![OTRS Chek Module needed for Installation](/data/attachment/album/201706/02/003044ozhfpofgr73c1o3k.png)

OTRS 已下载，并且我们的服务器可以安装 OTRS 了。

接下，进入 otrs 目录并复制配置文件。

```
cd /opt/otrs/
cp Kernel/Config.pm.dist Kernel/Config.pm

```

使用 vim 编辑 `Config.pm` 文件：

```
vim Kernel/Config.pm

```

更改 42 行的数据库密码：

```
$Self->{DatabasePw} = 'myotrspw';

```

注释 45 行的 MySQL 数据库支持：

```
# $Self->{DatabaseDSN} = "DBI:mysql:database=$Self->{Database};host=$Self->{DatabaseHost};";

```

取消注释 49 行的 PostgreSQL 数据库支持：

```
$Self->{DatabaseDSN} = "DBI:Pg:dbname=$Self->{Database};";

```

保存文件并退出 vim。

接着编辑 apache 启动文件来启用 PostgreSQL 支持。

```
vim scripts/apache2-perl-startup.pl

```

取消注释 60 和 61 行：

```
# enable this if you use postgresql
use DBD::Pg ();
use Kernel::System::DB::postgresql;

```

保存文件并退出编辑器。

最后，检查缺失的依赖和模块。

```
perl -cw /opt/otrs/bin/cgi-bin/index.pl
perl -cw /opt/otrs/bin/cgi-bin/customer.pl
perl -cw /opt/otrs/bin/otrs.Console.pl

```

你可以在下面的截图中看到结果是 “**OK**”：

![Check all modules again](/data/attachment/album/201706/02/003046w5jfvx5jf21ffy44.png)

### 步骤 6 - 导入样本数据库

在本教程中，我们会使用样本数据库，这可以在脚本目录中找到。因此我们只需要将所有的样本数据库以及表结构导入到第 4 步创建的数据库中。

登录到 `postgres` 用户并进入 otrs 目录中。

```
su - postgres
cd /opt/otrs/

```

作为 otrs 用户使用 `psql` 命令插入数据库以及表结构。

```
psql -U otrs -W -f scripts/database/otrs-schema.postgresql.sql otrs
psql -U otrs -W -f scripts/database/otrs-initial_insert.postgresql.sql otrs
psql -U otrs -W -f scripts/database/otrs-schema-post.postgresql.sql otrs

```

在需要的时候输入数据库密码 `myotrspw`。

![Import OTRS Sample Database](/data/attachment/album/201706/02/003051uuiinj58sa6tial7.png)

### 步骤 7 - 启动 OTRS

数据库以及 OTRS 已经配置了，现在我们可以启动 OTRS。

将 otrs 的文件及目录权限设置为 `www-data` 用户和用户组。

```
/opt/otrs/bin/otrs.SetPermissions.pl --otrs-user=www-data --web-group=www-data

```

通过创建一个新的链接文件到 apache 虚拟主机目录中启用 otrs apache 配置。

```
ln -s /opt/otrs/scripts/apache2-httpd.include.conf /etc/apache2/sites-available/otrs.conf

```

启用 otrs 虚拟主机并重启 apache。

```
a2ensite otrs
systemctl restart apache2

```

确保 apache 启动没有错误。

![Enable OTRS Apache Virtual Host](/data/attachment/album/201706/02/003052ub7vjebbvdz7vk0x.png)

### 步骤 8 - 配置 OTRS 计划任务

OTRS 已经安装并运行在 Apache Web 服务器中了，但是我们仍然需要配置 OTRS 计划任务。

登录到 `otrs` 用户，接着以 otrs 用户进入 `var/cron` 目录。

```
su - otrs
cd var/cron/
pwd

```

使用下面的命令复制所有 `.dist` 计划任务脚本：

```
for foo in *.dist; do cp $foo `basename $foo .dist`; done

```

使用 `exit` 回到 root 权限，并使用 otrs 用户启动计划任务脚本。

```
exit
/opt/otrs/bin/Cron.sh start otrs

```

![Enable OTRS Cron](/data/attachment/album/201706/02/003100yff5sbswfj5fllo5.png)

接下来，手动收取电子邮件的 PostMaster 创建一个新的计划任务。我会配置为每 2 分钟收取一次邮件。

```
su - otrs
crontab -e

```

粘贴下面的配置：

```
*/2 * * * *    $HOME/bin/otrs.PostMasterMailbox.pl >> /dev/null

```

保存并退出。

现在停止 otrs 守护进程并再次启动。

```
bin/otrs.Daemon.pl stop
bin/otrs.Daemon.pl start

```

![Enable OTRS Fetching Email](/data/attachment/album/201706/02/003104avxzlal61x6tyhlt.png)

OTRS 安装以及配置完成了。

### 步骤 9 - 测试 OTRS

打开你的 web 浏览器并输入你的服务器 IP 地址： <http://192.168.33.14/otrs/>

使用默认的用户 `root@localhost` 以及密码 `root` 登录。

![Installation Successfully OTRS Home Page](/data/attachment/album/201706/02/003107dkdnnxzlxpg8dsz5.png)

使用默认的 root 账户你会看到一个警告。点击警告信息来创建一个新的 admin root 用户。

下面是用另外的 admin root 用户登录后出现的 admin 页面，这里没有出现错误信息。

![OTRS Admin Dashboard Without Error Messages](/data/attachment/album/201706/02/003109y9cw28ccvdchn1y1.png)

如果你想作为客户登录，你可以使用 `customer.pl` ：<http://192.168.33.14/otrs/customer.pl>

你会看到客户登录界面，输入客户的用户名和密码。

![OTRS Customer Login Page](/data/attachment/album/201706/02/003109pntzn1nbop286yt1.png)

下面是一个创建新单据的客户页面。

![Customer Open Ticket](/data/attachment/album/201706/02/003112xlvltyvymltbe99z.png)

### 步骤 10 - 疑难排查

如果你仍旧看到 “OTRS Daemon is not running” 的错误，你可以像这样调试 OTRS 守护进程。

```
su - otrs
cd /opt/otrs/

```

停止 OTRS 守护进程：

```
bin/otrs.Daemon.pl stop

```

使用 `--debug` 选项启动 OTRS 守护进程。

```
bin/otrs.Daemon.pl start --debug

```

### 参考

* [http://wiki.otterhub.org/index.php?title=Installation*on*Debian*6*with\_Postgres](http://wiki.otterhub.org/index.php?title=Installation_on_Debian_6_with_Postgres)
* <http://www.geoffstratton.com/otrs-installation-5011-ubuntu-1604>
* <https://www.linkedin.com/pulse/ticketing-system-otrs-ubuntu-1404-muhammad-faiz-khan>

---

via: <https://www.howtoforge.com/tutorial/how-to-install-otrs-opensource-trouble-ticket-system-on-ubuntu-16-04/>

作者：[Muhammad Arul](https://www.howtoforge.com/tutorial/how-to-install-otrs-opensource-trouble-ticket-system-on-ubuntu-16-04/) 译者：[geekpi](https://github.com/geekpi) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


在 Go 中如何使用切片的容量和长度

使用Python这个功能没啥好说的

![](/data/attachment/album/201706/02/010040jzhp12rlrd2lhktp.jpg)

快速测试 - 下面的代码输出什么？

```
vals := make([]int, 5)
for i := 0; i < 5; i++ {
  vals = append(vals, i)
}
fmt.Println(vals)

```

*[在 Go Playground 运行一下](https://play.golang.org/p/7PgUqBdZ6Z)*

如果你猜测的是 `[0 0 0 0 0 0 1 2 3 4]`，那你是对的。

*等等，什么？* 为什么不是 `[0 1 2 3 4]`?

如果你在测试中做错了，你也不用担心。这是在过渡到 Go 语言的过程中相当常见的错误，在这篇文章中，我们将说明为什么输出不是你预期的，以及如何利用 Go 的细微差别来使你的代码更有效率。

### 切片 vs 数组

在 Go 中同时有数组（array）和切片（slice）。这可能令人困惑，但一旦你习惯了，你会喜欢上它。请相信我。

切片和数组之间存在许多差异，但我们要在本文中重点介绍的内容是数组的大小是其类型的一部分，而切片可以具有动态大小，因为它们是围绕数组的封装。

这在实践中意味着什么？那么假设我们有数组 `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 中运行](https://play.golang.org/p/Np6-NEohm2)*

在代码中，我们有一个长度为 `20` 的数组，但是由于我们只使用一个子集，代码中我们可以假定数组的长度是 `5`，然后在我们向数组中添加一个新的项之后是 `6`。

这是（非常粗略地说）切片是如何工作的。它们包含一个具有设置大小的数组，就像我们前面的例子中的数组一样，它的大小为 `20`。

它们还跟踪程序中使用的数组的子集 - 这就是 `append` 属性，它类似于上一个例子中的 `subsetLen` 变量。

最后，一个切片还有一个 `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 中运行](https://play.golang.org/p/M_qaNGVbC-)*

我们仍然可以像数组一样访问我们的切片中的元素，但是通过使用切片和 `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 中运行](https://play.golang.org/p/d6OUulTYM7)*

最后，我们最终得到 `[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 中运行](https://play.golang.org/p/JI8Fx3fJCU)*

在这种情况下，我们设置的值恰好与我们要使用的索引相同，但是你也可以独立跟踪索引。

比如，如果你想要获取 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 中运行](https://play.golang.org/p/kIKxkdX35B)*

这样做很好，因为我们知道我们返回的切片的长度将与 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 中运行](https://play.golang.org/p/h5hVAHmqJm)*

### 如果 `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 中运行](https://play.golang.org/p/fDbAxtAjLF)*

现在将此与相同的代码进行比较，但具有预定义的容量。

```
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 中运行](https://play.golang.org/p/nwT8X9-7eQ)*

在第一个代码示例中，我们的容量从 `0` 开始，然后增加到 `1`、 `2`、 `4`, 最后是 `8`，这意味着我们不得不分配 5 次数组，最后一个容纳我们切片的数组的容量是 `8`，这比我们最终需要的要大。

另一方面，我们的第二个例子开始和结束都是相同的容量（`5`），它只需要在 `keys()` 函数的开头分配一次。我们还避免了浪费任何额外的内存，并返回一个能放下这个数组的完美大小的切片。

### 不要过分优化

如前所述，我通常不鼓励任何人做这样的小优化，但如果最后大小的效果真的很明显，那么我强烈建议你尝试为切片设置适当的容量或长度。

这不仅有助于提高程序的性能，还可以通过明确说明输入的大小和输出的大小之间的关系来帮助澄清你的代码。

### 总结

>
> 你好！我写了很多关于Go、Web 开发和其他我觉得有趣的话题。
>
>
> 如果你想跟上最新的文章，请[注册我的邮件列表](https://www.calhoun.io/how-to-use-slice-capacity-and-length-in-go/?utm_source=golangweekly&utm_medium=email#mailing-list-form)。我会给你发送我新书的样例、Go 的 Web 开发、以及每当有新文章（通常每周 1-2 次）会给你发送邮件。
>
>
> 哦，我保证不会发垃圾邮件。我像你一样讨厌它 :)
>
>
>

本文并不是对切片或数组之间差异的详细讨论，而是简要介绍了容量和长度如何影响切片，以及它们在方案中的用途。

为了进一步阅读，我强烈推荐 Go 博客中的以下文章：

* [Go Slices：使用及内部](https://blog.golang.org/go-slices-usage-and-internals)
* [数组、切片（和字符串）：“append” 的机制](https://blog.golang.org/slices)
* [切片技巧](https://github.com/golang/go/wiki/SliceTricks)

---

作者简介：

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](https://www.calhoun.io/hire-me) 译者：[geekpi](https://github.com/geekpi) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


Fuchsia 对 Android 意味着什么

fuchsia flutter dart <br />
最近表示密切关注

Fuchsia 可能是下个会替代 Android 或 Chrome OS 的系统。猜测有很多，Jack Wallen 对此补充了一些给 Google 的赞誉和告诫。

![fuchsiahero.jpg](/data/attachment/album/201706/03/150725uijqhhoo7qu1do3o.jpg)

Google 总是以 “Google” 的方式解决或者做某件事。因此，当他们开始做一个让很多人挠头的项目时，大家是不觉得奇怪的。该项目被称为 [Fuschia](https://github.com/fuchsia-mirror)，大多数密切关注 Google 和 Android 的人都知道这个新平台。

对于那些还没紧跟 Google 最新消息的用户而言，Fuschia 是一个新的、开源的实时操作系统，它首先出现于 2016 年 8 月。那时，Fuchsia 只不过是一个命令行。一年不到的时间过去了，这个平台已经有了一个相当有趣的 GUI。

可能最让 Linux 拥趸失望的是，Fuchsia 并没有使用 Linux 内核。这个项目完全是 Google 开发的，使用了 Google 开发的名为 “Magenta”微内核。他们为什么这么做？了解到 Google 的最新设备 Pixel 运行的内核是 Linux 内核 3.18，你就会有你自己的答案了。Linux 3.18 发布于 2014 年（也就是说，在技术上已经过时了）。既然这样，为什么 Google 不能自己完全单干，以便尽可能地保持他们的移动平台跟上最新发展？

尽管我不愿意承认 Linux 可能不会（在未来的某个时期）成为全球最广泛使用的生态系统，但我相信这是 Google 的正确举措，不过我有一个重要的告诫。

### 首先，一些赞誉

首先我必须说，Google 开源 Fuchsia 这事真棒。Android 已经从开源的 Linux 内核中受益多年，所以这促使了 Google 开放他们最新的项目。说实话，如果不是开源和 Linux 内核，Android 就不会发展得那么快了。事实上，我大胆猜测，如果 Android 没有 Linux 和开源的支持，现在移动市场份额会显示出非常不同的、由苹果制定的结果。

一些喝彩是有必要的。操作系统不时需要完全重新思考。Android 是一个为移动平台服务得很好的令人惊奇的平台。然而，走到现在也就差不多了。考虑到消费界一直在寻找下一个大事件，而 Android（和 iOS）的潜力已尽榨干。与一个严重过时的内核相比，还是准备迎接对 Fuchsia 的喜爱吧。

谷歌从来不会停滞不前，这个新平台是证明。

### 一个告诫

开始这部分之前，我需要先给大家展示我的开源背景。自从 90 年代末以来，我一直是 Linux 的用户，并几乎涉及了开源的各个方面。在过去几年中，我一直在关注 Ubuntu 的发展，并对他们（现在）失败的融合尝试发表过看法。换言之，这也是我对 Fuchsia 的担心。

我认为 Google 对 Fucshia 的大计划是创建一个面对所有设备的操作系统：智能手机、IoT、Chromebook。从表面看来，这听起来像是一个会有重大成果的想法。但是，如果你看过 Canonical 对 Unity 8/Mir 融合的努力，你就会对“一个平台统治所有”的想法感到畏惧。当然这并不完全相同。我觉得 Google 正在创建一个单一的平台，让你 “融合” 所有的设备。毕竟，智能手机与物联网融合有什么好处？我们不需要在手机和恒温器之间交换数据。对么？对么？？？

即使如此，这应该是谷歌的计划，我会提醒他们近距离了解下 Canonical 和 Unity 8 之间发生的事。想法很好，但根本无法实现。

我也有可能错了。Google 可能只是将 Fuchsia 看作是 Android 的替代品。这很可能是 Google 需要替换过时的 Linux 内核，并决定“把一切都包含进来”。但是考虑到 Armadillo（Fuchsia UI）由跨平台的 [Flutter SDK](https://flutter.io/) 编写，跨越平台边界的想法就有了可能。

或者，也许 Fuchsia 只是谷歌说的 “让我们用今天所知道的知识重建我们的智能手机平台，看看它会走向何方”。如果是这样，我可以想象，Google 移动操作系统将会取得重大成功。然而，现实情况是，人们必须面对的是“一个平台统治所有”还有许多要解决的事情。Google 已经在 Chromebook 上测试 Android app 很长时间了。不幸的是，这个思路一直反响平平（最多如此）。随着微软以自己的方式来直面 Chromebook，Google 知道他们必须扩大生态系统，否则将会失去宝贵的领地（如在教育领域）。要解决这个问题的一种方法是使用单个操作系统来驱动智能手机和 Chromebook。这意味着所有的程序都可以在两个平台（这是一个重要的福音）运行以及生态系统的普遍性（再一次，这是巨大的福音）。

### 猜测

Google 对会引发很多行家的猜测的事情一直小心谨慎。一般来说，至少对于 Android，谷歌似乎一直都在做出正确的选择。如果他们相信 Fuchsia 是要走的路，那么我就倾向于相信他们。然而，围绕这个平台有如此多的不确定性会让人们一直迫切地要知道。

那你怎么看？Fuchsia 会成为什么？和我一起猜猜看。

---

作者简介：

Jack Wallen 是 TechRepublic 和 Linux.com 的获奖作家。他是开源的狂热倡导者, 也是 The Android Expert 的代言人。有关 Jack Wallen 的更多消息，请访问他的网站 jackwallen.com。

---

via: <http://www.techrepublic.com/article/what-fuchsia-could-mean-for-android/>

作者：[Jack Wallen](http://www.techrepublic.com/article/what-fuchsia-could-mean-for-android/#modal-bio) 译者：[geekpi](https://github.com/geekpi) 校对：[jasminepeng](https://github.com/jasminepeng)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


十动然拒：一款 Linux 笔记本电脑点评

Summary: 我是个 Mac 电脑重度用户，但我其实 对目前最新的 MacBook Pro 是失望的。由此我就开始去研究了下看是否有 一些可以替代前者（New MacBook Pro） 的选择。然而让我也意想不到的是，这居然使我产生了离开 Mac 平台的决定。

ubantu不好用，不够稳定，不如XP，也容易造成死机，虽然我自己的电脑性能也是问题，但作为一种linux系统，ubantu比XP更容易死机，后来装windows7,速度反而更快，更稳定。所以，我相信，如果不和芯片厂商联合研发，linux系统想代替windows，还要稳定好用，是完全不可能的事情，那纯粹是一种经不起考验的传说！

Linux是Intel的子公司，所以只支持Intel的产品。我现在使用的sandy bridge，在Ubuntu下3天了，没遇到什么问题。

Linux 多好, 但都是受有限资源的限制

死机的问题, 多源自用户没注意与监控 RAM 内存的使用.

明明不够用, 还启动太多程序与服务(包括自动启动的), 让 RAM 耗尽导致死机, 这简直就是作死的典范.

这回复里都是些什么玩意啊。。

KDE其实挺不错的，不过起点太高了。

Linux是intel的子公司。。。我还以为错过了什么大新闻

哈哈，这是调侃啦

HP是个好东西，Ubuntu是个好东西，钱是个好东西。。。

二合一、触摸屏什么的还是不要用Linux了。否则很多硬件用起来可能有问题。<br />
就普通台式机和笔记本还是可以的。

>
> 简述：我是个 Mac 电脑重度用户，但我其实 [对目前最新的 MacBook Pro 是失望的](http://www.onebigfluke.com/2016/10/lamenting-progress.html)。由此我就开始去研究了下看是否有 [一些可以替代前者（New MacBook Pro）](http://www.onebigfluke.com/2016/10/alternatives-to-apple-computers.html) 的选择。然而让我也意想不到的是，这居然使我产生了离开 Mac 平台的决定。
>
>
>

![](/data/attachment/album/201706/03/154436lp44p43t3qdq0u7q.jpg)

首先我们来看看 2017 年 CES（LCTT 译注：International Consumer Electronics Show，国际消费类电子产品展览会）大会后发布的 HP Spectre x360 13 寸笔记本电脑，拥有 4K 显示屏的新款笔记本电脑。我是从[百思买](http://www.bestbuy.com/site/hp-spectre-x360-2-in-1-13-3-4k-ultra-hd-touch-screen-laptop-intel-core-i7-16gb-memory-512gb-solid-state-drive-dark-ash-silver/5713178.p?skuId=5713178)（这不是一个赞助链接）买来的这款电脑，因为这是唯一售卖这款配置的零售商。我的目标是使用 Ubuntu 这个系统替代跑在这款笔记本上的 Windows 。

以下是我过去几个月使用这款笔记本的感受，还有一些在使用中对自己的使用习惯的重新认识。

### Ubuntu 系统

安装 Ubuntu 还是很简单的。当时电脑到手的时候预装的是 Windows 10 的系统。当时我使用 Windows 内建的硬盘管理工具来 [缩减主分区](https://www.howtogeek.com/101862/how-to-manage-partitions-on-windows-without-downloading-any-other-software/) 并将剩余的空间分配给 Linux 系统。我 [通过 USB 设备加载了 Ubuntu 系统镜像](https://www.ubuntu.com/download/desktop/create-a-usb-stick-on-windows)，这款笔记本能够很方便的适配 USB-A 接口（这在新版的 Mac 系列电脑是没有的）。然后我就按照 [Ubuntu 的简便安装说明](https://www.ubuntu.com/download/desktop/install-ubuntu-desktop)，将 BIOS 设置为 [从 USB 启动](http://support.hp.com/us-en/document/c00364979)。

### 屏幕

Spectre x360 的 4k 显示屏简直令人惊艳。令我觉得吃惊的是，最新的 Ubuntu 系统在高 DPI 的屏幕上体验也是非常不错的。系统内建的设置工具配合 [gnome-tweak-tool](https://launchpad.net/gnome-tweak-tool) 这样的附加工具，你可以更好的控制用户界面在 4K 屏上的渲染，2 倍于原生大小的控件使得它们看起非常不错，你也可以将默认字体大小调整到一个合适的比例，甚至还可以调整窗口标题栏和任务管理器上的图标大小。虽然有点繁琐，但我自己设置时也没花多久时间。

### 触控板

实话说触控板有点细微的声音，但还是能够很不错的配合手指移动，Ubuntu 系统也默认支持多点触控。然而你会很快的发现你在打字的时候会误触触控板导致光标到处乱晃。在 Linux 上的默认 Synaptics 触控驱动并不能够很好的识别这款机型的手掌误触，解决方法是切换到 [新的 libinput 系统](https://launchpad.net/xserver-xorg-input-libinput)，通过调整 [xinput 设置](https://wiki.archlinux.org/index.php/Libinput#Configuration) 就可以让触控板工作的不错。

但我所习惯的手势操作，比如两指滑动回到 Chrome 浏览器，又或者说四指滑动切换工作区，这些操作在 Ubuntu 系统上就没法用了，或者实在想用可以通过 [libinput-gestures](https://github.com/bulletmark/libinput-gestures) 这样的工具来启用他们。令人失望的是，就算使用上面的工具体验其实也一般，因为其实只有 50% 的几率能识别那些手势。“点击触控板”的功能也有些问题：当你使用大拇指双击触控板或触控板按钮表面想要点击，系统会认为你要移动光标或者使用多点触控来调整大小，又一次的失望。

### 键盘

键盘手感就还不错。键盘的键程挺长，这样打起字来就会比较快。左侧 Ctrl 键在左下角所以对我来说就几乎用不上了（不像 Macs 系列电脑就会将 function 键放在那）。方向键工作的不错。比较奇特的是，键盘右侧有一列额外的键，分别是 Delete 键、Home 键、Page Up 键、Page Down 键和 End 键。由于使用习惯导致我在将手从箭头控制键换到 Home 键的时候没法额外考虑还有一列键。而且由于这样的设计我在打字时手没法维持在键盘中央，这让我觉得好像离键盘右侧的键远了许多。

起初我觉得那一列键（Home 键、Page Up 键之类）是多余的，但自从我使用 Sublime Text（一款代码编辑器）来写代码之后，我发现在 Linux 系统和 Windows 系统下输入文本时其实挺依赖那些键的，这就很好理解为什么惠普公司在设计时决定要加入这些键了。作为一个 Mac 用户，我经常会使用 Command 键和向右键来使光标到行结束的位置，而在 Linux 系统和 Windows 系统用户就直接使用 End 键。其实要将键盘映射成和 Mac 一样也不是不行的，但是却很难保证所有的程序都会一样的映射。我花了挺多时间在重组我的肌肉记忆上，这个过程蛮痛苦的，就好像我尝试去使用 [Dvorak 键盘布局](https://en.wikipedia.org/wiki/Dvorak_Simplified_Keyboard) 的那个夏天。

### 音响

此款机型有四个扬声器：两个 B&O（Bang & Olufsen，音响制造商）扬声器在上部，两个在下部。上部的两个扬声器在 Ubuntu 系统中没法工作，这是一个 [内核问题](https://bugzilla.kernel.org/show_bug.cgi?id=189331)，尚未解决。下部的两个扬声器正常工作但声音有点小。耳机插孔使用正常，当插上耳机时扬声器也会自动静音。但我相信这可能是由于我为了让其他的硬件工作而将内核升级到了 [4.10 测试版本](http://kernel.ubuntu.com/%7Ekernel-ppa/mainline/v4.10/) 才出现的。我觉得社区最终会解决内核问题，所以上部扬声器无法工作的问题应该只是暂时性的。这些情况其实也就证明了为什么惠普公司自带的是带有一堆额外的神奇驱动的 Windows 系统。

### 电池续航

电池续航的问题真的就很糟糕了，我想主要是因为 4k 显示屏太耗电了。此外我还发现了 CPU 散热风扇在高速运转使会从笔记本左侧的出风口吹出热风。这风热的程度如果你把它放到你的腿上会让你感觉很不舒服。我觉得这应该是 Ubuntu 的默认电源管理配置的缺陷。为了解决这个问题，你可以使用诸如 [powertop](https://blog.sleeplessbeastie.eu/2015/08/10/how-to-set-all-tunable-powertop-options-at-system-boot/) 或者 [pm-powersave](http://askubuntu.com/questions/765840/does-pm-powersave-start-automatically-when-running-on-battery) 这样的工具。Intel 公司也提供 [Linux 系统固件支持](https://01.org/linuxgraphics/downloads/firmware) 来使 GPU 更好的工作。通过各种优化，我可以使电池续航能力接近 5 小时：和广告中宣传的 9 小时以上相去甚远。其实也有好的一点，使用 USB-C 接口充电速度快很多。这个接口也能很好的配合我得 Nexus X 手机充电，因为它们都是一样的接口。

### 二合一

惠普 Spectre x360 这款机型名字来源于它独特的设计，通过屏幕旋转可以变成一台平板电脑。变形后在 Ubuntu 系统上无需设置就可以完成点击、滚动和缩放操作。它甚至支持直接使用前进/后退手势操作，这些操作连它的触摸板也不支持。当你将它旋转为平板模式，键盘和触摸板会自动禁用。你可以将系统设置为 [便携模式](https://launchpad.net/onboard)，Gnome 桌面键盘就会启用，体验还不错哦。比较糟糕的是不支持屏幕自动旋转，但我还是使用 [iio-sensor-proxy](https://github.com/hadess/iio-sensor-proxy) 和 [这个一次性脚本](http://askubuntu.com/questions/634151/auto-rotate-screen-on-dell-13-7000-with-15-04-gnome/889591#889591) 东拼西凑地实现了这个功能。最后我虽然实现了这个功能，但是我发现使用 16:9 的屏幕好伤我的眼睛，当电脑处于平板电脑时候我需要使我的眼睛移动很长一段距离。

### 窗口管理器和各种软件

从 1998 年 RedHat 5.0 版开始我就不怎么常用 Linux 桌面版本了。时光飞逝，Ubuntu 发展迅猛，默认用户界面是他们自主研发的 Unity（Gnome 的变体），感觉还不错。我其实用过原生的 Gnome ，但它与别的桌面比较起来让我觉得非常的笨拙。我最后还是最喜欢 KDE，而且如果让我再次选择，我也会选择 KDE 的 [Kubuntu](https://www.kubuntu.org/)。总体来说 KDE 的窗口管理器让我觉得非常棒而且我想要的它都有！

在这次的回归 Linux 探索中，我意识到其实我基本上就在使用以下 8 个软件：浏览器（Chrome）、终端（没什么特别喜欢的）、文本编辑器（Sublime Text 3）、配置工具、可视化文件管理器、自动化备份工具（Arq）、类似 Flux 的屏幕亮度调节器，和图片编辑器（GIMP）。这几乎就是我所需要的软件了，其他别的需求非常容易满足。此外，我还比较依赖几个控件：时钟、WIFI 状态、电池状态和音量调节。我一般也会使用任务管理器（比如 Dock）和虚拟工作空间（比如 Mission Control 或 Expose）。我几乎不会用桌面图标、桌面提醒、最近使用的软件、搜索功能和应用软件菜单，所以我就可以适应 Linux 系统的种种设置了。

### 十动然拒

如果你正在考虑购入一款笔记本电脑，或许可以试试这款。尽管我是这样说，我还是准备要卖掉这台 Spectre x360，然后回到我的 2012 年中期款的 MacBook Air 怀抱中去。也不能说惠普公司或是 Linux 桌面平台的错吧，主要还是因为时间更宝贵。

我是如此的被 Mac 系统的高端用户体验所宠爱着，以至于我对别的东西都特别难以高效起来。我的脑袋几乎已经被 Mac 的触摸板、键盘布局和打字输入习惯等等体验所征服。所以我用起来惠普的电脑和 Linux 系统就觉得被拖慢了很多，感觉好像我就要完蛋了。当我使用计算机的时候，我只希望花更多的时间在提高我的技术（编程、写作等等）上。我只希望我将我仅有的“再学习”能力使用在一些尚未明白和不熟悉的课题上，比如 [新型函数式编程语言](http://docs.idris-lang.org/en/latest/tutorial/index.html#tutorial-index) 和 [同态加密](https://arxiv.org/abs/1702.07588) 等等。我再也不想花更多的时间去学习什么基本使用方法了。

反过来说，我也曾花了超过 2 年时间去学习弹钢琴，弹钢琴需要我死记硬背和不断的机械性重复训练。当我在学习钢琴的时候我发现这个过程其实打开了我的思维，让我对曾经有了更深的理解。我对音乐的学习，也让我懂得了许多曾经没有理解的事。可以说，我对音乐的“再学习”打开了我的视野。所以，我也琢磨去适应惠普的硬件和 Linux 桌面系统会不会也对我有这样的影响。

最终说明，我还是固执的。可能以后吧，我也会需要去适应新的工作方式来让我保持最新的状态，就好像电报员终有一天一定会从摩斯电码转向去使用 [电传打字机](https://en.wikipedia.org/wiki/Teleprinter) 一样。我希望到了未来的那天，我仍然会有耐心和远见让我平滑的过渡。可能，只有当这样东西会创造出更多的可能性，我才会选择那些需要“再学习”的东西，就好像一个为达到目的才去做的石蕊试验（测试液体酸碱度？）一样。至少目前来说，我还是会选择留在 Mac 下。

---

作者简介：

我是《Effective Python》一书的作者，我是一名软件工程师，我曾在谷歌工作了 11 年，我目前专注于调查统计，此外，我还曾在云计算基础设施建设和开放协议上有过工作经验。

以后，如果你还想阅读我写的文章，可以关注我的推 @haxor。如果你遇到什么问题，也可以写邮件给我，或者直接在下面写评论。如果你觉得这篇文章还不错，点击这里也可以看看我别的兴趣爱好。

---

via: <http://www.onebigfluke.com/2017/04/discovering-my-inner-curmudgeon-linux.html>

作者：[Brett Slatkin](http://www.onebigfluke.com/) 译者：[kenxx](https://github.com/kenxx) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


Samba 系列（十）：如何在 CentOS 7 上安装 iRedMail 集成到 Samba4 AD

Summary: 本系列教程将引导你了解如何在 CentOS 7 安装 iRedMail 以及 Samba4 AD 域控制器，以便域帐户可以通过 Thunderbird 桌面客户端或通过 Roundcube Web 界面发送或接收邮件。

新版的 里面 SOGO 可以实现 exchange 地址簿同步的 效果了么、

![](/data/attachment/album/201706/03/183457zc0cexazlnx4z0kv.jpg)

本系列教程将引导你了解如何在 CentOS 7 安装 iRedMail 以及 [Samba4 AD 域控制器](/article-8065-1.html)，以便域帐户可以通过 Thunderbird 桌面客户端或通过 Roundcube Web 界面发送或接收邮件。

将要安装 iRedMail 的 CentOS 7 服务器需允许通过 25 和 587 端口进行 SMTP 或邮件路由服务，并且还将通过 Dovecot 作为邮件传递代理，提供 POP3 和 IMAP 服务，两者都使用安装过程中签发的自签名证书进行安全保护。

收件人邮箱将与 Roundcube 提供的 webmail 用户代理一起存储在同一台 CentOS 服务器上。iRedMail 将使用 Samba4 AD 来查询和验证收件人帐户，在 AD 组的帮助下创建邮件列表，并通过 Samba4 AD DC 控制邮件帐户。

#### 需要：

* [在 Ubuntu 上使用 Samba4 创建 AD 基础架构](/article-8065-1.html)

### 步骤 1：在 CentOS 7 上安装 iRedMail

1、 在安装 iRedMail 之前，请先确保你使用下面的指南在你的机器上安装了一个全新的 CentOS 7 操作系统：

* [全新安装 CentOS 7 Minimal](/article-8048-1.html)

2、 同样使用下面的命令确保系统更新了最新的安全补丁和软件包。

```
# yum update

```

3、 系统同样需要一个 FQDN 主机名，使用下面的命令设置。使用你自定义的 FQDN 代替 `mail.tecmint.lan` 变量。

```
# hostnamectl set-hostname mail.tecmint.lan

```

使用下面的命令验证系统主机名。

```
# hostname -s   # Short name
# hostname -f   # FQDN
# hostname -d   # Domain
# cat /etc/hostname  # Verify it with cat command

```

![Verify CentOS 7 Hostname](/data/attachment/album/201706/03/183638vwfjjfsxp0sxlwjc.png)

*验证 CentOS 7 主机名*

4、 通过手动编辑 `/etc/hosts`，将机器的 FQDN 和短名称映射到机器的回环 IP 地址。添加如下所示的值，并相应替换 `mail.tecmint.lan` 和 mail 的值。

```
127.0.0.1   mail.tecmint.lan mail  localhost localhost.localdomain

```

5、 iRedMail 专家建议应该完全禁用 SELinux。通过编辑 `/etc/selinux/config` 并将 SELINUX 参数的值从 `permissive` 设置成 `disabled` 来禁用 SELinux。

```
SELINUX=disabled

```

重启机器并应用新的 SELinux 策略，或者运行 `setenforce` 带上参数 `0` 来强制 SELinux 立即禁用。

```
# reboot
或者
# setenforce 0

```

6、 接下来，安装下面这些接下来会用来系统管理的软件包：

```
# yum install bzip2 net-tools bash-completion wget

```

7、 要安装 iRedMail，首先打开下载页 <http://www.iredmail.org/download.html> 中并用下面的命令下载最新的版本。

```
# wget https://bitbucket.org/zhb/iredmail/downloads/iRedMail-0.9.6.tar.bz2

```

8、 下载完成后，使用下面命令解压压缩包并进入解压后的 iRedMail 目录。

```
# tar xjf iRedMail-0.9.6.tar.bz2
# cd iRedMail-0.9.6/
# ls

```

9、 使用下面的命令执行 iRedMail 的 shell 脚本来开始安装。接下来安装器会询问一系列的问题。

```
# bash iRedMail.sh

```

10、 在首个欢迎提示中，点击 `Yes` 来继续安装。

![iRedMail Setup Wizard](/data/attachment/album/201706/03/183640d75ib95iifxoa1o1.png)

*iRedMail 安装向导*

11、 接下来，选择邮件存储的位置。iRedMail 默认邮箱的存储位置在 `/var/vmail/` 中。

如果这个目录所在的分区有足够的空间来保存你所有域帐户的邮件，接着点击 Next 来继续。

否则，如果你已经配置一个更大的分区来用于邮件存储，那么就用不同的目录来更改默认位置。

![iRedMail Mail Storage Path](/data/attachment/album/201706/03/183642wwb2gwf6xxbwwslx.png)

*iRedMail 邮件存储路径*

12、 在下一步中，选择要与 iRedMail 进行交互的前端 Web 服务器。今后将完全禁用 iRedMail 管理面板，因此我们将使用前端 Web 服务器仅通过 Roundcube Web 面板访问帐户邮件。

如果你每小时没有数以千计的邮件帐户访问 webmail 界面，那么你应该使用 Apache Web 服务器来实现其灵活性和易于管理。

![iRedMail Preferred Web Server](/data/attachment/album/201706/03/183643ke00e6b2660t6ezb.png)

*iRedMail 首选的 Web 服务器*

13、 在此步骤中，由于 Samba4 域控制器的兼容性原因，请选择 OpenLDAP 后端数据库，并点击 Next 继续，但是一旦将 iRedMail 集成到 Samba 域控制器中，我们将不再使用该 OpenLDAP 数据库。

![iRedMail LDAP Backend](/data/attachment/album/201706/03/183645ksszekckd1dseksr.png)

*iRedMail LDAP 后端*

14、 接下来，如下图所示，为你的 Samba4 域名指定 LDAP 后缀，然后点击 Next 继续。

![iRedMail LDAP Suffix](/data/attachment/album/201706/03/183646ew6pr8rcyc6p8wzy.png)

*iRedMail LDAP 后缀*

15、 在接下来的提示中，只要输入你的域名，并点击 Next 继续。相应地替换 `tecmint.lan` 值。

![iRedMail Mail Domain](/data/attachment/album/201706/03/183647vfpjzrlz4zf6szll.png)

*iRedMail 邮件域*

16、 现在，为 `postmaster@yourdomain.tld` 管理员设置一个密码，并点击 Next 继续。

![iRedMail Mail Domain Administrator](/data/attachment/album/201706/03/183649szmi1vkbhoiokodb.png)

*iRedMail 邮件域管理员*

17、 接下来，从列表中选择要与邮件服务器集成的可选组件。我强烈建议你安装 Roundcube，以便为域帐户提供访问邮件的 Web 界面，尽管你也可以在不同的计算机上安装并配置 Roundcube，以便在高负载情况下释放邮件服务器资源。

对于受限访问互联网的本地域，特别是在我们使用域集成时，除了 Awstats 可以用于你进行邮件分析，其他组件不是非常有用。

![iRedMail Optional Components](/data/attachment/album/201706/03/183650tifcin7jl2228eze.png)

*iRedMail 可选组件*

18、 在下一步中输入 `Y` 来应用配置并开始安装。

![iRedMail Configuration Changes](/data/attachment/album/201706/03/183652j4mnsmphhlmz4446.png)

*iRedMail 配置更改*

19、 最后，所有的问题都输入 `Y`，接受 iRedMail 脚本自动配置你的防火墙以及 MySQL 配置文件。

![iRedMail System Configuration](/data/attachment/album/201706/03/183654x6ii4ihhtr1aim3b.png)

*iRedMail 系统配置*

20、 安装完成后，安装器会提供一些敏感信息。比如 iRedAdmin 凭证、web 面板的 URL 地址以及安装过程中使用的所有参数的文件位置。

![iRedMail Installation Summary](/data/attachment/album/201706/03/183656n6s6ys67z06s1y60.png)

*iRedMail 安装总结*

仔细阅读上面的信息，使用下面的命令重启机器来使所有的邮件服务启用。

```
# init 6

```

21、 系统重启后，使用 root 权限的帐户登录或以 root 身份登录，并使用下面的命令列出所有的网络套接字以及你邮件服务器监听的相关程序。

在套接字列表中，你会看到邮件服务器几乎覆盖邮件服务正常运行所需的所有服务：SMTP/S、POP3/S、IMAP/S 和防病毒以及垃圾邮件保护。

```
# netstat -tulpn

```

![iRedMail Network Sockets](/data/attachment/album/201706/03/183659zo90rxbx60b69fh9.png)

*iRedMail 网络套接字*

22、 为了查看 iRedMail 已修改的所有配置文件的位置、iRedMail 安装过程中用于数据库管理的凭据、邮件管理帐户以及其他帐户，那么就显示 `iRedMail.tips` 这个文件。

该文件位于你最初解压安装包的目录中。请注意，你应该移动并保护此文件，因为它包含有关邮件服务器的敏感信息。

```
# less iRedMail-0.9.6/iRedMail.tips

```

23、 上面提到的包含邮件服务器详细信息的文件也将自动发送到 postmaster 这个邮件服务器管理员帐户中。

通过在浏览器中输入机器的 IP 地址，你可以通过 HTTPS 协议安全地访问 webmail。接受 iRedMail 自签名证书在浏览器中生成的错误，并使用在安装中为 [postmaster@your\_domain.tld](mailto:postmaster@your_domain.tld) 帐户设置的密码登录。阅读并将此电子邮件存储到一个安全的邮箱。

```
https://192.168.1.254

```

![iRedMail Account Login](/data/attachment/album/201706/03/183705opcddh03xrrdfhky.png)

*iRedMail 登录帐户*

![iRedMail Web Mail](/data/attachment/album/201706/03/183708uqoqn6kwfst5pzcm.png)

*iRedMail Web 邮件*

就是这样了！到目前为止，你已经配置了一台完整的自己运行的邮件服务器了，但尚未与 Samba4 AD 域控制器服务集成。

在下一部分中，我们将看到如何修改 iRedMail 服务（postfix，dovecot 和 roundcube 配置文件），以便查询域帐户、发送、接收和读取邮件。

---

作者简介：

我是一个电脑上瘾的家伙，开源和基于 linux 系统软件的粉丝，在 Linux 发行版桌面、服务器和 bash 脚本方面拥有大约 4 年的经验。

---

via: <http://www.tecmint.com/install-iredmail-on-centos-7-for-samba4-ad-integration/>

作者：[Matei Cezar](http://www.tecmint.com/author/cezarmatei/) 译者：[geekpi](https://github.com/geekpi) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


极客漫画：chown 与 chmod

Summary:
chown ：Linux 中用来改变某个文件的属主的命令，如漫画中所示，将某个“资源”（门）的访问权限给予别人。

chmod ：Linux 中用来改变某个文件的访问模式的命令，如漫画中所示，chmod 777 会将“大门”敞开，谁都可以进出了。

这篇文章很有我当年的风范。

这形同于 Windows 中在 NTFS 系统设置 ACL 权限为: everyone:(oi)(ci)(f)

这个图很生动啊

chown：把钥匙交给谁<br />
chmod：直接把门打开、放人进去，钥匙所有者不变

![chown - chmod](/data/attachment/album/201706/03/231724btq9t8sxhty2p12f.png)

`chown` ：Linux 中用来改变某个文件的属主的命令，如漫画中所示，将某个“资源”（门）的访问权限给予别人。

`chmod` ：Linux 中用来改变某个文件的访问模式的命令，如漫画中所示，`chmod 777` 会将“大门”敞开，谁都可以进出了。

---

via: <http://turnoff.us/geek/chown-chmod/>

作者：[Daniel Stori](http://turnoff.us/about/) 译者&点评：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


安卓编年史（17）：安卓 3.0 蜂巢—平板和设计复兴

Android 3.0还有人用？

当时只知道Moto的Xoom支持这个系统，其他的还真没听说

来自北京的 Internet Explorer 11.0|Windows 10 用户

![](/data/attachment/album/201706/04/115507prb4u07pt7e7s7d8.jpg)

![](/data/attachment/album/201706/04/120432kbqawzdwvddxdw0u.jpg)

*安卓市场的新设计试水“卡片式”界面，这将成为谷歌的主要风格。 [Ron Amadeo 供图]*

安卓推向市场已经有两年半时间了，安卓市场放出了它的第四版设计。这个新设计十分重要，因为它已经很接近谷歌的“卡片式”界面了。通过在小方块中显示应用或其他内容，谷歌可以使它的设计在不同尺寸屏幕下无缝过渡而不受影响。内容可以像一个相册应用里的照片一样显示——给布局渲染填充一个内容块列表，加上屏幕包装，就完成了。更大的屏幕一次可以看到更多的内容块，小点的屏幕一次看到的内容就少。内容用了不一样的方式显示，谷歌还在右边新增了一个“分类”板块，顶部还有个巨大的热门应用滚动显示。

虽然设计上为更容易配置界面准备好准备好了，但功能上还没有。最初发布的市场版本锁定为横屏模式，而且还是蜂巢独占的。

![](/data/attachment/album/201706/04/120512j59q6v995pq9vqe8.jpg)

*应用详情页和“我的应用”界面。 [Ron Amadeo 供图]*

新的市场不仅出售应用，还加入了书籍和电影租借。谷歌从 2010 年开始出售图书；之前只通过网站出售。新的市场将谷歌所有的内容销售聚合到了一处，进一步向苹果 iTunes 所的主宰地位展开较量。虽然在“安卓市场”出售这些东西有点品牌混乱，因为大部分内容都不依赖于安卓才能使用。

![](/data/attachment/album/201706/04/120539vqdg8866d3qzq6i1.jpg)

*浏览器看起来非常像 Chrome，联系人使用了双面板界面。 [Ron Amadeo 供图]*

新浏览器界面顶部添加了标签页栏。尽管这个浏览器并不是 Chrome ，但它模仿了许多 Chrome 的设计和特性。除了这个探索性的顶部标签页界面，浏览器还加入了隐身标签，在浏览网页时不保存历史记录和自动补全记录。它还有个选项可以让你拥有一个 Chrome 风格的新标签页，页面上包含你最经常访问的网页略缩图。

新浏览器甚至还能和 Chrome 同步。在浏览器登录后，它会下载你的 Chrome 书签并且自动登录你的谷歌账户。收藏一个页面只需点击地址栏的星形标志即可，和谷歌地图一样，浏览器抛弃了缩放按钮，完全改用手势控制。

联系人应用最终从电话应用中移除，并且独立为一个应用。之前的联系人/拨号的混合式设计相对于人们使用现代智能手机的方式来说，过于以电话为中心了。联系人中存有电子邮件、IM、短信、地址、生日以及社交网络等信息，所以将它们捆绑在电话应用里的意义和将它们放进谷歌地图里差不多。抛开了电话通讯功能，联系人能够简化成没有标签页的联系人列表。蜂巢采用了双面板视图，在左侧显示完整的联系人列表，右侧是联系人详情。应用利用了 Fragments API，通过它应用可以在同一屏显示多个面板界面。

蜂巢版本的联系人应用是第一个拥有快速滚动功能的版本。当按住左侧滚动条的时候，你可以快速上下拖动，应用会显示列表当前位置的首字母预览。

![](/data/attachment/album/201706/04/120608thxhevsd2tmocmoi.jpg)

*新 Youtube 应用看起来像是来自黑客帝国。 [Ron Amadeo 供图]*

谢天谢地 Youtube 终于抛弃了自安卓 2.3 以来的谷歌给予这个视频服务的“独特”设计，新界面设计与系统更加一体化。主界面是一个水平滚动的曲面墙，上面显示着最热门或者（登录之后）个人关注的视频。虽然谷歌从来没有将这个设计带到手机上，但它可以被认为是一个易于重新配置的卡片界面。操作栏在这里是个可配置的工具栏。没有登录时，操作栏由一个搜索栏填满。当你登录后，搜索缩小为一个按钮，“首页”，“浏览”和“你的频道”标签将会显示出来。

![](/data/attachment/album/201706/04/120651zrd6zndufhw87awf.jpg)

*蜂巢用一个蓝色框架的电脑界面来驱动主屏。电影工作室完全采用橙色电子风格主题。 [Ron Amadeo 供图]*

蜂巢新增的应用“电影工作室”，这不是一个不言自明的应用，而且没有任何的解释或说明。就我们所知，你可以导入视频，剪切它们，添加文本和场景过渡。编辑视频——电脑上你可以做的最耗时、困难，以及处理器密集型任务之一 —— 在平板上完成感觉有点野心过大了，谷歌在之后的版本里将其完全移除了。电影工作室里我们最喜欢的部分是它完全的电子风格主题。虽然系统的其它部分使用蓝色高亮，在这里是橙色的。（电影工作室是个邪恶的程序！）

![](/data/attachment/album/201706/04/120739ffrxsc806zr21b04.jpg)

*小部件！ [Ron Amadeo 供图]*

蜂巢带来了新的部件框架，允许部件滚动，Gmail、Email 以及日历部件都升级了以支持改功能。Youtube 和书籍使用了新的部件，内容卡片可以自动滚动切换。在小部件上轻轻向上或向下滑动可以切换卡片。我们不确定你的书籍中哪些书会被显示出来，但如果你想要的话它就在那儿。尽管所有的这些小部件在 10 英寸屏幕上运行良好，谷歌从未为手机重新设计它们，这让它们在安卓最流行的规格上几乎毫无用处。所有的小部件有个大块的标识标题栏，而且通常占据大半屏幕只显示很少的内容。

![安卓3.1中可滚动的最近应用以及可自定义大小的小部件。](/data/attachment/album/201706/04/115732on98684jf8646fjf.jpg)

*安卓 3.1 中可滚动的最近应用以及可自定义大小的小部件。 [Ron Amadeo 供图]*

蜂巢后续的版本修复了 3.0 早期的一些问题。安卓 3.1 在蜂巢的第一个版本之后三个月放出，并带来了一些改进。小部件自定义大小是添加的最大特性之一。长按小部件之后，一个带有拖拽按钮的蓝色外框会显示出来，拖动按钮可以改变小部件尺寸。最近应用界面现在可以垂直滚动并且承载更多应用。这个版本唯一缺失的功能是滑动关闭应用。

在今天，一个 0.1 版本的升级是个主要更新，但是在蜂巢，那只是个小更新。除了一些界面调整，3.1 添加了对游戏手柄，键盘，鼠标以及其它 USB 和蓝牙输入设备的支持。它还提供了更多的开发者 API。

![安卓3.2的兼容性缩放和一个安卓平板上典型的展开视图应用。](/data/attachment/album/201706/04/115733ki8aa0vkazuak11k.jpg)

*安卓 3.2 的兼容性缩放和一个安卓平板上典型的展开视图应用。 [Ron Amadeo 供图]*

安卓 3.2 在 3.1 发布后两个月放出，添加了七到八英寸的小尺寸平板支持。3.2 终于启用了 SD 卡支持，Xoom 在生命最初的五个月就像是初生儿的柔弱的肢体一样。

蜂巢匆匆问世是为了成为一个生态系统建设者。如果应用没有平板版本，没人会想要一个安卓平板的，所以谷歌知道需要尽快将东西送到开发者手中。在这个安卓平板生态的早期阶段，应用还没有到齐。这是拥有 Xoom 的人们所面临的最大的问题。

3.2 添加了“兼容缩放”，给了用户一个新选项，可以将应用拉伸适应屏幕（如右侧图片显示的那样）或缩放成正常的应用布局来适应屏幕。这些选项都不是很理想，由于没有应用生态来支持平板，蜂巢设备销售状况惨淡。但谷歌的平板决策最终还是会得到回报。今天，安卓平板已经[取代 iOS 占据了最大的市场份额](http://techcrunch.com/2014/03/03/gartner-195m-tablets-sold-in-2013-android-grabs-top-spot-from-ipad-with-62-share/)。

### Google Music Beta —— 取代内容商店的云存储

![](/data/attachment/album/201706/04/122029qa7t77af1azt5myf.jpg)

*姜饼上的 Google Music Beta。 [Ron Amadeo 供图]*

尽管蜂巢改进了 Google Music 的界面，但是音乐应用的设计并没有从蜂巢直接进化到冰淇淋三明治。2011 年 5 月，谷歌发布了“[Google Music Beta](http://arstechnica.com/gadgets/2011/05/hands-on-grooving-on-the-go-with-impressive-google-music-beta/)”，和新的 Google Music 应用一同到来的在线音乐存储。

新 Google Music 为安卓 2.2 及以上版本设计，借鉴了 Cooliris 相册的设计语言，但也有改变之处，背景使用了模糊处理的图片。几乎所有东西都是透明的：弹出菜单，顶部标签页，还有底部的正在播放栏。可以下载单独的歌曲或整个播放列表到设备上离线播放，这让 Google Music 成为一个让音乐同步到你所有设备的好途径。除了移动应用外，Google Music 还有一个 Web 应用，让它可以在任何一台桌面电脑上使用。

谷歌和唱片公司关于内容的合约还没有谈妥，音乐商店还没准备好，所以它的权宜之计是允许用户存储音乐到线上并下载到设备上。如今谷歌除了音乐存储服务外，还有单曲购买和订阅模式。

---

![](/data/attachment/album/201706/04/115734xag6aagzczem6et8.jpg)

[Ron Amadeo](http://arstechnica.com/author/ronamadeo) / Ron 是 Ars Technica 的评论编缉，专注于安卓系统和谷歌产品。他总是在追寻新鲜事物，还喜欢拆解事物看看它们到底是怎么运作的。[@RonAmadeo](https://twitter.com/RonAmadeo)

---

via: <http://arstechnica.com/gadgets/2016/10/building-android-a-40000-word-history-of-googles-mobile-os/18/>

译者：[alim0x](https://github.com/alim0x) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创翻译，[Linux中国](http://linux.cn/) 荣誉推出


安卓编年史（18）：Android 4.0 冰淇淋三明治—摩登时代

![](/data/attachment/album/201706/04/122939rol970wq8nohyon2.jpg)

### Android 4.0 冰淇淋三明治 —— 摩登时代

![](/data/attachment/album/201706/04/123210auswiq704wu08iiu.jpg)

*三星 Galaxy Nexus，安卓4.0的首发设备。*

安卓 4.0，冰淇淋三明治，在 2011 年 10 月发布，系统发布回到正轨，带来定期发布的手机和平板，并且安卓再次开源。这是自姜饼以来手机设备的第一个更新，意味着最主要的安卓用户群体近乎一年没有见到更新了。4.0 随处可见缩小版的蜂巢设计，还将虚拟按键，<ruby> 操作栏 <rp>  （ </rp> <rt>  Action Bar </rt> <rp>  ） </rp></ruby>，全新的设计语言带到了手机上。

冰淇淋三明治在三星 Galaxy Nexus 上首次亮相，也是最早带有 720p 显示屏的安卓手机之一。随着分辨率的提高，Galaxy Nexus 使用了更大的 4.65 英寸显示屏——几乎比最初的 Nexus One 大了一整英寸。这被许多批评者认为“太大了”，但如今的安卓设备甚至更大。（5 英寸当今是“正常”的。）冰淇淋三明治比姜饼的性能要求更高，Galaxy Nexus 配备了一颗双核，1.2Ghz 德州仪器 OMAP 处理器和 1GB 的内存。

在美国，Galaxy Nexus 在 Verizon 首发并且支持 LTE。不像之前的 Nexus 设备，最流行的型号——Verizon 版——是在运营商的控制之下，谷歌的软件和更新在手机得到更新之前要经过 Verizon 的核准。这导致了更新的延迟以及 Verizon 不喜欢的应用被移除，即便是 Google Wallet 也不例外。

多亏了冰淇淋三明治的软件改进，谷歌终于达成了移除手机上按钮的目标。有了虚拟导航键，实体电容按钮就可以移除了，最终 Galaxy Nexus 仅有电源和音量是实体按键。

![](/data/attachment/album/201706/04/123242clm8yyddl8lmcr8r.jpg)

*安卓 4.0 将很多蜂巢的设计缩小了。 [Ron Amadeo 供图]*

电子质感的审美在蜂巢中显得有点多。于是在冰淇淋三明治中，谷歌开始减少科幻风的设计。科幻风的时钟字体从半透明折叠风格转变成纤细，优雅，看起来更加正常的字体。解锁环的水面波纹效果被去除了，蜂巢中的外星风格时钟小部件也被极简设计所取代。系统按钮也经过了重新设计，原先的蓝色轮廓，偶尔的厚边框变成了细的，设置带有白色轮廓。默认壁纸从蜂巢的蓝色太空船内部变成条纹状，破碎的彩虹，给默认布局增添了不少迟来的色彩。

蜂巢的系统栏在手机上一分为二。在顶上是传统的状态栏，底部是新的系统栏，放着三个系统按钮：后退、主屏幕、最近应用。一个固定的搜索栏放置在了主屏幕顶部。该栏以和底栏一样的方式固定在屏幕上，所以在五个主屏上，它总共占据了 20 个图标大小的位置。在蜂巢的锁屏上，内部的小圆圈可以向大圆圈外的任意位置滑动来解锁设备。在冰淇淋三明治，你得把小圆圈移动到解锁图标上。这个新准确度要求允许谷歌向锁屏添加新的选项：一个相机快捷方式。将小圆圈拖向相机图标会直接启动相机，跳过了主屏幕。

![](/data/attachment/album/201706/04/123314ynmoqfae006e2ho9.jpg)

*一个手机系统意味着更多的应用，通知面板重新回到了全屏界面。 [Ron Amadeo 供图]*

应用抽屉还是标签页式的，但是蜂巢中的“我的应用”标签被“部件”标签页替代，这是个简单的 2×3 部件略缩图视图。像蜂巢里的那样，这个应用抽屉是分页的，需要水平滑动换页。（如今安卓仍在使用这个应用抽屉设计。）应用抽屉里新增的是 Google+ 应用，后来独立存在。还有一个“Messenger”快捷方式，是 Google+ 的私密信息服务。（不要混淆 “Messenger” 和已有的 “Messaging” 短信应用。）

因为我们现在回到了手机上，所以短信，新闻和天气，电话，以及语音拨号都回来了，以及 Cordy，一个平板的游戏，被移除了。尽管不是 Nexus 设备，我们的截图还是来自 Verizon 版的设备，可以从图上看到有像 “My Verizon Mobile” 和 “VZ Backup Assistant” 这样没用的应用。为了和冰淇淋三明治的去电子风格主题一致，日历和相机图标现在看起来更像是来自地球的东西而不是来自外星球。时钟，下载，电话，以及安卓市场同样得到了新图标，“联系人”获得了新图标，还有新名字 “People”。

通知面板进行了大改造，特别是和[之前姜饼中的设计](http://cdn.arstechnica.net/wp-content/uploads/2014/02/32.png)相比而言。面板头部有个日期，一个设置的快捷方式，以及“清除所有”按钮。虽然蜂巢的第一个版本就允许用户通过通知右边的“X”消除单个通知，但是冰淇淋三明治的实现更加优雅：只要从左向右滑动通知即可。蜂巢有着蓝色高亮，但是蓝色色调到处都是。冰淇淋三明治几乎把所有地方的蓝色统一成一个（如果你想知道确定的值，hex 码是 `#33B5E5`）。通知面板的背景是透明的，底部的“把手”变为一个简单的小蓝圈，带着不透明的黑色背景。

![](/data/attachment/album/201706/04/123349m8cu78400un4ny89.jpg)

*安卓市场的主页背景变成了黑色。 [Ron Amadeo 供图]*

市场获得了又一个新设计。它终于再次支持纵向模式，并且添加了音乐到商店中，你可以从中购买音乐。新的市场拓展了从蜂巢中引入的卡片概念，它还是第一个同时使用在手机和平板上的版本。主页上的卡片通常不是链接到应用的，而是指向特别的促销页面，像是“编辑精选”或季度促销。

---

![](/data/attachment/album/201706/04/123445b51ttftbki4etttb.jpg)

[Ron Amadeo](http://arstechnica.com/author/ronamadeo) / Ron是Ars Technica的评论编缉，专注于安卓系统和谷歌产品。他总是在追寻新鲜事物，还喜欢拆解事物看看它们到底是怎么运作的。[@RonAmadeo](https://twitter.com/RonAmadeo)

---

via: <http://arstechnica.com/gadgets/2016/10/building-android-a-40000-word-history-of-googles-mobile-os/19/>

译者：[alim0x](https://github.com/alim0x) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创翻译，[Linux中国](http://linux.cn/) 荣誉推出


怎么使用 Diff 和 Meld 工具发现两个目录间的不同之处

Summary: 本篇文章中，我们将会描述在 Linux 下怎样找到两个目录之间的不同。

diff是很有价值的开源工具，很遗憾在非Linux平台下它不是自由的。

是这样的？不允许用在 Windows 上之类的？我还真没注意到它的许可证~

你运行一下你的mac上的diff看看，它是不自由的。这不是许可证的问题，这是自由与否的问题。

get 不到你的点。

cuthead@cuthead-To-be-filled-by-O-E-M:~$ echo abc >1.txt

cuthead@cuthead-To-be-filled-by-O-E-M:~$ echo bbc >2.txt

cuthead@cuthead-To-be-filled-by-O-E-M:~$ diff 1.txt 2.txt

1c1

< abc

---

> bbc

cuthead@cuthead-To-be-filled-by-O-E-M:~$

仅在Linux下工作，在Mac下不工作，我其实也有Mac。但我比较喜欢Linux。

我给你说，diff有图形化工具diffuse

我不知道你什么情况，但是我原样复制你的命令，在我的 mac 下执行，结果是和 linux 下一样的。bash 和 zsh 都工作。

cmp -l 1.txt 2.txt | gawk '{printf &quot;%08X %02X %02X\n&quot;, $1, strtonum(0$2), strtonum(0$3)}' 我用windows 10年，mac 10年，我可以很确定的说mac没有diff

没有 diff 有什么问题么，无论是 ports ，还是 brew，或者编译，都可以有啊。

本篇文章中，我们将会描述在 Linux 下怎样找到两个目录之间的不同。

![](/data/attachment/album/201706/04/175016zl5kamnkfda1bnk4.jpg)

在之前的一篇文章里，我们回顾了 [Linux 下 9 个最好的文件比较工具](http://www.tecmint.com/best-linux-file-diff-tools-comparison/)，本篇文章中，我们将会描述在 Linux 下怎样找到两个目录之间的不同。

一般情况下，要在 Linux 下比较两个文件，我们会使用 `diff` （一个简单的源自 Unix 的命令行工具）来显示两个计算机文件的不同；它一行一行的去比较文件，而且很方便使用，在几乎全部的 Linux 发行版都预装了。

问题是在 Linux 下我们怎么才能比较两个目录？现在，我们想知道两个目录中哪些文件/子目录是共有的，哪些只存在一个于目录。

运行 diff 常规的语法如下：

```
$ diff [OPTION]… FILES
$ diff options dir1 dir2

```

默认情况下，输出是按文件/子文件夹的文件名的字母排序的，如下面截图所示，在命令中， `-q` 开关是告诉 `diif` 只有在文件有差异时报告。

```
$ diff -q directory-1/ directory-2/

```

![Difference Between Two Directories](/data/attachment/album/201706/04/175024uqejdsgnzfz8jdv2.png)

*两个文件夹之间的差异*

再次运行 `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+]

```

一旦你安装了它之后，在 **Ubuntu Dash** 或者 **Linux Mint** 菜单搜索 “**meld**” ，或者 Fedora 或 CentOS 桌面的 Activities Overview，然后启动它。

你可以看到如下的 Meld 界面，可以选择文件或者文件夹来比较，此外还有版本控制视图。点击目录比较并移动到下个界面。 ![Meld Comparison Tool](/data/attachment/album/201706/04/175026cu1zqgrdgqj7q7gz.png)

*Meld 比较工具*

选择你想要比较的文件夹，注意你可以勾选 “**3-way Comparison**” 选项，添加第三个文件夹。

![Select Comparison Directories](/data/attachment/album/201706/04/175028nk2emz82g30kk2ky.png)

*选择比较的文件夹*

选择好要比较的文件夹后，点击 “Compare”。

![Listing Difference Between +](/data/attachment/album/201706/04/175029ai2ug6i2wiaviiuz.png)

*文件夹不同列表*

在这篇文章中，我们描述了怎么在 Linux 下找到两个文件夹的不同。如果你知道其他的命令或者图形界面工具，不要忘记在下方评论分享你们的想法。

---

作者简介：

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](http://www.tecmint.com/author/aaronkili/) 译者：[hkurj](https://github.com/hkurj) 校对：[jasminepeng](https://github.com/jasminepeng)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


安卓编年史（19）：Android 4.0 冰淇淋三明治—摩登时代

![](/data/attachment/album/201706/04/203730ma7gphtq5sa78gp8.jpg)

![](/data/attachment/album/201706/04/203823wtl2q7dy6l7273g3.jpg)

*和之前完全不同的市场设计。以上是分类，特色，热门应用以及应用详情页面。 [Ron Amadeo 供图]*

这些截图给了我们冰淇淋三明治中新版操作栏的第一印象。几乎所有的应用顶部都有一条栏，带有应用图标，当前界面标题，一些功能按钮，右边还有一个菜单按钮。这个右对齐的菜单按钮被称为“更多操作”，因为里面存放着无法放置到主操作栏的项目。不过更多操作菜单并不是固定不变的，它给了操作栏节省了更多的屏幕空间——比如在横屏模式或在平板上时，更多操作菜单的项目会像通常的按钮一样显示在操作栏上。

冰淇凌三明治中新增了“滑动标签页”设计，替换掉了谷歌之前推行的 2×3 方阵导航屏幕。一个标签页栏放置在了操作栏下方，位于中间的标签显示的是当前页面，左右侧的两个标签显示的是对应的当前页面的左右侧页面。向左右滑动可以切换标签页，或者你可以点击指定页面的标签跳转过去。

应用详情页面有个很赞的设计，在应用截图后，会根据你关于那个应用的历史动态地重新布局页面。如果你从来没有安装过该应用，应用描述会优先显示。如果你曾安装过这个应用，第一部分将会是评价栏，它会邀请你评价该应用或者提醒你上次你安装该应用时的评价是什么。之前使用过的应用页面第二部分是“新特性”，因为一个老用户最关心的应该是应用有什么变化。

![](/data/attachment/album/201706/04/203945fbt41o84xgnizozh.jpg)

*最近应用和浏览器和蜂巢中的类似，但是是小号的。 [Ron Amadeo 供图]*

最近应用的电子风格外观被移除了。略缩图周围的蓝色的轮廓线被去除了，同时去除的还有背景怪异的、不均匀的蓝色光晕。它现在看起来是个中立型的界面，在任何时候看起来都很舒适。

浏览器尽了最大的努力把标签页体验带到手机上来。多标签浏览受到了关注，操作栏上引入的一个标签页按钮会打开一个类似最近应用的界面，显示你打开的标签页，而不是浪费宝贵的屏幕空间引入一个标签条。从功能上来说，这个和之前的浏览器中的“窗口”视图没什么差别。浏览器最佳的改进是菜单中的“请求桌面版站点”选项，这让你可以从默认的移动站点视图切换到正常站点。浏览器展示了谷歌的操作栏设计的灵活性，尽管这里没有左上角的应用图标，功能上来说和其他的顶栏设计相似。

![](/data/attachment/album/201706/04/204018rah7zr2vgjg7gro2.jpg)

*Gmail 和 Google Talk —— 它们和蜂巢中的相似，但是更小！ [Ron Amadeo 供图]*

Gmail 和 Google Talk 看起来都像是之前蜂巢中的设计的缩小版，但是有些小调整让它们在小屏幕上表现更佳。Gmail 以双操作栏为特色——一个在屏幕顶部，一个在底部。顶部操作栏显示当前文件夹、账户，以及未读消息数目，点击顶栏可以打开一个导航菜单。底部操作栏有你期望出现在更多操作中的选项。使用双操作栏布局是为了在界面显示更多的按钮，但是在横屏模式下纵向空间有限，双操作栏就合并成一个顶部操作栏。

在邮件视图下，往下滚动屏幕时蓝色栏有“粘性”。它会固定在屏幕顶部，所以你一直可以看到该邮件是谁写的，回复它，或者给它加星标。一旦处于邮件消息界面，底部细长的、深灰色栏会显示你当前在收件箱（或你所在的某个列表）的位置，并且你可以向左或向右滑动来切换到其他邮件。

Google Talk 允许你像在 Gmail 中那样左右滑动来切换聊天窗口，但是这里显示栏是在顶部。

![](/data/attachment/album/201706/04/204049rrz4z1ma2a42bb07.jpg)

*新的拨号和来电界面，都是姜饼以来我们还没见过的。 [Ron Amadeo 供图]*

因为蜂巢只给平板使用，所以一些界面设计直接超前于姜饼。冰淇淋三明治的新拨号界面就是如此，黑色和蓝色相间，并且使用了可滑动切换的小标签。尽管冰淇淋三明治终于做对了，将电话主体和联系人独立开来，但电话应用还是有它自己的联系人标签。现在有两个地方可以看到你的联系人列表——一个有着暗色主题，另一个有着亮色主题。由于实体搜索按钮不再是硬性要求，底部的按钮栏的语音信息快捷方式被替换为了搜索图标。

谷歌几乎就是把来电界面做成了锁屏界面的镜像，这意味着冰淇淋三明治有着一个环状解锁设计。除了通常的接受和挂断选项，圆环的顶部还添加了一个按钮，让你可以挂断来电并给对方发送一条预先定义好的信息。向上滑动并选择一条信息如“现在无法接听，一会回电”，相比于一直响个不停的手机而言这样做的信息交流更加丰富。

![](/data/attachment/album/201706/04/204128wpefpwpv9chetecv.jpg)

*蜂巢没有文件夹和信息应用，所以这里是冰淇淋三明治和姜饼的对比。 [Ron Amadeo 供图]*

现在创建文件夹更加方便了。在姜饼中，你得长按屏幕，选择“文件夹”选项，再点击“新文件夹”。在冰淇淋三明治中，你只要将一个图标拖拽到另一个图标上面，就会自动创建一个文件夹，并包含这两个图标。这简直不能更简单了，比寻找隐藏的长按命令容易多了。

设计上也有很大的改进。姜饼使用了一个通用的米黄色文件夹图标，但冰淇淋三明治直接显示出了文件夹中的头三个应用，把它们的图标叠在一起，在外侧画一个圆圈，并将其设置为文件夹图标。打开文件夹容器将自动调整大小以适应文件夹中的应用图标数目，而不是显示一个全屏的，大部分都是空的对话框。这看起来好得多得多。

![](/data/attachment/album/201706/04/204159tr3kgrkccz816qc8.jpg)

*Youtube 转换到一个更加现代的白色主题，使用了列表视图替换疯狂的 3D 滚动视图。 [Ron Amadeo 供图]*

Youtube 经过了完全的重新设计，看起来没那么像是来自黑客帝国的产物，更像是，嗯，Youtube。它现在就是一个简单的垂直滚动的白色视频列表，就像网站的那样。在你手机上制作视频受到了重视，操作栏的第一个按钮专用于拍摄视频。奇怪的是，不同的界面左上角使用了不同的 Youtube 标志，在水平的 Youtube 标志和方形标志之间切换。

Youtube 几乎在所有地方都使用了滑动标签页。它们被放置在主页面以在浏览和账户间切换，放置在视频页面以在评论，介绍和相关视频之间切换。4.0 版本的应用显示出 Google+ Youtube 集成的第一个信号，通常的评分按钮旁边放置了 “+1” 图标。最终 Google+ 会完全占据 Youtube，将评论和作者页面变成 Google+ 活动。

![](/data/attachment/album/201706/04/204231d7mnnqmt7j5q55ii.jpg)

*冰淇淋三明治试着让事情对所有人都更加简单。这里是数据使用量追踪，打开许多数据的新开发者选项，以及使用向导。 [Ron Amadeo 供图]*

数据使用量允许用户更轻松地追踪和控制他们的数据使用。主页面显示一个月度使用量图表，用户可以设置数据使用警告值或者硬性使用限制以避免超量使用产生费用。所有的这些只需简单地拖动橙色和红色水平限制线在图表上的位置即可。纵向的白色把手允许用户选择图表上的一段指定时间段。在页面底部，选定时间段内的数据使用量又细分到每个应用，所以用户可以选择一个数据使用高峰并轻松地查看哪个应用在消耗大量流量。当流量紧张的时候，更多操作按钮中有个限制所有后台流量的选项。设置之后只用在前台运行的程序有权连接互联网。

开发者选项通常只有一点点设置选项，但是在冰淇淋三明治中，这部分有非常多选项。谷歌添加了所有类型的屏幕诊断显示浮层来帮助开发者理解他们的应用中发生了什么。你可以看到 CPU 使用率，触摸点位置，还有视图界面更新。还有些选项可以更改系统功能，比如控制动画速度，后台处理，以及 GPU 渲染。

安卓和 iOS 之间最大的区别之一就是应用抽屉界面。在冰淇淋三明治对更加用户友好的追求下，设备第一次初始化启动会启动一个小教程，向用户展示应用抽屉的位置以及如何将应用图标从应用抽屉拖拽到主屏幕。随着实体菜单按键的移除和像这样的改变，安卓 4.0 做了很大的努力变得对新智能手机用户和转换过来的用户更有吸引力。

![](/data/attachment/album/201706/04/204407ak2dl2j11z23fkj8.jpg)

*“触摸分享”NFC 支持，Google Earth，以及应用信息，让你可以禁用垃圾软件。*

冰淇淋三明治内置对 [NFC](http://arstechnica.com/gadgets/2011/02/near-field-communications-a-technology-primer/) 的完整支持。尽管之前的设备，比如 Nexus S 也拥有 NFC，得到的支持是有限的并且系统并不能利用芯片做太多事情。4.0 添加了一个“Android Beam”功能，两台拥有 NFC 的安卓 4.0 设备可以借此在设备间来回传输数据。NFC 会传输关于此时屏幕显示的数据，因此在手机显示一个网页的时候使用该功能会将该页面传送给另一部手机。你还可以发送联系人信息、方向导航，以及 Youtube 链接。当两台手机放在一起时，屏幕显示会缩小，点击缩小的界面会发送相关信息。

在安卓中，用户不允许删除系统应用，以保证系统完整性。运营商和 OEM 利用该特性并开始将垃圾软件放入系统分区，经常有一些没用的应用存在系统中。安卓 4.0 允许用户禁用任何不能被卸载的应用，意味着该应用还存在于系统中但是不显示在应用抽屉里并且不能运行。如果用户愿意深究设置项，这给了他们一个简单的途径来拿回手机的控制权。

安卓 4.0 可以看做是现代安卓时代的开始。大部分这时发布的谷歌应用只能在安卓 4.0 及以上版本运行。4.0 还有许多谷歌想要好好利用的新 API——至少最初想要——对 4.0 以下的版本的支持就有限了。在冰淇淋三明治和蜂巢之后，谷歌真的开始认真对待软件设计。在 2012 年 1 月，谷歌[最终发布了](http://arstechnica.com/business/2012/01/google-launches-style-guide-for-android-developers/) *Android Design*，一个教安卓开发者如何创建符合安卓外观和感觉的应用的设计指南站点。这是 iOS 在有第三方应用支持开始就在做的事情，苹果还严肃地对待应用的设计，不符合指南的应用都被 App Store 拒之门外。安卓三年以来谷歌没有给出任何公共设计规范文档的事实，足以说明事情有多糟糕。但随着在 Duarte 掌控下的安卓设计革命，谷歌终于发布了基本设计需求。

### Google Play 和直接面向消费者出售设备的回归

![](/data/attachment/album/201706/08/212202xbejbj6mxhjbjxzb.png)

2012 年 3 月 6 日，谷歌将旗下提供的所有内容统一到 “Google Play”。安卓市场变为了 Google Play 商店，Google Books 变为 Google Play Books，Google Music 变为 Google Play Music，还有 Android Market Movies 变为 Google Play Movies & TV。尽管应用界面的变化不是很大，这四个内容应用都获得了新的名称和图标。在 Play 商店购买的内容会下载到对应的应用中，Play 商店和 Play 内容应用一道给用户提供了易管理的内容体验。

Google Play 更新是谷歌第一个大的更新周期外更新。四个自带应用都没有通过系统更新获得升级，它们都是直接通过安卓市场/ Play 商店更新的。对单独的应用启用周期外更新是谷歌的重大关注点之一，而能够实现这样的更新，是自姜饼时代开始的工程努力的顶峰。谷歌一直致力于对应用从系统“解耦”，从而让它们能够通过安卓市场/ Play 商店进行分发。

尽管一两个应用（主要是地图和 Gmail）之前就在安卓市场上，从这里开始你会看到许多更重大的更新，而其和系统发布无关。系统更新需要 OEM 厂商和运营商的合作，所以很难保证推送到每个用户手上。而 Play 商店更新则完全掌握在谷歌手上，给了谷歌一条直接到达用户设备的途径。因为 Google Play 的发布，安卓市场对自身升级到了 Google Play Store，在那之后，图书，音乐以及电影应用都下发了 Google Play 式的更新。

Google Play 系列应用的设计仍然不尽相同。每个应用的外观和功能各有差异，但暂且来说，一个统一的品牌标识是个好的开始。从品牌标识中去除“安卓”字样是很有必要的，因为很多服务是在浏览器中提供的，不需要安卓设备也能使用。

2012 年 4 月，谷歌[再次开始通过 Play 商店销售设备](http://arstechnica.com/gadgets/2011/02/near-field-communications-a-technology-primer/)，恢复在 Nexus One 发布时尝试的直接面向消费者销售的方式。尽管距 Nexus One 销售结束仅有两年，但网上购物现在更加寻常，在接触到物品之前就购买它并不像在 2010 年时听起来那么疯狂。

谷歌也看到了价格敏感的用户在面对 Nexus One 的 530 美元的价格时的反应。第一部销售的设备是无锁的，GSM 版本的 Galaxy Nexus，价格 399 美元。在那之后，价格变得更低。350 美元成为了最近两台 Nexus 设备的入门价，7 英寸 Nexus 平板的价格更是只有 200 美元到 220 美元。

今天，Play 商店销售八款不同的安卓设备，四款 Chromebook，一款自动调温器，以及许多配件，设备商店已经是谷歌新产品发布的实际地点了。新产品发布总是如此受欢迎，站点往往无法承载如此大的流量，新 Nexus 手机也在几小时内售空。

---

![](/data/attachment/album/201706/04/204537fvv3r9f1zovwq1he.jpg)

[Ron Amadeo](http://arstechnica.com/author/ronamadeo) / Ron是Ars Technica的评论编缉，专注于安卓系统和谷歌产品。他总是在追寻新鲜事物，还喜欢拆解事物看看它们到底是怎么运作的。[@RonAmadeo](https://twitter.com/RonAmadeo)

---

via: <http://arstechnica.com/gadgets/2016/10/building-android-a-40000-word-history-of-googles-mobile-os/20/>

译者：[alim0x](https://github.com/alim0x) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创翻译，[Linux中国](http://linux.cn/) 荣誉推出


MyCLI ：一个支持自动补全和语法高亮的 MySQL/MariaDB 客户端

Emacs 有没有类似插件

centos上pip安装命令不对，应该是yum -y install python-pip

MyCLI 是一个易于使用的命令行客户端，可用于受欢迎的数据库管理系统 MySQL、MariaDB 和 Percona，支持自动补全和语法高亮。它是使用 `prompt_toolkit` 库写的，需要 Python 2.7、3.3、3.4、3.5 和 3.6 的支持。MyCLI 还支持通过 SSL 安全连接到 MySQL 服务器。

![](/data/attachment/album/201706/05/090536ynnzhoqhaoa8doo2.jpg)

#### MyCLI 的特性

* 当你第一次使用它的时候，将会自动创建一个文件 `~/.myclirc`。
* 当输入 SQL 的关键词和数据库中的表、视图和列时，支持自动补全。
* 默认情况下也支持智能补全，能根据上下文的相关性提供补全建议。

比如：

```
SELECT * FROM <Tab> - 这将显示出数据库中的表名。
SELECT * FROM users WHERE <Tab> - 这将简单的显示出列名称。

```

* 通过使用 `Pygents` 支持语法高亮
* 支持 SSL 连接
* 提供多行查询支持
* 它可以将每一个查询和输出记录到一个文件中（默认情况下禁用）。
* 允许保存收藏一个查询（使用 `\fs 别名` 保存一个查询，并可使用 `\f 别名` 运行它）。
* 支持 SQL 语句执行和表查询计时
* 以更吸引人的方式打印表格数据

### 如何在 Linux 上为 MySQL 和 MariaDB 安装 MyCLI

在 Debian/Ubuntu 发行版上，你可以很容易的像下面这样使用 `apt` 命令 来安装 MyCLI 包：

```
$ sudo apt-get update
$ sudo apt-get install mycli

```

同样，在 Fedora 22+ 上也有 MyCLI 的可用包，你可以像下面这样使用 `dnf` 命令 来安装它：

```
$ sudo dnf install mycli

```

对于其他 Linux 发行版，比如 RHEL/CentOS，你需要使用 Python 的 `pip` 工具来安装 MyCLI。首先，使用下面的命令来安装 pip：

```
$ sudo yum install pip

```

安装好 `pip` 以后，你可以像下面这样安装 MyCLI：

```
$ sudo pip install mycli

```

### 在 Linux 中如何使用 MyCLI 连接 MySQL 和 MariaDB

安装好 MyCLI 以后，你可以像下面这样使用它：

```
$ mycli -u root -h localhost

```

#### 自动补全

对于关键词和 SQL 函数可以进行简单的自动补全：

![MySQL Auto Completion](/data/attachment/album/201706/05/090544uony82y705mnyygy.png)

*MySQL 自动补全*

#### 智能补全

当输入 `FROM` 关键词以后会进行表名称的补全：

![MySQL Smart Completion](/data/attachment/album/201706/05/090544bjqkv56hpdqazy5v.png)

*MySQL 智能补全*

#### 别名支持

当表的名称设置别名以后，也支持列名称的补全：

![MySQL Alias Support](/data/attachment/album/201706/05/090545vyltwalw4acd2aa7.png)

*MySQL 别名支持*

#### 语法高亮

支持 MySQL 语法高亮：

![MySQL Syntax Highlighting](/data/attachment/album/201706/05/090546x8rddx3fgasx4xl4.png)

*MySQL 语法高亮*

#### 格式化 SQL 的输出

MySQL 的输出会通过 [`less` 命令](https://www.tecmint.com/linux-more-command-and-less-command-examples/) 进行格式化输出：

![MySQL Formatted Output](/data/attachment/album/201706/05/090546ysrcf71syd64mzbf.png)

*MySQL 格式化输出*

要登录 MySQL 并同时选择数据库，你可以使用和下面类似的命令：

```
$ mycli local_database
$ mycli -h localhost -u root app_db
$ mycli mysql://amjith@localhost:3306/django_poll

```

更多使用选项，请输入：

```
$ mycli --help

```

MyCLI 主页： <http://mycli.net/index>

记得阅读一些关于 MySQL 管理的有用文章：

1. [在 Linux 中用于数据库管理的 20 个 MySQL（Mysqladmin）命令](https://www.tecmint.com/mysqladmin-commands-for-database-administration-in-linux/)
2. [如何在 Linux 中更改默认的 MySQL/MariaDB 数据目录](https://www.tecmint.com/change-default-mysql-mariadb-data-directory-in-linux/)
3. [在 Linux 中监测 MySQL 性能的 4 个实用命令行工具](https://www.tecmint.com/mysql-performance-monitoring/)
4. [如何在 Linux 中更改 MySQL 或 MariaDB 的 Root 密码](/article-8328-1.html)
5. [MySQL 备份和恢复数据库管理命令](https://www.tecmint.com/mysql-backup-and-restore-commands-for-database-administration/)

MyCLI 作者写的两篇如何创建具有可发现性的交互式命令行客户端的文章：

1. [4 个拥有绝佳命令行界面的终端程序](/article-8526-1.html)
2. [4 个用于构建优秀的命令行用户界面的 Python 库](/article-8561-1.html)

这就是本文的全部内容了。在这篇指南中，我们展示了如何通过一些简单的命令在 Linux 中安装和使用 MyCLI。记得通过下面的反馈表向我们分享你关于这篇文章的想法。

---

作者简介：

Aaron Kili是一名 Linux 和 F.O.S.S 的爱好者，未来的 Linux 系统管理员、网站开发人员，目前是 TecMint 的内容创作者，他喜欢用电脑工作，并乐于分享知识。

---

via: <https://www.tecmint.com/mycli-mysql-client-with-auto-completion-syntax-highlighting/>

作者：[Aaron Kili](https://www.tecmint.com/author/aaronkili/) 译者：[ucasFL](https://github.com/ucasFL) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


ssh_scan：远程验证你 SSH 服务的配置和策略

Summary: ssh_scan 是一个面向 Linux 和 UNIX 服务器的易用的 SSH 服务参数配置和策略的扫描器程序，其思路来自Mozilla OpenSSH 安全指南，这个指南为 SSH 服务参数配置提供了一个可靠的安全策略基线的建议，如加密算法（Ciphers），报文认证信息码算法（MAC），密钥交换算法（KexAlgos）和其它。

前面讲的在安装有问题

系统：centos6.4

1.安装的是rubygems,少写了个s

2.yum rubygem会提示ruby版本要在2.0以上，

所以我使用的是源码安装的ruby 和rubygems，默认安装目录是/usr/local/bin    做个软链接到/usr/bin下就可以了

谢谢，已更正 :D

`ssh_scan` 是一个面向 Linux 和 UNIX 服务器的易用的 SSH 服务参数配置和策略的扫描器程序，其思路来自[Mozilla OpenSSH 安全指南](https://wiki.mozilla.org/Security/Guidelines/OpenSSH)，这个指南为 SSH 服务参数配置提供了一个可靠的安全策略基线的建议，如加密算法（Ciphers），报文认证信息码算法（MAC），密钥交换算法（KexAlgos）和其它。

![](/data/attachment/album/201706/05/094154g4ah7ilcejlls4ii.jpg)

`ssh_scan` 有如下好处：

* 它的依赖是最小化的，`ssh_scan` 只引入了本地 Ruby 和 BinData 来进行它的工作，没有太多的依赖。
* 它是可移植的，你可以在其它的项目中使用 `ssh_scan` 或者将它用在[自动化任务](https://www.tecmint.com/automating-linux-system-administration-tasks/)上。
* 它是易于使用的，只需要简单的将它指向一个 SSH 服务就可以获得一个该服务所支持的选项和策略状态的 JSON 格式报告。
* 它同时也是易于配置的，你可以创建适合你策略需求的策略。

**建议阅读：** [如何在 Linux 上安装配置 OpenSSH 服务](https://www.tecmint.com/install-openssh-server-in-linux/)

### 如何在 Linux 上安装 ssh\_scan

有如下三种安装 `ssh_scan` 的方式：

使用 Ruby gem 来安装运行，如下：

```
----------- 在 Debian/Ubuntu -----------
$ sudo apt-get install rubygems
$ sudo gem install ssh_scan
----------- 在 CentOS/RHEL -----------
# yum install ruby rubygems
# gem install ssh_scan

```

使用[docker 容器](https://www.tecmint.com/install-docker-and-learn-containers-in-centos-rhel-7-6/)来运行，如下：

```
# docker pull mozilla/ssh_scan
# docker run -it mozilla/ssh_scan /app/bin/ssh_scan -t github.com

```

使用源码安装运行，如下：

```
# git clone https://github.com/mozilla/ssh_scan.git
# cd ssh_scan
# gpg2 --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3
# curl -sSL https://get.rvm.io | bash -s stable
# rvm install 2.3.1
# rvm use 2.3.1
# gem install bundler
# bundle install
# ./bin/ssh_scan

```

### 如何在 Linux 上使用 ssh\_scan

使用 `ssh_scan` 的语法如下：

```
$ ssh_scan -t ip地址
$ ssh_scan -t 主机名

```

举个例子来扫描 192.168.43.198 这台服务器的 SSH 配置和策略，键入：

```
$ ssh_scan -t 192.168.43.198

```

注意你同时也可以像下方展示的给 `-t` 选项传入一个[IP地址/地址段/主机名]：

```
$ ssh_scan -t 192.168.43.198,200,205
$ ssh_scan -t test.tecmint.lan

```

输出示例：

```
I, [2017-05-09T10:36:17.913644 #7145]  INFO -- : You're using the latest version of ssh_scan 0.0.19
[
  {
    "ssh_scan_version": "0.0.19",
    "ip": "192.168.43.198",
    "port": 22,
    "server_banner": "SSH-2.0-OpenSSH_7.2p2 Ubuntu-4ubuntu2.1",
    "ssh_version": 2.0,
    "os": "ubuntu",
    "os_cpe": "o:canonical:ubuntu:16.04",
    "ssh_lib": "openssh",
    "ssh_lib_cpe": "a:openssh:openssh:7.2p2",
    "cookie": "68b17bcca652eeaf153ed18877770a38",
    "key_algorithms": [
      "curve25519-sha256@libssh.org",
      "ecdh-sha2-nistp256",
      "ecdh-sha2-nistp384",
      "ecdh-sha2-nistp521",
      "diffie-hellman-group-exchange-sha256",
      "diffie-hellman-group14-sha1"
    ],
    "server_host_key_algorithms": [
      "ssh-rsa",
      "rsa-sha2-512",
      "rsa-sha2-256",
      "ecdsa-sha2-nistp256",
      "ssh-ed25519"
    ],
    "encryption_algorithms_client_to_server": [
      "chacha20-poly1305@openssh.com",
      "aes128-ctr",
      "aes192-ctr",
      "aes256-ctr",
      "aes128-gcm@openssh.com",
      "aes256-gcm@openssh.com"
    ],
    "encryption_algorithms_server_to_client": [
      "chacha20-poly1305@openssh.com",
      "aes128-ctr",
      "aes192-ctr",
      "aes256-ctr",
      "aes128-gcm@openssh.com",
      "aes256-gcm@openssh.com"
    ],
    "mac_algorithms_client_to_server": [
      "umac-64-etm@openssh.com",
      "umac-128-etm@openssh.com",
      "hmac-sha2-256-etm@openssh.com",
      "hmac-sha2-512-etm@openssh.com",
      "hmac-sha1-etm@openssh.com",
      "umac-64@openssh.com",
      "umac-128@openssh.com",
      "hmac-sha2-256",
      "hmac-sha2-512",
      "hmac-sha1"
    ],
    "mac_algorithms_server_to_client": [
      "umac-64-etm@openssh.com",
      "umac-128-etm@openssh.com",
      "hmac-sha2-256-etm@openssh.com",
      "hmac-sha2-512-etm@openssh.com",
      "hmac-sha1-etm@openssh.com",
      "umac-64@openssh.com",
      "umac-128@openssh.com",
      "hmac-sha2-256",
      "hmac-sha2-512",
      "hmac-sha1"
    ],
    "compression_algorithms_client_to_server": [
      "none",
      "zlib@openssh.com"
    ],
    "compression_algorithms_server_to_client": [
      "none",
      "zlib@openssh.com"
    ],
    "languages_client_to_server": [
    ],
    "languages_server_to_client": [
    ],
    "hostname": "tecmint",
    "auth_methods": [
      "publickey",
      "password"
    ],
    "fingerprints": {
      "rsa": {
        "known_bad": "false",
        "md5": "0e:d0:d7:11:f0:9b:f8:33:9c:ab:26:77:e5:66:9e:f4",
        "sha1": "fc:8d:d5:a1:bf:52:48:a6:7e:f9:a6:2f:af:ca:e2:f0:3a:9a:b7:fa",
        "sha256": "ff:00:b4:a4:40:05:19:27:7c:33:aa:db:a6:96:32:88:8e:bf:05:a1:81:c0:a4:a8:16:01:01:0b:20:37:81:11"
      }
    },
    "start_time": "2017-05-09 10:36:17 +0300",
    "end_time": "2017-05-09 10:36:18 +0300",
    "scan_duration_seconds": 0.221573169,
    "duplicate_host_key_ips": [
    ],
    "compliance": {
      "policy": "Mozilla Modern",
      "compliant": false,
      "recommendations": [
        "Remove these Key Exchange Algos: diffie-hellman-group14-sha1",
        "Remove these MAC Algos: umac-64-etm@openssh.com, hmac-sha1-etm@openssh.com, umac-64@openssh.com, hmac-sha1",
        "Remove these Authentication Methods: password"
      ],
      "references": [
        "https://wiki.mozilla.org/Security/Guidelines/OpenSSH"
      ]
    }
  }
]

```

你可以使用 `-p` 选项来指定不同的端口，`-L` 选项来开启日志记录配合 `-V` 选项来指定日志级别：

```
$ ssh_scan -t 192.168.43.198 -p 22222 -L ssh-scan.log -V INFO

```

另外，可以使用 `-P` 或 `--policy` 选项来指定一个策略文件（默认是 Mozilla Modern）（LCTT 译注：这里的 Modern 可能指的是 <https://wiki.mozilla.org/Security/Server_Side_TLS> 中提到的 Modern compatibility ）：

```
$ ssh_scan -t 192.168.43.198 -L ssh-scan.log -V INFO -P /path/to/custom/policy/file

```

ssh\_scan 使用帮助与其它示例：

```
$ ssh_scan -h

```

输出示例：

```
ssh_scan v0.0.17 (https://github.com/mozilla/ssh_scan)
Usage: ssh_scan [options]
-t, --target [IP/Range/Hostname] IP/Ranges/Hostname to scan
-f, --file [FilePath]            File Path of the file containing IP/Range/Hostnames to scan
-T, --timeout [seconds]          Timeout per connect after which ssh_scan gives up on the host
-L, --logger [Log File Path]     Enable logger
-O, --from_json [FilePath]       File to read JSON output from
-o, --output [FilePath]          File to write JSON output to
-p, --port [PORT]                Port (Default: 22)
-P, --policy [FILE]              Custom policy file (Default: Mozilla Modern)
--threads [NUMBER]           Number of worker threads (Default: 5)
--fingerprint-db [FILE]      File location of fingerprint database (Default: ./fingerprints.db)
--suppress-update-status     Do not check for updates
-u, --unit-test [FILE]           Throw appropriate exit codes based on compliance status
-V [STD_LOGGING_LEVEL],
--verbosity
-v, --version                    Display just version info
-h, --help                       Show this message
Examples:
ssh_scan -t 192.168.1.1
ssh_scan -t server.example.com
ssh_scan -t ::1
ssh_scan -t ::1 -T 5
ssh_scan -f hosts.txt
ssh_scan -o output.json
ssh_scan -O output.json -o rescan_output.json
ssh_scan -t 192.168.1.1 -p 22222
ssh_scan -t 192.168.1.1 -p 22222 -L output.log -V INFO
ssh_scan -t 192.168.1.1 -P custom_policy.yml
ssh_scan -t 192.168.1.1 --unit-test -P custom_policy.yml

```

SSH 服务器相关参考阅读：

1. [使用 SSH Keygen（ssh-keygen）五步实现 SSH 免密登录](https://www.tecmint.com/ssh-passwordless-login-using-ssh-keygen-in-5-easy-steps/)
2. [安全 SSH 服务器的 5 个最佳实践](/article-7683-1.html)
3. [使用 Chroot 来限制 SSH 用户进入某些目录](/article-8313-1.html)
4. [如何配置 SSH 连接来简化远程登录](/article-8306-1.html)

如果需要更详细的信息可以访问 `ssh_scan` 的 Github 仓库：<https://github.com/mozilla/ssh_scan>

---

作者简介：

Aaron Kili 是 Linux 与 F.O.S.S （自由及开源软件）爱好者，一位将来的 Linux 系统管理员，网站开发者，现在是一个热爱与计算机一起工作并且拥有强烈知识分信念的 TecMint 内容贡献者。

---

via: <https://www.tecmint.com/ssh_scan-ssh-configuration-and-policy-scanner-for-linux/>

作者：[Aaron Kili](https://www.tecmint.com/author/aaronkili/) 译者：[wcnnbdk1](https://github.com/wcnnbdk1) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


理解 Linux 中的 shutdown、poweroff、halt 和 reboot 命令

Summary: 在本篇中，我们会向你解释 shutdown、poweroff、halt 以及 reboot 命令。我们会解释清楚当你用那些可用的选项执行的时候它们实际做了什么。

只能说是介绍，而不是理解。<br />
没什么干货。

这个。。。

最重要的是要分清出"停止機器"和"關閉機器"的區別，至於用哪個命令，呵呵，這些命令是互相引用或者說互相替代的～

poweroff和shutdown now一样啊

并没有解释这些命令具体的细节和区别，差评

并没有看懂什么。。。

等于没写

"低层维护状态"是什么意思？“底层维护”还听说过。

原文如此，low-level ，应该不是专有名词，可能是指，处于通电但是没有进入引导状态。

很水啊，没有解释下几个名词的区别吗？

shutdown 以一种安全的方式关闭系统。所有登陆用户都可以看到关机信息提示，并且 login  将被阻塞。

halt命令，若系统的 runlevel 为 0 或 6 ，则关闭系统，否则以 shutdown 指令（加上 -h 参数）来取代。

poweroff命令用来关闭计算机操作系统并且切断系统电源。

reboot执行reboot指令可让系统停止运作，并重新开机。

网上能搜到的就这些，详细的内容自己搜搜看吧，文章列出的内容确实太单一了。

要看具体的 init 是什么，systemd 是没有 runlevel 的概念。

来自 man 的简要说明

poweroff, halt, reboot: These are legacy commands available for compatibility only.

shutdown: shutdown may be used to halt, power-off or reboot the machine.

然而我并没有看懂

我选择init 0 关机init 6 重启

其实我还是比较想知道shutdown -r now和reboot的区别，据我所了解的：

【reboot】默认情况下其实是调用了shutdown -r来进行重启的；

和【halt】类似，【halt】其实是调用shutdown -h命令！

这种理解不知道是否正确？！

關閉機器:主板关电<br />
停止機器：主板不关电，可以看到风扇、灯都在闪

![](/data/attachment/album/201706/05/095810ydt5h18yh8etzhkx.jpg)

在本篇中，我们会向你解释 `shutdown`、`poweroff`、`halt` 以及 `reboot` 命令。我们会解释清楚当你用那些可用的选项执行的时候它们实际做了什么。

如果你想深入 Linux 服务器管理，那么为了有效和可靠的服务器管理，这些[重要的 Linux 命令](https://www.tecmint.com/60-commands-of-linux-a-guide-from-newbies-to-system-administrator/)你需要完全理解。

通常上，当你想要关闭或者重启你的机器时，你会运行下面之一的命令：

### shutdown 命令

`shutdown` 会给系统计划一个时间关机。它可以被用于停止、关机、重启机器。

你可以指定一个时间字符串（通常是 `now` 或者用 `hh:mm` 指定小时/分钟）作为第一个参数。额外地，你也可以设置一个广播信息在系统关闭前发送给所有已登录的用户。

重要：如果使用了时间参数，系统关机前 5 分钟，会创建 `/run/nologin` 文件。以确保没有人可以再登录。

`shutdown` 命令示例：

```
# shutdown
# shutdown now
# shutdown 13:20
# shutdown -p now  ### 关闭机器
# shutdown -H now  ### 停止机器
# shutdown -r09:35 ### 在 09:35am 重启机器

```

要取消即将进行的关机，只要输入下面的命令：

```
# shutdown -c

```

### halt 命令

`halt` 通知硬件来停止所有的 CPU 功能，但是仍然保持通电。你可以用它使系统处于低层维护状态。

注意在有些情况会它会完全关闭系统。下面是 `halt` 命令示例：

```
# halt             ### 停止机器
# halt -p          ### 关闭机器
# halt --reboot    ### 重启机器

```

### poweroff 命令

`poweroff` 会发送一个 ACPI 信号来通知系统关机。

下面是 `poweroff` 命令示例：

```
# poweroff           ### 关闭机器
# poweroff --halt    ### 停止机器
# poweroff --reboot  ### 重启机器

```

### reboot 命令

`reboot` 通知系统重启。

```
# reboot           ### 重启机器
# reboot --halt    ### 停止机器
# reboot -p        ### 关闭机器

```

就是这样了！如先前提到的，理解这些命令能够有效并可靠地在多用户环境下管理 Linux 服务器。你有一些额外的想法么？在评论区留言与我们分享。

---

作者简介：

Aaron Kili是一名 Linux 和 F.O.S.S 的爱好者，未来的 Linux 系统管理员、网站开发人员，目前是 TecMint 的内容创作者，他喜欢用电脑工作，并乐于分享知识。

---

via: <https://www.tecmint.com/shutdown-poweroff-halt-and-reboot-commands-in-linux/>

作者：[Aaron Kili](https://www.tecmint.com/author/aaronkili/) 译者：[geekpi](https://github.com/geekpi) 校对：[jasminepeng](https://github.com/jasminepeng)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


极客漫画：数据库链接池中的生生死死

你知道得太多了<br />
“砰”

大企业吗？真是伤脑筋。

“砰”

![Life (and Death) in the DB Connection Pool](/data/attachment/album/201706/05/140712giqn2zgynkl17fq1.png)

数据库连接池是常用的 B/S 技术，而似乎生活在这个“池子”里面的那些连接对象有点不幸。

要是顺利的话，你干完活就可以歇着了。

要是不顺利，比如你掌握的连接已经被拒绝了，那么……

你就会被“砰”地干掉。就问你怕不怕？（话说回来，回答错误会不会也被“砰”……）

---

via: <http://turnoff.us/geek/db-connection-pool/>

作者：[Daniel Stori](http://turnoff.us/about/) 译者&点评：[wxy](https://github.com/wxy) 校对&合成：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


调试器工作原理（三）：调试信息

![](/data/attachment/album/201706/06/012000szsjjsm4zobh4xho.jpg)

这是调试器的工作原理系列文章的第三篇。阅读这篇文章之前应当先阅读[第一篇](/article-8552-1.html)与[第二篇](/article-8418-1.html)。

### 这篇文章的主要内容

本文将解释调试器是如何在机器码中查找它将 C 语言源代码转换成机器语言代码时所需要的 C 语言函数、变量、与数据。

### 调试信息

现代编译器能够将有着各种缩进或嵌套的程序流程、各种数据类型的变量的高级语言代码转换为一大堆称之为机器码的 0/1 数据，这么做的唯一目的是尽可能快的在目标 CPU 上运行程序。通常来说一行 C 语言代码能够转换为若干条机器码。变量被分散在机器码中的各个部分，有的在堆栈中，有的在寄存器中，或者直接被优化掉了。数据结构与对象在机器码中甚至不“存在”，它们只是用于将数据按一定的结构编码存储进缓存。

那么调试器怎么知道，当你需要在某个函数入口处暂停时，程序要在哪停下来呢？它怎么知道当你查看某个变量值时，它怎么找到这个值？答案是，调试信息。

编译器在生成机器码时同时会生成相应的调试信息。调试信息代表了可执行程序与源代码之间的关系，并以一种提前定义好的格式，同机器码存放在一起。过去的数年里，人们针对不同的平台与可执行文件发明了很多种用于存储这些信息的格式。不过我们这篇文章不会讲这些格式的历史，而是将阐述这些调试信息是如何工作的，所以我们将专注于一些事情，比如 `DWARF`。`DWARF` 如今十分广泛的用作 Linux 和类 `Unix` 平台上的可执行文件的调试格式。

### ELF 中的 DWARF

![](/data/attachment/album/201706/06/155046ncicgp5u9sh7rhhe.gif)

根据[它的维基百科](http://en.wikipedia.org/wiki/DWARF) 所描述，虽然 `DWARF` 是同 `ELF` 一同设计的（`DWARF` 是由 `DWARF` 标准委员会推出的开放标准。上文中展示的图标就来自这个网站。），但 `DWARF` 在理论上来说也可以嵌入到其他的可执行文件格式中。

`DWARF` 是一种复杂的格式，它吸收了过去许多年各种不同的架构与操作系统的格式的经验。正是因为它解决了一个在任何平台与 ABI （应用二进制接口）上为任意高级语言产生调试信息这样棘手的难题，它也必须很复杂。想要透彻的讲解 `DWARF` 仅仅是通过这单薄的一篇文章是远远不够的，说实话我也并没有充分地了解 `DWARF` 到每一个微小的细节，所以我也不能十分透彻的讲解 （如果你感兴趣的话，文末有一些能够帮助你的资源。建议从 `DWARF` 教程开始上手）。这篇文章中我将以浅显易懂的方式展示 `DWARF`，以说明调试信息是如何实际工作的。

### ELF 文件中的调试部分

首先让我们看看 `DWARF` 处在 ELF 文件中的什么位置。`ELF` 定义了每一个生成的目标文件中的每一节。 <ruby> 节头表 <rt>  section header table </rt></ruby> 声明并定义了每一节及其名字。不同的工具以不同的方式处理不同的节，例如连接器会寻找连接器需要的部分，调试器会查找调试器需要的部分。

我们本文的实验会使用从这个 C 语言源文件构建的可执行文件，编译成 `tracedprog2`：

```
#include <stdio.h>

void do_stuff(int my_arg)、
{
    int my_local = my_arg + 2;
    int i;

    for (i = 0; i < my_local; ++i)
        printf("i = %d\n", i);
}

int main()
{
    do_stuff(2);
    return 0;
}

```

使用 `objdump -h` 命令检查 `ELF` 可执行文件中的<ruby> 节头 <rt>  section header </rt></ruby>，我们会看到几个以 `.debug_` 开头的节，这些就是 `DWARF` 的调试部分。

```
26 .debug_aranges 00000020  00000000  00000000  00001037
                 CONTENTS, READONLY, DEBUGGING
27 .debug_pubnames 00000028  00000000  00000000  00001057
                 CONTENTS, READONLY, DEBUGGING
28 .debug_info   000000cc  00000000  00000000  0000107f
                 CONTENTS, READONLY, DEBUGGING
29 .debug_abbrev 0000008a  00000000  00000000  0000114b
                 CONTENTS, READONLY, DEBUGGING
30 .debug_line   0000006b  00000000  00000000  000011d5
                 CONTENTS, READONLY, DEBUGGING
31 .debug_frame  00000044  00000000  00000000  00001240
                 CONTENTS, READONLY, DEBUGGING
32 .debug_str    000000ae  00000000  00000000  00001284
                 CONTENTS, READONLY, DEBUGGING
33 .debug_loc    00000058  00000000  00000000  00001332
                 CONTENTS, READONLY, DEBUGGING

```

每个节的第一个数字代表了该节的大小，最后一个数字代表了这个节开始位置距离 `ELF` 的偏移量。调试器利用这些信息从可执行文件中读取节。

现在让我们看看一些在 `DWARF` 中查找有用的调试信息的实际例子。

### 查找函数

调试器的最基础的任务之一，就是当我们在某个函数处设置断点时，调试器需要能够在入口处暂停。为此，必须为高级代码中的函数名称与函数在机器码中指令开始的地址这两者之间建立起某种映射关系。

为了获取这种映射关系，我们可以查找 `DWARF` 中的 `.debug_info` 节。在我们深入之前，需要一点基础知识。`DWARF` 中每一个描述类型被称之为调试信息入口（`DIE`）。每个 `DIE` 都有关于它的类型、属性之类的标签。`DIE` 之间通过兄弟节点或子节点相互连接，属性的值也可以指向其它的 `DIE`。

运行以下命令：

```
objdump --dwarf=info tracedprog2

```

输出文件相当的长，为了方便举例我们只关注这些行（从这里开始，无用的冗长信息我会以 （...）代替，方便排版）：

```
<1><71>: Abbrev Number: 5 (DW_TAG_subprogram)
    <72>   DW_AT_external    : 1
    <73>   DW_AT_name        : (...): do_stuff
    <77>   DW_AT_decl_file   : 1
    <78>   DW_AT_decl_line   : 4
    <79>   DW_AT_prototyped  : 1
    <7a>   DW_AT_low_pc      : 0x8048604
    <7e>   DW_AT_high_pc     : 0x804863e
    <82>   DW_AT_frame_base  : 0x0      (location list)
    <86>   DW_AT_sibling     : <0xb3>

<1><b3>: Abbrev Number: 9 (DW_TAG_subprogram)
    <b4>   DW_AT_external    : 1
    <b5>   DW_AT_name        : (...): main
    <b9>   DW_AT_decl_file   : 1
    <ba>   DW_AT_decl_line   : 14
    <bb>   DW_AT_type        : <0x4b>
    <bf>   DW_AT_low_pc      : 0x804863e
    <c3>   DW_AT_high_pc     : 0x804865a
    <c7>   DW_AT_frame_base  : 0x2c     (location list)

```

上面的代码中有两个带有 `DW_TAG_subprogram` 标签的入口，在 `DWARF` 中这是对函数的指代。注意，这是两个节的入口，其中一个是 `do_stuff` 函数的入口，另一个是主（`main`）函数的入口。这些信息中有很多值得关注的属性，但其中最值得注意的是 `DW_AT_low_pc`。它代表了函数开始处程序指针的值（在 x86 平台上是 `EIP`）。此处 `0x8048604` 代表了 `do_stuff` 函数开始处的程序指针。下面我们将利用 `objdump -d` 命令对可执行文件进行反汇编。来看看这块地址中都有什么：

```
08048604 <do_stuff>:
 8048604:       55           push   ebp
 8048605:       89 e5        mov    ebp,esp
 8048607:       83 ec 28     sub    esp,0x28
 804860a:       8b 45 08     mov    eax,DWORD PTR [ebp+0x8]
 804860d:       83 c0 02     add    eax,0x2
 8048610:       89 45 f4     mov    DWORD PTR [ebp-0xc],eax
 8048613:       c7 45 (...)  mov    DWORD PTR [ebp-0x10],0x0
 804861a:       eb 18        jmp    8048634 <do_stuff+0x30>
 804861c:       b8 20 (...)  mov    eax,0x8048720
 8048621:       8b 55 f0     mov    edx,DWORD PTR [ebp-0x10]
 8048624:       89 54 24 04  mov    DWORD PTR [esp+0x4],edx
 8048628:       89 04 24     mov    DWORD PTR [esp],eax
 804862b:       e8 04 (...)  call   8048534 <printf@plt>
 8048630:       83 45 f0 01  add    DWORD PTR [ebp-0x10],0x1
 8048634:       8b 45 f0     mov    eax,DWORD PTR [ebp-0x10]
 8048637:       3b 45 f4     cmp    eax,DWORD PTR [ebp-0xc]
 804863a:       7c e0        jl     804861c <do_stuff+0x18>
 804863c:       c9           leave
 804863d:       c3           ret

```

显然，`0x8048604` 是 `do_stuff` 的开始地址，这样一来，调试器就可以建立函数与其在可执行文件中的位置间的映射关系。

### 查找变量

假设我们当前在 `do_staff` 函数中某个位置上设置断点停了下来。我们想通过调试器取得 `my_local` 这个变量的值。调试器怎么知道在哪里去找这个值呢？很显然这要比查找函数更为困难。变量可能存储在全局存储区、堆栈、甚至是寄存器中。此外，同名变量在不同的作用域中可能有着不同的值。调试信息必须能够反映所有的这些变化，当然，`DWARF` 就能做到。

我不会逐一去将每一种可能的状况，但我会以调试器在 `do_stuff` 函数中查找 `my_local` 变量的过程来举个例子。下面我们再看一遍 `.debug_info` 中 `do_stuff` 的每一个入口，这次连它的子入口也要一起看。

```
<1><71>: Abbrev Number: 5 (DW_TAG_subprogram)
    <72>   DW_AT_external    : 1
    <73>   DW_AT_name        : (...): do_stuff
    <77>   DW_AT_decl_file   : 1
    <78>   DW_AT_decl_line   : 4
    <79>   DW_AT_prototyped  : 1
    <7a>   DW_AT_low_pc      : 0x8048604
    <7e>   DW_AT_high_pc     : 0x804863e
    <82>   DW_AT_frame_base  : 0x0      (location list)
    <86>   DW_AT_sibling     : <0xb3>
 <2><8a>: Abbrev Number: 6 (DW_TAG_formal_parameter)
    <8b>   DW_AT_name        : (...): my_arg
    <8f>   DW_AT_decl_file   : 1
    <90>   DW_AT_decl_line   : 4
    <91>   DW_AT_type        : <0x4b>
    <95>   DW_AT_location    : (...)       (DW_OP_fbreg: 0)
 <2><98>: Abbrev Number: 7 (DW_TAG_variable)
    <99>   DW_AT_name        : (...): my_local
    <9d>   DW_AT_decl_file   : 1
    <9e>   DW_AT_decl_line   : 6
    <9f>   DW_AT_type        : <0x4b>
    <a3>   DW_AT_location    : (...)      (DW_OP_fbreg: -20)
<2><a6>: Abbrev Number: 8 (DW_TAG_variable)
    <a7>   DW_AT_name        : i
    <a9>   DW_AT_decl_file   : 1
    <aa>   DW_AT_decl_line   : 7
    <ab>   DW_AT_type        : <0x4b>
    <af>   DW_AT_location    : (...)      (DW_OP_fbreg: -24)

```

看到每个入口处第一对尖括号中的数字了吗？这些是嵌套的等级，在上面的例子中，以 `<2>` 开头的入口是以 `<1>` 开头的子入口。因此我们得知 `my_local` 变量（以 `DW_TAG_variable` 标签标记）是 `do_stuff` 函数的局部变量。除此之外，调试器也需要知道变量的数据类型，这样才能正确的使用与显示变量。上面的例子中 `my_local` 的变量类型指向另一个 `DIE` `<0x4b>`。如果使用 `objdump` 命令查看这个 `DIE` 的话，我们会发现它是一个有符号 4 字节整型数据。

而为了在实际运行的程序内存中查找变量的值，调试器需要使用到 `DW_AT_location` 属性。对于 `my_local` 而言，是 `DW_OP_fbreg: -20`。这个代码段的意思是说 `my_local` 存储在距离它所在函数起始地址偏移量为 `-20` 的地方。

`do_stuff` 函数的 `DW_AT_frame_base` 属性值为 `0x0 (location list)`。这意味着这个属性的值需要在 `location list` 中查找。下面我们来一起看看。

```
$ objdump --dwarf=loc tracedprog2

tracedprog2:     file format elf32-i386

Contents of the .debug_loc section:

    Offset   Begin    End      Expression
    00000000 08048604 08048605 (DW_OP_breg4: 4 )
    00000000 08048605 08048607 (DW_OP_breg4: 8 )
    00000000 08048607 0804863e (DW_OP_breg5: 8 )
    00000000 <End of list>
    0000002c 0804863e 0804863f (DW_OP_breg4: 4 )
    0000002c 0804863f 08048641 (DW_OP_breg4: 8 )
    0000002c 08048641 0804865a (DW_OP_breg5: 8 )
    0000002c <End of list>

```

我们需要关注的是第一列（`do_stuff` 函数的 `DW_AT_frame_base` 属性包含 `location list` 中 `0x0` 的偏移量。而 `main` 函数的相同属性包含 `0x2c` 的偏移量，这个偏移量是第二套地址列表的偏移量）。对于调试器可能定位到的每一个地址，它都会指定当前栈帧到变量间的偏移量，而这个偏移就是通过寄存器来计算的。对于 x86 平台而言，`bpreg4` 指向 `esp`，而 `bpreg5` 指向 `ebp`。

让我们再看看 `do_stuff` 函数的头几条指令。

```
08048604 <do_stuff>:
 8048604:       55          push   ebp
 8048605:       89 e5       mov    ebp,esp
 8048607:       83 ec 28    sub    esp,0x28
 804860a:       8b 45 08    mov    eax,DWORD PTR [ebp+0x8]
 804860d:       83 c0 02    add    eax,0x2
 8048610:       89 45 f4    mov    DWORD PTR [ebp-0xc],eax

```

只有当第二条指令执行后，`ebp` 寄存器才真正存储了有用的值。当然，前两条指令的基址是由上面所列出来的地址信息表计算出来的。一但 `ebp` 确定了，计算偏移量就十分方便了，因为尽管 `esp` 在操作堆栈的时候需要移动，但 `ebp` 作为栈底并不需要移动。

究竟我们应该去哪里找 `my_local` 的值呢？在 `0x8048610` 这块地址后， `my_local` 的值经过在 `eax` 中的计算后被存在了内存中，从这里开始我们才需要关注 `my_local` 的值。调试器会利用 `DW_OP_breg5: 8` 这个栈帧来查找。我们回想下，`my_local` 的 `DW_AT_location` 属性值为 `DW_OP_fbreg: -20`。所以应当从基址中 `-20` ，同时由于 `ebp` 寄存器需要 `+8`，所以最终结果为 `ebp - 12`。现在再次查看反汇编代码，来看看数据从 `eax` 中被移动到哪里了。当然，这里 `my_local` 应当被存储在了 `ebp - 12` 的地址中。

### 查看行号

当我们谈到在调试信息寻找函数的时候，我们利用了些技巧。当调试 C 语言源代码并在某个函数出放置断点的时候，我们并不关注第一条“机器码”指令（函数的调用准备工作已经完成而局部变量还没有初始化）。我们真正关注的是函数的第一行“C 代码”。

这就是 `DWARF` 完全覆盖映射 C 源代码中的行与可执行文件中机器码地址的原因。下面是 `.debug_line` 节中所包含的内容，我们将其转换为可读的格式展示如下。

```
$ objdump --dwarf=decodedline tracedprog2

tracedprog2:     file format elf32-i386

Decoded dump of debug contents of section .debug_line:

CU: /home/eliben/eli/eliben-code/debugger/tracedprog2.c:
File name           Line number    Starting address
tracedprog2.c                5           0x8048604
tracedprog2.c                6           0x804860a
tracedprog2.c                9           0x8048613
tracedprog2.c               10           0x804861c
tracedprog2.c                9           0x8048630
tracedprog2.c               11           0x804863c
tracedprog2.c               15           0x804863e
tracedprog2.c               16           0x8048647
tracedprog2.c               17           0x8048653
tracedprog2.c               18           0x8048658

```

很容易就可以看出其中 C 源代码与反汇编代码之间的对应关系。第 5 行指向 `do_stuff` 函数的入口，`0x8040604`。第 6 行，指向 `0x804860a` ，正是调试器在调试 `do_stuff` 函数时需要停下来的地方。这里已经完成了函数调用的准备工作。上面的这些信息形成了行号与地址间的双向映射关系。

* 当在某一行设置断点的时候，调试器会利用这些信息去查找相应的地址来做断点工作（还记得上篇文章中的 `int 3` 指令吗？）
* 当指令造成段错误时，调试器会利用这些信息来查看源代码中发生问题的行。

### libdwarf - 用 DWARF 编程

尽管使用命令行工具来获得 `DWARF` 很有用，但这仍然不够易用。作为程序员，我们希望知道当我们需要这些调试信息时应当怎么编程来获取这些信息。

自然我们想到的第一种方法就是阅读 `DWARF` 规范并按规范操作阅读使用。有句话说的好，分析 HTML 应当使用库函数，永远不要手工分析。对于 `DWARF` 来说正是如此。`DWARF` 比 HTML 要复杂得多。上面所展示出来的只是冰山一角。更糟糕的是，在实际的目标文件中，大部分信息是以非常紧凑的压缩格式存储的，分析起来更加复杂（信息中的某些部分，例如位置信息与行号信息，在某些虚拟机下是以指令的方式编码的）。

所以我们要使用库来处理 `DWARF`。下面是两种我熟悉的主要的库（还有些不完整的库这里没有写）

1. `BFD` （libbfd），包含了 `objdump` （对，就是这篇文章中我们一直在用的这货），`ld`（`GNU` 连接器）与 `as`（`GNU` 编译器）。`BFD` 主要用于 [GNU binutils](http://www.gnu.org/software/binutils/)。
2. `libdwarf` ，同它的哥哥 `libelf` 一同用于 `Solaris` 与 `FreeBSD` 中的调试信息分析。

相比较而言我更倾向于使用 `libdwarf`，因为我对它了解的更多，并且 `libdwarf` 的开源协议更开放（`LGPL` 对比 `GPL`）。

因为 `libdwarf` 本身相当复杂，操作起来需要相当多的代码，所以我在这不会展示所有代码。你可以在 [这里](https://github.com/eliben/code-for-blog/blob/master/2011/dwarf_get_func_addr.c) 下载代码并运行试试。运行这些代码需要提前安装 `libelfand` 与 `libdwarf` ，同时在使用连接器的时候要使用参数 `-lelf` 与 `-ldwarf`。

这个示例程序可以接受可执行文件并打印其中的函数名称与函数入口地址。下面是我们整篇文章中使用的 C 程序经过示例程序处理后的输出。

```
$ dwarf_get_func_addr tracedprog2
DW_TAG_subprogram: 'do_stuff'
low pc  : 0x08048604
high pc : 0x0804863e
DW_TAG_subprogram: 'main'
low pc  : 0x0804863e
high pc : 0x0804865a

```

`libdwarf` 的文档很棒，如果你花些功夫，利用 `libdwarf` 获得这篇文章中所涉及到的 `DWARF` 信息应该并不困难。

### 结论与计划

原理上讲，调试信息是个很简单的概念。尽管实现细节可能比较复杂，但经过了上面的学习我想你应该了解了调试器是如何从可执行文件中获取它需要的源代码信息的了。对于程序员而言，程序只是代码段与数据结构；对可执行文件而言，程序只是一系列存储在内存或寄存器中的指令或数据。但利用调试信息，调试器就可以将这两者连接起来，从而完成调试工作。

此文与这系列的前两篇，一同介绍了调试器的内部工作过程。利用这里所讲到的知识，再敲些代码，应该可以完成一个 Linux 中最简单、基础但也有一定功能的调试器。

下一步我并不确定要做什么，这个系列文章可能就此结束，也有可能我要讲些堆栈调用的事情，又或者讲 Windows 下的调试。你们有什么好的点子或者相关材料，可以直接评论或者发邮件给我。

### 参考

* objdump 参考手册
* [ELF](http://en.wikipedia.org/wiki/Executable_and_Linkable_Format) 与 [DWARF](http://en.wikipedia.org/wiki/DWARF) 的维基百科
* [Dwarf Debugging Standard 主页](http://dwarfstd.org/)，这里有很棒的 DWARF 教程与 DWARF 标准，作者是 Michael Eager。第二版基于 GCC 也许更能吸引你。
* [libdwarf 主页](http://reality.sgiweb.org/davea/dwarf.html)，这里可以下载到 libwarf 的完整库与参考手册
* [BFD 文档](http://sourceware.org/binutils/docs-2.21/bfd/index.html)

---

---

via: <http://eli.thegreenplace.net/2011/02/07/how-debuggers-work-part-3-debugging-information>

作者：[Eli Bendersky](http://eli.thegreenplace.net/) 译者：[YYforymj](https://github.com/YYforymj) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


软件定义存储（SDS）的发展：十个你应当知道的项目

![Software defined Storage](/data/attachment/album/201706/06/153319xy8kyg6blkreodt6.jpg "Software Defined Storage")

>
> 凭借 SDS，组织机构可以更好抽象出底层存储的管理功能，并且通过不同策略实现灵活配置。下面将要向你展示一些你应当知道的此类开源项目。
>
>
>

纵观 2016 年，SDS（Software-Defined Storage，软件定义存储）方面取得了很多里程碑式的进步，并且日益紧密的与云部署结合在了一起。凭借 SDS ，组织机构可以更好抽象出底层存储的管理功能，并且通过不同策略实现灵活配置。当然，他们也可以选择自由开源的 SDS 解决方案。人们熟知的 Ceph 正是凭借 OpenStack 部署在不断扩大自己的影响力，但是它离成为唯一的 SDS 开源项目还有很长的路要走。

Gartner 的一份市场调查报告中预测，截至到 2019 年，70% 已有的存储部署解决方案会支持以纯软件的方式来实施。同时 Gartner 还预测截至到 2020 年，70% 到 80% 的非结构化数据会存储在由 SDS 管理的廉价存储设备中。

最近，Dell EMC 公司加入到了由 Linux 基金会发起的 [OpenSDS](http://ctt.marketwire.com/?release=11G125514-001&id=10559023&type=0&url=https%3A%2F%2Fwww.opensds.io%2F) 项目中。 OpenSDS 致力于寻求解决 SDS 集成所面临的挑战，并推动企业对开放标准的采用。它由存储客户与厂商组成，包括 Fujitsu，Hitachi Data Systems，Huawei，Oregon State University 以及 Vodafone。同时 OpenSDS 也寻求与其它的上游开源社区进行合作，比如 Cloud Native Computing Foundation、Docker、OpenStack 以及 Open Container Initiative。

根据 Open SDS 项目的 [主页](https://www.opensds.io/)，2017 年会是 SDS 的一个元年：“社区希望在 2017 第二季度完成原型的发布，并且在第三季度中发布一个测试版本。OpenSDS 的最初组织者期望能通过这个项目来影响到一些开源技术，比如来自 Openstack 社区的 Cinder 和 Manila 项目，并且能够支持更广泛的云存储解决方案。”

与此同时，SDS 相关项目也呈现了爆发式的增长，其范围横跨 Apache Cassandra 到 Cehp。Linux 基金会最近发布了 2016 年度报告“[开放云指南：当前的趋势及开源项目](http://ctt.marketwire.com/?release=11G120876-001&id=10172077&type=0&url=http%3A%2F%2Fgo.linuxfoundation.org%2Frd-open-cloud-report-2016-pr)”，报告从整体上分析了开放云计算的现状，其中有一章涵盖了 SDS。你可以[下载](http://go.linuxfoundation.org/l/6342/2016-10-31/3krbjr)这篇报告，需要注意的是，这是一份综合了容器发展趋势、SDS，以及云计算的重新定义等等很多内容。报告中涵盖了当今对于开源云计算最重要的一些项目，并分类给出了描述和链接。

在这个系列的文章中，我们从该报告中整理了很多项目，并且针对它们是如何发展的提供了一些额外的视角及信息。在下面的内容当中，你会看到现今对 SDS 来说很重要的项目，并且能了解到它们为什么具有这么大的影响力。同时，根据上面的报告，我们提供了相关项目的 GitHub 仓库链接，方便大家查看。

### 软件定义存储（SDS）

* [Apache Cassandra](http://cassandra.apache.org/)

Apache Cassandra 是一个可扩展的、高可用的，面向任务优先应用的数据库。它可以运行在商业设备或者云架构上，并且能实现跨数据中心的低延迟数据传输，同时具备良好的容错性。[Cassandra 的 GitHub 仓库](https://github.com/apache/cassandra)。
* [Ceph](http://ceph.com/)

Ceph 是 Red Hat 构建的一个企业级可扩展的块设备、对象，以及文件存储平台，并且可部署在公有云或者私有云之上。Ceph 目前被广泛应用于 OpenStack。[Ceph 的 GitHub 仓库](https://github.com/ceph/ceph)。
* [CouchDB](http://couchdb.apache.org/)

CouchDB 是一个 Apache 软件基金会项目，是一个单节点或者集群数据库管理系统。CouchDB 提供了 RESTful HTTP 接口来读取和更新数据库文件。[CouchDB 的 GitHub 仓库](https://github.com/apache/couchdb)。
* [Docker 数据卷插件](https://docs.docker.com/engine/extend/plugins_volume/)

Docker Engine 数据卷插件可以使 Engine 与外部的存储系统一起集成部署，并且数据卷的生命周期与单一 Engine 主机相同。目前存在很多第三方的数据卷管理插件，包括 Azure File Storage、NetApp、VMware vSphere 等等。你可以在 GitHub上查找到更多的插件。
* [GlusterFS](https://www.gluster.org/)

Gluster 是 Red Hat 的可扩展网络文件系统，同时也是数据管理平台。Gluster 可以部署在公有云，私有云或者混合云之上，可用于 Linux 容器内的流媒体处理任务、数据分析任务，以及其它数据和带宽敏感型任务的执行。[GlusterFS 的 GitHub 仓库](https://github.com/gluster/glusterfs)。
* [MongoDB](https://www.mongodb.com/)

MongoDB 是一个高性能的文件数据库，并且部署和扩展都非常简单。[MongoDB 的 GitHub 仓库](https://github.com/mongodb/mongo)。
* [Nexenta](https://nexenta.com/)

NexentaStor 是一个可扩展的、统一的软件定义的文件和块设备管理服务，同时支持数据管理功能。它能够与 VMware 集成，并且支持 Docker 和 OpenStack。[Nexenta 的 GitHub 仓库](https://github.com/Nexenta)。
* [Redis](http://redis.io/)

Redis 是一个基于内存的数据存储，一般被用作数据库、缓存，以及消息代理。它支持多种数据结构，并且本身支持复制、Lua 脚本、LRU 算法、事务，以及多层级的硬盘持久化。
* [Riak CS](http://docs.basho.com/riak/cs/2.1.1/)

Riak CS（Cloud Storage）是基于 Basho 的分布式数据库 Riak KV 构建的对象存储软件。它提供了在不同规模的分布式云存储能力，可以用于公有云和私有云，还能为大压力的应用和服务提供基础的存储服务。其 API 兼容 Amazon S3，并且支持租户级别的费用计算和测量能力。[Riak CS 的 GitHub 仓库](https://github.com/basho/riak_cs)。
* [Swift](https://wiki.openstack.org/wiki/Swift)

Swift 是 OpenStack 项目中的对象存储系统，设计初衷是通过简单 API 存储和获取非结构化数据。Swift 设计之初就是可扩展的，并且针对持久性、可靠性以及并发数据读取做了优化。[Swift 的 GitHub 仓库](https://github.com/openstack/swift)。

*了解更多的开源云计算趋势以及更完整的开源云计算项目列表，请[下载 Linux 基金会的“开放云指南”](http://bit.ly/2eHQOwy)。*

（题图：Pixabay，CC0）

---

via: <https://www.linux.com/news/open-cloud-report/2016/guide-open-cloud-software-defined-storage-opens>

作者：[SAM DEAN](https://www.linux.com/users/sam-dean) 译者：[toutoudnf](https://github.com/toutoudnf) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


mimipenguin：从当前 Linux 用户转储登录密码

![](/data/attachment/album/201706/07/081750rx207a5nhaa4qv40.jpg)

mimipenguin 是一个免费、开源、简单但是强大的 shell/python 脚本，用来从当前 Linux 桌面用户转储登录凭证（用户名和密码），并且已在不同的 Linux 发行版中测试过。

另外，它还支持如：VSFTPd（活跃的 FTP 客户端连接）、Apache2（活跃的/旧的 HTTP 基础认证会话，但是这需要 Gcore），还有 openssh-server（活跃的 SSH 链接，需用 [sudo 命令](https://www.tecmint.com/sudoers-configurations-for-setting-sudo-in-linux/)）。重要的是，它逐渐被移植到其他语言中，以支持所有可想到的以后可以利用的情况。

### mimipenguin 是如何工作的？

要理解 mimipenguin 是如何工作的，你需要知道所有或者大多数的 Linux 发行版会在内存中存储大量的重要信息, 如：凭据、加密密钥以及个人数据。

尤其是用户名和密码是由进程（运行中的程序）保存在内存中，并以明文形式存储较长时间。mimipenguin 在技术上利用这些在内存中的明文凭证 - 它会转储一个进程，并提取可能包含明文凭据的行。

然后，通过以下内容的哈希值来尝试计算每个单词的出现几率：`/etc/shadow`、内存和 regex 搜索。一旦找到任何内容，它就会在标准输出上打印出来。

### 在 Linux 中安装 mimipenguin

我们将使用 git 来克隆 mimipenguin 仓库，因此如果你还没安装，那么首先在系统上安装 git。

```
$ sudo apt install git      #Debian/Ubuntu systems
$ sudo yum install git      #RHEL/CentOS systems
$ sudo dnf install git      #Fedora 22+

```

接着像这样在你的家目录（或者其他任何地方）克隆 mimipenguin 目录：

```
$ git clone https://github.com/huntergregal/mimipenguin.git

```

下载完成后，进入并如下运行 mimipenguin：

```
$ cd mimipenguin/
$ ./mimipenguin.sh

```

注意：如果你遇到下面的错误，那就使用 sudo 命令：

```
Root required - You are dumping memory...
Even mimikatz requires administrator

```

![Dump Login Passwords in Linux](/data/attachment/album/201706/07/081856hei2hruiwnbbwz8j.png)

*在 Linux 中转储登录密码*

从上面的输出中，mimipenguin 向你提供了桌面环境的用户名和密码。

另外，还可以如下运行 python 版脚本：

```
$ sudo ./mimipenguin.py

```

注意有时 gcore 可能会阻塞脚本（这是 gcore 中一个已知问题）。

### 未来更新

下面是将会被添加到 mimipenguin 的功能：

* 提升总体效率
* 添加更多支持以及其他的凭据位置
* 包括支持非桌面环境
* 添加 LDAP 的支持

mimipenguin 的 Github 仓库：<https://github.com/huntergregal/mimipenguin>

同样，请查阅：

1. [如何在 Linux 中用密码保护一个 vim 文件](/article-8547-1.html)
2. [如何在 Linux 中生成/加密/解密随机密码](https://www.tecmint.com/generate-encrypt-decrypt-random-passwords-in-linux/)
3. [如何在 RHEL/CentOS/Fedora 中用密码保护 GRUB](https://www.tecmint.com/password-protect-grub-in-linux/)
4. [在 CentOS 7 中重置/恢复忘记的 root 用户账号密码](/article-8212-1.html)

在下面的评论栏中分享你关于这个工具的额外想法或者对 Linux 中内存中明文凭据的问题。

（题图：Pixabay，CC0）

---

作者简介：

Aaron Kili 是 Linux 和 F.O.S.S 爱好者，即将成为 Linux SysAdmin 和网络开发人员，目前是 TecMint 的内容创作者，他喜欢在电脑上工作，并坚信分享知识。

---

via: <https://www.tecmint.com/mimipenguin-hack-login-passwords-of-linux-users/>

作者：[Aaron Kili](https://www.tecmint.com/author/aaronkili/) 译者：[geekpi](https://github.com/geekpi) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


使用 Python 开始你的机器学习之旅

支持linux中国，加油

谢谢！！

>
> 机器学习是你的简历中必需的一门技能。我们简要概括一下使用 Python 来进行机器学习的一些步骤。
>
>
>

![Get started with machine learning using Python](/data/attachment/album/201706/07/091219dd15wiwukzlubid0.png "Get started with machine learning using Python")

你想知道如何开始机器学习吗？在这篇文章中，我将简要概括一下使用 [Python](https://opensource.com/article/17/2/3-top-machine-learning-libraries-python) 来开始机器学习的一些步骤。Python 是一门流行的开源程序设计语言，也是在人工智能及其它相关科学领域中最常用的语言之一。机器学习简称 ML，是人工智能的一个分支，它是利用算法从数据中进行学习，然后作出预测。机器学习有助于帮助我们预测我们周围的世界。

从无人驾驶汽车到股市预测，再到在线学习，机器学习通过预测来进行自我提高的方法几乎被用在了每一个领域。由于机器学习的实际运用，目前它已经成为就业市场上最有需求的技能之一。另外，使用 Python 来开始机器学习很简单，因为有大量的在线资源，以及许多可用的 [Python 机器学习库](https://opensource.com/article/17/2/3-top-machine-learning-libraries-python)。

你需要如何开始使用 Python 进行机器学习呢？让我们来总结一下这个过程。

### 提高你的 Python 技能

由于 Python 在工业界和科学界都非常受欢迎，因此你不难找到 Python 的学习资源。如果你是一个从未接触过 Python 的新手，你可以利用在线资源，比如课程、书籍和视频来学习 Python。比如下面列举的一些资源：

* [Python 学习之路](https://learnpythonthehardway.org/book/)
* [Google 开发者 Python 课程（视频）](https://www.youtube.com/playlist?list=PLfZeRfzhgQzTMgwFVezQbnpc1ck0I6CQl)
* [Google 的 Python 课堂](https://developers.google.com/edu/python/)

### 安装 Anaconda

下一步是安装 [Anacona](https://opensource.com/tags/javascript?src=programming_resource_menu)。有了 Anaconda ，你将可以开始使用 Python 来探索机器学习的世界了。Anaconda 的默认安装库包含了进行机器学习所需要的工具。

### 基本的机器学习技能

有了一些基本的 Python 编程技能，你就可以开始学习一些基本的机器学习技能了。一个实用的学习方法是学到一定技能便开始进行练习。然而，如果你想深入学习这个领域，那么你需要准备投入更多的学习时间。

一个获取技能的有效方法是在线课程。吴恩达的 Coursera [机器学习课程](https://www.coursera.org/learn/machine-learning) 是一个不错的选择。其它有用的在线训练包括：

* [Python 机器学习： Scikit-Learn 教程](https://www.datacamp.com/community/tutorials/machine-learning-python#gs.HfAvLRs)
* [Python 实用机器学习教程](https://pythonprogramming.net/machine-learning-tutorial-python-introduction/)

你也可以在 [LiveEdu.tv](https://www.liveedu.tv/) 上观看机器学习视频，从而进一步了解这个领域。

### 学习更多的 Python 库

当你对 Python 和机器学习有一个好的感觉之后，可以开始学习一些[开源的 Python 库](https://opensource.com/article/17/5/4-practical-python-libraries)。科学的 Python 库将会使完成一些简单的机器学习任务变得很简单。然而，选择什么库是完全主观的，并且在业界内许多人有很大的争论。

一些实用的 Python 库包括：

* [Scikit-learn](http://scikit-learn.org/stable/) ：一个优雅的机器学习算法库，可用于数据挖掘和数据分析任务。
* [Tensorflow](https://opensource.com/article/17/2/machine-learning-projects-tensorflow-raspberry-pi) ：一个易于使用的神经网络库。
* [Theano](http://deeplearning.net/software/theano/) ： 一个强大的机器学习库，可以帮助你轻松的评估数学表达式。
* [Pattern](https://github.com/clips/pattern) ： 可以帮助你进行自然语言处理、数据挖掘以及更多的工作。
* [Nilearn](https://github.com/nilearn/nilearn) ：基于 Scikit-learn，它可以帮助你进行简单快速的统计学习。

### 探索机器学习

对基本的 Python、机器学习技能和 Python 库有了一定理解之后，就可以开始探索机器学习了。接下来，尝试探索一下 Scikit-learn 库。一个不错的教程是 Jake VanderPlas 写的 [Scikit-learn 简介](http://nbviewer.jupyter.org/github/donnemartin/data-science-ipython-notebooks/blob/master/scikit-learn/scikit-learn-intro.ipynb)。

然后，进入中级主题，比如 [K-均值聚类算法简介](https://www.datascience.com/blog/introduction-to-k-means-clustering-algorithm-learn-data-science-tutorials)、线性回归、[决策树](http://machinelearningmastery.com/implement-decision-tree-algorithm-scratch-python/)和逻辑回归。

最后，深入高级机器学习主题，比如向量机和复杂数据转换。

就像学习任何新技能一样，练习得越多，就会学得越好。你可以通过练习不同的算法，使用不同的数据集来更好的理解机器学习，并提高解决问题的整体能力。

使用 Python 进行机器学习是对你的技能的一个很好的补充，并且有大量免费和低成本的在线资源可以帮助你。你已经掌握机器学习技能了吗？可以在下面留下你的评论，或者[提交一篇文章](https://opensource.com/story)来分享你的故事。

（题图：opensource.com）

---

作者简介：

Michael J. Garbade 博士是旧金山 LiveEdu Inc（Livecoding.tv）的创始人兼首席执行官。Livecoding.tv 是世界上观看工程师直播编代码最先进的直播平台。你可以通过观看工程师们写网站、移动应用和游戏，来将你的技能提升到一个新的水平。MichaelJ. Garbade 博士拥有金融学博士学位，并且是一名自学成才的工程师，他喜欢 Python、Django、Sencha Touch 和视频流。

---

via: <https://opensource.com/article/17/5/python-machine-learning-introduction>

作者：[Michael J. Garbade](https://opensource.com/users/drmjg) 译者：[ucasFL](https://github.com/ucasFL) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


使用 comm 比较两个排序好的文件

Summary: Linux 中的 comm 命令可以让用户按行比较两个已经排序好的文件。在本教程中，我们将使用一些浅显易懂的例子来讨论这个命令行工具。

![](/data/attachment/album/201706/07/093734gfgib0dugxmlihd0.jpg)

Linux 中的 `comm` 命令可以让用户按行比较两个**已经排序好**的文件。在本教程中，我们将使用一些浅显易懂的例子来讨论这个命令行工具。在开始之前，请注意，本教程中提到的所有例子都已经在 Ubuntu 16.04LTS 版本中测试过。

下面的例子将会告诉你 `comm` 命令是如何工作的。

### 1、 如何使用 `comm` 比较两个排序好的文件

要使用 `comm` 命令比较两个排序好的文件，只需要把它们的名字作为 `comm` 命令的参数。下面是通常的语法：

```
comm [name-of-first-file] [name-of-second-file]

```

比如，假设 `file1` 和 `file2` 是这种情况下的两个文件。前者包含下面几行内容：

```
001
056
127
258

```

而后者包含下面几行内容：

```
002
056
167
369

```

此时，`comm` 命令的输出如下图所示：

```
comm file1 file2

```

![](/data/attachment/album/201706/07/093741vqxvetv322xvr3vx.png)

你可以看到，输出包含 3 列。第一列是仅包含在 `file1` 中的内容，第二列是仅包含在 `file2` 中的内容，最后，第三列是两个文件中均包含的内容。

### 2、 如何不输出 `comm` 命令输出中的某些列

如果你想，你可以不输出 `comm` 命令输出中的某些列。对于该特性，你有三个命令行选项可用：`-1`、`-2` 和 `-3` 。正如你所猜想的，这些数字表示你不想输出的列。

比如，下面这个命令将会不输出上面例子中的第三列：

```
comm -3 file1 file2

```

![](/data/attachment/album/201706/07/093741nfa3n47qf4s8s4vt.png)

因此，你可以看到，第三列并没有输出。

注意，你可以通过一个单一命令同时不输出多列内容。比如：

```
comm -12 file1 file2

```

上面这个命令将会不输出第一、二列。

### 3、 如何使用 `comm` 命令比较两个未排序好的文件

正如我们所知道的，`comm` 只可用于排序好的文件。如果发现其中一个文件未排序好，那么便会在输出中产生一条信息来告诉用户。比如，我们交换 `file1` 的第一行和第二行，然后与 `file2` 进行比较。下面是该命令的输出：

![](/data/attachment/album/201706/07/093741illmd1xltay1k2hc.png)

你可以看到，这个命令产生一个输出告诉我们：`file1` 还没有排序好。此时，如果你不想让这个工具检查输入是否已经排序好，那么你可以使用 `--nocheck-order` 选项：

```
comm --nocheck-order file1 file2

```

![](/data/attachment/album/201706/07/093741vx5xjew8j1nc511j.png)

你可以看到，前面出现的提示信息已经消失了。

注意，如果你想明确告诉 `comm` 命令来检查输入文件是否排序好，那么你可以使用 `--check-order` 选项。

### 4、 如何用自定义字符串分隔 `comm` 命令的输出列

默认情况下，`comm` 命令的输出列之间是以空格分隔的。然而，如何你想使用一个自定义字符串作为分隔符，那么你可以使用 `--output-delimiter` 选项。使用该选项时需要指定你想用来作为分隔符的字符串。

```
comm --output-delimiter=+ file1 file2

```

比如，我们使用加号来作为分隔符：

![](/data/attachment/album/201706/07/093742yqq2pw3e3m3iimqi.png)

### 5、 如何使 `comm` 的输出行以 `NUL` 字符终止

默认情况下，`comm` 命令的输出行以新行终止。然而，如果你想，那么你可以改为以 `NUL` 字符终止，只需要使用 `-z` 选项即可：

```
comm -z file1 file2

```

### 结论

`comm` 命令并没有特别多的特性性，我们在这儿已经讨论了它的绝大多数命令行选项。只需要理解和练习在这篇教程中讨论的内容，那么你便可以在日常工作中知道如何使用这个工具了。如果你有任何问题或者疑问，请前往该命令的 [man 手册](https://linux.cn/man/1/comm)，或者在下面评论。

---

via: <https://www.howtoforge.com/linux-comm-command/>

作者：[Himanshu Arora](https://www.howtoforge.com/linux-comm-command/) 译者：[ucasFL](https://github.com/ucasFL) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


FreeFileSync：在 Ubuntu 中对比及同步文件

![](/data/attachment/album/201706/08/060245nbh3tj5tlhjtenx5.png)

FreeFileSync 是一个自由、开源以及跨平台的文件夹对比及同步软件，它可以帮助你同步 Linux、Windows 和 Mac OS 中的文件和文件夹。

它是便携的，也可以被安装在本地系统中，它的功能丰富，旨在节省设置和执行备份操作的时间，同时具有有吸引力的图形界面。

#### FreeFileSync 功能

下面是它的主要功能：

1. 它可以同步网络共享和本地磁盘。
2. 它可以同步 MTP 设备（Android、iPhone、平板电脑、数码相机）。
3. 它也可以通过 [SFTP（SSH 文件传输协议）](http://www.tecmint.com/sftp-command-examples/)进行同步。
4. 它可以识别被移动和被重命名的文件和文件夹。
5. 使用目录树显示磁盘空间使用情况。
6. 支持复制锁定文件（卷影复制服务）。
7. 识别冲突并同步删除（propagate deletions）。
8. 支持按内容比较文件。
9. 它可以配置为处理符号链接。
10. 支持批量自动同步。
11. 支持多个文件夹比较。
12. 支持深入详细的错误报告。
13. 支持复制 NTFS 扩展属性，如（压缩、加密、稀疏）。
14. 还支持复制 NTFS 安全权限和 NTFS 备用数据流。
15. 支持超过 260 个字符的长文件路径。
16. 支持免故障的文件复制防止数据损坏。
17. 允许扩展环境变量，例如 `％UserProfile％`。
18. 支持通过卷名访问可变驱动器盘符（U盘）。
19. 支持管理已删除/更新文件的版本。
20. 通过最佳同步序列防止光盘空间问题。
21. 完全支持 Unicode。
22. 提供高度优化的运行时性能。
23. 支持过滤器包含和排除文件等。

### 如何在 Ubuntu 中安装 FreeFileSync

我们会添加官方的 FreeFileSync PPA，这只在 Ubuntu 14.04 和 Ubuntu 15.10 上有，那么像这样更新系统仓库列表并安装它：

```
-------------- 在 Ubuntu 14.04 和 15.10 上 --------------
$ sudo apt-add-repository ppa:freefilesync/ffs
$ sudo apt-get update
$ sudo apt-get install freefilesync

```

对于 Ubuntu 16.04 或者更新的版本，进入 [FreeFileSync 的下载页](http://www.freefilesync.org/download.php)为你的 Ubuntu 和 Debian 获取合适的包。

接下来，进入下载文件夹，如下解压 FreeFileSync\_\*.tar.gz 到 `/opt` 目录中：

```
$ cd Downloads/
$ sudo tar xvf FreeFileSync_*.tar.gz -C /opt/
$ cd /opt/
$ ls
$ sudo unzip FreeFileSync/Resources.zip -d /opt/FreeFileSync/Resources/

```

下载我们会使用 Gnome 面板创建一个程序启动器（`.desktop` 文件）。要浏览系统中 `.desktop` 文件的例子，列出 `/usr/share/applications` 目录的内容：

```
$ ls /usr/share/applications

```

为防你没有安装 Gnome 面板，输入下面的命令来安装：

```
$ sudo apt-get install --no-install-recommends gnome-panel

```

接下来，运行下面的命令来创建程序启动器：

```
$ sudo gnome-desktop-item-edit /usr/share/applications/ --create-new

```

并定义下面的值：

```
Type:      Application
Name:      FreeFileSync
Command:   /opt/FreeFileSync/FreeFileSync
Comment:   Folder Comparison and Synchronization

```

要为启动器添加一个图标，只需要点击图标选择：`/opt/FreeFileSync/Resources/FreeFileSync.png`。

当你设置完成之后，点击 OK 创建。

![Create Desktop Launcher](/data/attachment/album/201706/08/060254dox95899b88ibpx4.png)

*创建桌面启动器*

如果你不想要创建桌面启动器，你可以从目录中启动 FreeFileSync。

```
$ ./FreeFileSync

```

### 如何在 Ubuntu 中使用 FreeFileSync

在 Ubuntu 中，在 Unity Dash 中搜索 FreeFileSync，然而在 Linux Mint 中，在 System Menu 中搜索，并点击 FreeFileSync 图标打开。

![FreeFileSync ](/data/attachment/album/201706/08/060256lsszsaxoops7xs6a.png)

*FreeFileSync*

#### 使用 FreeFileSync 比较两个文件夹

在下面的例子中，我们使用：

```
Source Folder:  /home/aaronkilik/bin
Destination Folder: /media/aaronkilik/J_CPRA_X86F/scripts

```

要比较文件时间以及两个文件夹的大小（默认设置），只要点击比较按钮。

![Compare Two Folders in Linux](/data/attachment/album/201706/08/060257irjz7zrdri2rajmd.png)

*在 Linux 中比较两个文件夹*

通过下面的界面，可以在两个文件夹中按 `F6` 来更改要比较的内容：文件时间和大小、内容或文件大小。请注意，你选择的每个选项的含义也包括在内。

![File Comparison Settings](/data/attachment/album/201706/08/060258lx2xawya32h2rx43.png)

*文件比较设置*

#### 使用 FreeFileSync 同步两个文件夹

你可以开始比较两个文件夹，接着点击 Synchronize 按钮启动同步进程。在之后出现的对话框中点击 Start：

```
Source Folder: /home/aaronkilik/Desktop/tecmint-files
Destination Folder: /media/aaronkilik/Data/Tecmint

```

![Compare and Synchronize Two Folders](/data/attachment/album/201706/08/060259vv74w8h9rv9v7hzr.png)

*比较以及同步两个文件夹*

![Start File Synchronization](/data/attachment/album/201706/08/060302ndisjesjkcukujce.png)

*开始文件同步*

![File Synchronization Completed](/data/attachment/album/201706/08/060303u33w7fzs7uvrrssg.png)

*文件同步完成*

在下面的界面中按下 `F8` 设置默认同步选项：two way、mirror、update 或 custom。每个选项的意义不言自明。

![File Synchronization Settings](/data/attachment/album/201706/08/060304vjkjj8jupzjppjqy.png)

*文件同步设置*

要了解更多信息，访问 FreeFileSync 主页：<http://www.freefilesync.org/>

就是这样了！在本篇中，我们向你展示了如何在 Ubuntu 以及它的衍生版 Linux Mint、Kubuntu 等等中安装 FreeFileSync。在下面的评论栏中分享你的想法。

---

作者简介：

Ravi Saive，TecMint 的原创作者。一个喜爱在互联网上分享技巧和提示的计算机 geek 和 Linux 老手。我的大多数服务运行在 Linux 开源平台上。请在 Twitter、Facebook、Google+ 上关注我。

---

via: <http://www.tecmint.com/freefilesync-compare-synchronize-files-in-ubuntu/>

作者：[Ravi Saive](http://www.tecmint.com/author/admin/) 译者：[geekpi](https://github.com/geekpi) 校对：[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


为什么每家企业都应该考虑使用开源的 POS 系统

开源pos系统，安装问题支持需要付费么？

“大量的社区开发者在开发新功能的同时也会检查并修复影响系统安全的各种漏洞。有那么多的程序员在分析和维护开源软件的源代码，这可比专有软件开发商对代码的审查要严格得多。因此，开源的 POS 系统实际上更安全。”现在还有人提这种观点？

抱有开源等于安全思维的人多了去了。

重点在于——“一个技术精湛的员工提供技术支持”

![Why every business should consider an open source point of sale system](/data/attachment/album/201706/08/061222jaee720c8xp8ppoe.png "Why every business should consider an open source point of sale system")

销售点终端 (POS) 系统是从很久以前的简单的收银机发展而来的。如今的 POS 系统可以提供一体化解决方案，包括支付流程、库存管理、营销工具等等。零售店也可以使用移动设备来接收现金流和各种成本支出相关的日报表。

POS 系统是每家企业重要的生命线，那就意味着你在选择 POS 系统的过程中要非常谨慎。目前可供选择的收银系统也很多，但是如果你想节约成本，适应不断变化的业务需求，跟上技术发展的脚步，你应该很明智地考虑使用开源系统。你可以随意使用一款源代码公开的开源 POS 系统，这比那些严格保密源代码的专有系统要有更大的优势。

使用开源的 POS 系统，你可以获得它的一些非常重要的特性。

### 无限的灵活性

开源系统与其它系统的兼容性非常好。它们与第三方厂家系统进行集成的能力——从帐务和客户关系管理软件（CRM）到订单管理和库存管理系统——使得当企业管理者想要扩展专有 POS 系统以外的其它功能时，开源系统具有更强大的优势。

在 [2014 年科技调查](http://hospitalitytechnology.edgl.com/news/POS-Integration-Becoming-a--Must-Have-94389) 活动中，很多餐厅管理者声称 POS 系统的功能集成度将会是他们考虑更换新系统的主要因素。这是开源系统最具亮点的一方面。专有系统买来什么样就是什么样，很难与其它厂家的系统进行集成。但是使用开源系统，你就可以进行无限的集成及定制功能。如果你觉得你们公司的商业模式会不断的增长和变化，那么只有考虑使用开源的 POS 系统才能根据需要实时调整系统。

### 更快的开发速度

开源系统的另外一个优势是它有很多的社区开发者提供技术支持，他们持续不断的提交新功能，并且优化原有的功能。由于这种特性，开源项目的开发周期要比商用产品快得多——修复缺陷的速度更快，更新升级也很快，并且新的功能模块也不断地被开发出来。

### 更低的成本

也就是说，“更低的成本”意味着“基本免费”。你还需要购买相关硬件产品，只是软件本身是免费使用的。开源 POS 系统不像专有 POS 系统那样在购买时或是后期维护过程中需要支付高昂的费用，其每年的维护费在 3000 至 50000 美元之间，而开源系统则不会像专有系统那样需要花钱来购买。

在 [2013 年版](https://pos.toasttab.com/restaurant-technology-industry-report/2015) 的餐饮行业技术服务调查研究过程中，有超过一半的受访餐厅老板表示他们从很多的技术产商购买服务——有些餐厅所面对的技术厂家多达 10 个。而使用纯粹的开源定制化系统不需要支付维护费用，这从节约成本上来说意义非常重大。

然而，有一点我还得提醒大家。如果你们公司没有一个技术精湛的员工提供技术支持，你可能还需要聘请外部技术人员来帮助你们安装，调试和升级系统。开源系统允许用户无限制地集成和定制化开发，但是你还需要有技术精湛的专家来支持才行，这也会产生额外的费用。尽管如此，开源系统仍然是一个非常具有成本效益的选择。

### 更好的安全性

如果任何人都可以看到源代码，那是不是也意味着它同样对那些怀有恶意并想入侵你系统的程序员开放呢？那不就是一个安全上的严重隐患吗？事实正好相反。

大量的社区开发者在开发新功能的同时也会检查并修复影响系统安全的各种漏洞。有那么多的程序员在分析和维护开源软件的源代码，这可比专有软件开发商对代码的审查要严格得多。因此，开源的 POS 系统实际上更安全。

有很多开源的 POS 系统解决方案可供选择，我列出一部分来：

* [Chromis](http://chromis.co.uk/)
* [Drupal POS](https://www.acromediainc.com/drupal-pos)
* [Floreant](http://floreant.org/)
* [Odoo](https://www.odoo.com/)
* [Open Source Point of Sale](https://github.com/jekkos/opensourcepos)
* [Unicenta](https://unicenta.com/)

### 勇敢地跨出第一步

你比其它人更了解你们公司。只有你能决定哪种开源系统最适合你们公司。由于开源 POS 系统比专有 POS 系统有更多亮丽的优点——灵活性、开发快速、低成本、更安全——因此，每个公司都应该考虑使用开源的 POS 系统。

（题图：opensource.com）

---

作者简介：

![](/data/attachment/album/201706/08/061222aaadamdwma2wrurj.jpg)

我是 AcroMedia 公司数字化市场营销项目经理。我们主要使用 Drupal 开源系统来为客户提供定制化商业解决方案。

---

via: <https://opensource.com/article/17/1/open-source-point-sale-system>

作者：[Preston Pilgrim](https://opensource.com/users/preston-pilgrim) 译者：[rusking](https://github.com/rusking) 校对：[Bestony](https://github.com/Bestony)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出