极客漫画:chown 与 chmod
chown
:Linux 中用来改变某个文件的属主的命令,如漫画中所示,将某个“资源”(门)的访问权限给予别人。
chmod
:Linux 中用来改变某个文件的访问模式的命令,如漫画中所示,chmod 777
会将“大门”敞开,谁都可以进出了。
via: http://turnoff.us/geek/chown-chmod/
作者:Daniel Stori 译者&点评:wxy
chown
:Linux 中用来改变某个文件的属主的命令,如漫画中所示,将某个“资源”(门)的访问权限给予别人。
chmod
:Linux 中用来改变某个文件的访问模式的命令,如漫画中所示,chmod 777
会将“大门”敞开,谁都可以进出了。
via: http://turnoff.us/geek/chown-chmod/
作者:Daniel Stori 译者&点评:wxy
本系列教程将引导你了解如何在 CentOS 7 安装 iRedMail 以及 Samba4 AD 域控制器,以便域帐户可以通过 Thunderbird 桌面客户端或通过 Roundcube Web 界面发送或接收邮件。
将要安装 iRedMail 的 CentOS 7 服务器需允许通过 25 和 587 端口进行 SMTP 或邮件路由服务,并且还将通过 Dovecot 作为邮件传递代理,提供 POP3 和 IMAP 服务,两者都使用安装过程中签发的自签名证书进行安全保护。
收件人邮箱将与 Roundcube 提供的 webmail 用户代理一起存储在同一台 CentOS 服务器上。iRedMail 将使用 Samba4 AD 来查询和验证收件人帐户,在 AD 组的帮助下创建邮件列表,并通过 Samba4 AD DC 控制邮件帐户。
1、 在安装 iRedMail 之前,请先确保你使用下面的指南在你的机器上安装了一个全新的 CentOS 7 操作系统:
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
验证 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 安装向导
11、 接下来,选择邮件存储的位置。iRedMail 默认邮箱的存储位置在 /var/vmail/
中。
如果这个目录所在的分区有足够的空间来保存你所有域帐户的邮件,接着点击 Next 来继续。
否则,如果你已经配置一个更大的分区来用于邮件存储,那么就用不同的目录来更改默认位置。
iRedMail 邮件存储路径
12、 在下一步中,选择要与 iRedMail 进行交互的前端 Web 服务器。今后将完全禁用 iRedMail 管理面板,因此我们将使用前端 Web 服务器仅通过 Roundcube Web 面板访问帐户邮件。
如果你每小时没有数以千计的邮件帐户访问 webmail 界面,那么你应该使用 Apache Web 服务器来实现其灵活性和易于管理。
iRedMail 首选的 Web 服务器
13、 在此步骤中,由于 Samba4 域控制器的兼容性原因,请选择 OpenLDAP 后端数据库,并点击 Next 继续,但是一旦将 iRedMail 集成到 Samba 域控制器中,我们将不再使用该 OpenLDAP 数据库。
iRedMail LDAP 后端
14、 接下来,如下图所示,为你的 Samba4 域名指定 LDAP 后缀,然后点击 Next 继续。
iRedMail LDAP 后缀
15、 在接下来的提示中,只要输入你的域名,并点击 Next 继续。相应地替换 tecmint.lan
值。
iRedMail 邮件域
16、 现在,为 [email protected]
管理员设置一个密码,并点击 Next 继续。
iRedMail 邮件域管理员
17、 接下来,从列表中选择要与邮件服务器集成的可选组件。我强烈建议你安装 Roundcube,以便为域帐户提供访问邮件的 Web 界面,尽管你也可以在不同的计算机上安装并配置 Roundcube,以便在高负载情况下释放邮件服务器资源。
对于受限访问互联网的本地域,特别是在我们使用域集成时,除了 Awstats 可以用于你进行邮件分析,其他组件不是非常有用。
iRedMail 可选组件
18、 在下一步中输入 Y
来应用配置并开始安装。
iRedMail 配置更改
19、 最后,所有的问题都输入 Y
,接受 iRedMail 脚本自动配置你的防火墙以及 MySQL 配置文件。
iRedMail 系统配置
20、 安装完成后,安装器会提供一些敏感信息。比如 iRedAdmin 凭证、web 面板的 URL 地址以及安装过程中使用的所有参数的文件位置。
iRedMail 安装总结
仔细阅读上面的信息,使用下面的命令重启机器来使所有的邮件服务启用。
# init 6
21、 系统重启后,使用 root 权限的帐户登录或以 root 身份登录,并使用下面的命令列出所有的网络套接字以及你邮件服务器监听的相关程序。
在套接字列表中,你会看到邮件服务器几乎覆盖邮件服务正常运行所需的所有服务:SMTP/S、POP3/S、IMAP/S 和防病毒以及垃圾邮件保护。
# netstat -tulpn
iRedMail 网络套接字
22、 为了查看 iRedMail 已修改的所有配置文件的位置、iRedMail 安装过程中用于数据库管理的凭据、邮件管理帐户以及其他帐户,那么就显示 iRedMail.tips
这个文件。
该文件位于你最初解压安装包的目录中。请注意,你应该移动并保护此文件,因为它包含有关邮件服务器的敏感信息。
# less iRedMail-0.9.6/iRedMail.tips
23、 上面提到的包含邮件服务器详细信息的文件也将自动发送到 postmaster 这个邮件服务器管理员帐户中。
通过在浏览器中输入机器的 IP 地址,你可以通过 HTTPS 协议安全地访问 webmail。接受 iRedMail 自签名证书在浏览器中生成的错误,并使用在安装中为 postmaster@your\_domain.tld 帐户设置的密码登录。阅读并将此电子邮件存储到一个安全的邮箱。
https://192.168.1.254
iRedMail 登录帐户
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 译者:geekpi 校对:wxy
简述:我是个 Mac 电脑重度用户,但我其实 对目前最新的 MacBook Pro 是失望的。由此我就开始去研究了下看是否有 一些可以替代前者(New MacBook Pro) 的选择。然而让我也意想不到的是,这居然使我产生了离开 Mac 平台的决定。
首先我们来看看 2017 年 CES(LCTT 译注:International Consumer Electronics Show,国际消费类电子产品展览会)大会后发布的 HP Spectre x360 13 寸笔记本电脑,拥有 4K 显示屏的新款笔记本电脑。我是从百思买(这不是一个赞助链接)买来的这款电脑,因为这是唯一售卖这款配置的零售商。我的目标是使用 Ubuntu 这个系统替代跑在这款笔记本上的 Windows 。
以下是我过去几个月使用这款笔记本的感受,还有一些在使用中对自己的使用习惯的重新认识。
安装 Ubuntu 还是很简单的。当时电脑到手的时候预装的是 Windows 10 的系统。当时我使用 Windows 内建的硬盘管理工具来 缩减主分区 并将剩余的空间分配给 Linux 系统。我 通过 USB 设备加载了 Ubuntu 系统镜像,这款笔记本能够很方便的适配 USB-A 接口(这在新版的 Mac 系列电脑是没有的)。然后我就按照 Ubuntu 的简便安装说明,将 BIOS 设置为 从 USB 启动。
Spectre x360 的 4k 显示屏简直令人惊艳。令我觉得吃惊的是,最新的 Ubuntu 系统在高 DPI 的屏幕上体验也是非常不错的。系统内建的设置工具配合 gnome-tweak-tool 这样的附加工具,你可以更好的控制用户界面在 4K 屏上的渲染,2 倍于原生大小的控件使得它们看起非常不错,你也可以将默认字体大小调整到一个合适的比例,甚至还可以调整窗口标题栏和任务管理器上的图标大小。虽然有点繁琐,但我自己设置时也没花多久时间。
实话说触控板有点细微的声音,但还是能够很不错的配合手指移动,Ubuntu 系统也默认支持多点触控。然而你会很快的发现你在打字的时候会误触触控板导致光标到处乱晃。在 Linux 上的默认 Synaptics 触控驱动并不能够很好的识别这款机型的手掌误触,解决方法是切换到 新的 libinput 系统,通过调整 xinput 设置 就可以让触控板工作的不错。
但我所习惯的手势操作,比如两指滑动回到 Chrome 浏览器,又或者说四指滑动切换工作区,这些操作在 Ubuntu 系统上就没法用了,或者实在想用可以通过 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 键盘布局 的那个夏天。
此款机型有四个扬声器:两个 B&O(Bang & Olufsen,音响制造商)扬声器在上部,两个在下部。上部的两个扬声器在 Ubuntu 系统中没法工作,这是一个 内核问题,尚未解决。下部的两个扬声器正常工作但声音有点小。耳机插孔使用正常,当插上耳机时扬声器也会自动静音。但我相信这可能是由于我为了让其他的硬件工作而将内核升级到了 4.10 测试版本 才出现的。我觉得社区最终会解决内核问题,所以上部扬声器无法工作的问题应该只是暂时性的。这些情况其实也就证明了为什么惠普公司自带的是带有一堆额外的神奇驱动的 Windows 系统。
电池续航的问题真的就很糟糕了,我想主要是因为 4k 显示屏太耗电了。此外我还发现了 CPU 散热风扇在高速运转使会从笔记本左侧的出风口吹出热风。这风热的程度如果你把它放到你的腿上会让你感觉很不舒服。我觉得这应该是 Ubuntu 的默认电源管理配置的缺陷。为了解决这个问题,你可以使用诸如 powertop 或者 pm-powersave 这样的工具。Intel 公司也提供 Linux 系统固件支持 来使 GPU 更好的工作。通过各种优化,我可以使电池续航能力接近 5 小时:和广告中宣传的 9 小时以上相去甚远。其实也有好的一点,使用 USB-C 接口充电速度快很多。这个接口也能很好的配合我得 Nexus X 手机充电,因为它们都是一样的接口。
惠普 Spectre x360 这款机型名字来源于它独特的设计,通过屏幕旋转可以变成一台平板电脑。变形后在 Ubuntu 系统上无需设置就可以完成点击、滚动和缩放操作。它甚至支持直接使用前进/后退手势操作,这些操作连它的触摸板也不支持。当你将它旋转为平板模式,键盘和触摸板会自动禁用。你可以将系统设置为 便携模式,Gnome 桌面键盘就会启用,体验还不错哦。比较糟糕的是不支持屏幕自动旋转,但我还是使用 iio-sensor-proxy 和 这个一次性脚本 东拼西凑地实现了这个功能。最后我虽然实现了这个功能,但是我发现使用 16:9 的屏幕好伤我的眼睛,当电脑处于平板电脑时候我需要使我的眼睛移动很长一段距离。
从 1998 年 RedHat 5.0 版开始我就不怎么常用 Linux 桌面版本了。时光飞逝,Ubuntu 发展迅猛,默认用户界面是他们自主研发的 Unity(Gnome 的变体),感觉还不错。我其实用过原生的 Gnome ,但它与别的桌面比较起来让我觉得非常的笨拙。我最后还是最喜欢 KDE,而且如果让我再次选择,我也会选择 KDE 的 Kubuntu。总体来说 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 系统就觉得被拖慢了很多,感觉好像我就要完蛋了。当我使用计算机的时候,我只希望花更多的时间在提高我的技术(编程、写作等等)上。我只希望我将我仅有的“再学习”能力使用在一些尚未明白和不熟悉的课题上,比如 新型函数式编程语言 和 同态加密 等等。我再也不想花更多的时间去学习什么基本使用方法了。
反过来说,我也曾花了超过 2 年时间去学习弹钢琴,弹钢琴需要我死记硬背和不断的机械性重复训练。当我在学习钢琴的时候我发现这个过程其实打开了我的思维,让我对曾经有了更深的理解。我对音乐的学习,也让我懂得了许多曾经没有理解的事。可以说,我对音乐的“再学习”打开了我的视野。所以,我也琢磨去适应惠普的硬件和 Linux 桌面系统会不会也对我有这样的影响。
最终说明,我还是固执的。可能以后吧,我也会需要去适应新的工作方式来让我保持最新的状态,就好像电报员终有一天一定会从摩斯电码转向去使用 电传打字机 一样。我希望到了未来的那天,我仍然会有耐心和远见让我平滑的过渡。可能,只有当这样东西会创造出更多的可能性,我才会选择那些需要“再学习”的东西,就好像一个为达到目的才去做的石蕊试验(测试液体酸碱度?)一样。至少目前来说,我还是会选择留在 Mac 下。
作者简介:
我是《Effective Python》一书的作者,我是一名软件工程师,我曾在谷歌工作了 11 年,我目前专注于调查统计,此外,我还曾在云计算基础设施建设和开放协议上有过工作经验。
以后,如果你还想阅读我写的文章,可以关注我的推 @haxor。如果你遇到什么问题,也可以写邮件给我,或者直接在下面写评论。如果你觉得这篇文章还不错,点击这里也可以看看我别的兴趣爱好。
via: http://www.onebigfluke.com/2017/04/discovering-my-inner-curmudgeon-linux.html
作者:Brett Slatkin 译者:kenxx 校对:wxy
Fuchsia 可能是下个会替代 Android 或 Chrome OS 的系统。猜测有很多,Jack Wallen 对此补充了一些给 Google 的赞誉和告诫。
Google 总是以 “Google” 的方式解决或者做某件事。因此,当他们开始做一个让很多人挠头的项目时,大家是不觉得奇怪的。该项目被称为 Fuschia,大多数密切关注 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 编写,跨越平台边界的想法就有了可能。
或者,也许 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 译者:geekpi 校对:jasminepeng
快速测试 - 下面的代码输出什么?
vals := make([]int, 5)
for i := 0; i < 5; i++ {
vals = append(vals, i)
}
fmt.Println(vals)
如果你猜测的是 [0 0 0 0 0 0 1 2 3 4]
,那你是对的。
等等,什么? 为什么不是 [0 1 2 3 4]
?
如果你在测试中做错了,你也不用担心。这是在过渡到 Go 语言的过程中相当常见的错误,在这篇文章中,我们将说明为什么输出不是你预期的,以及如何利用 Go 的细微差别来使你的代码更有效率。
在 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)
在代码中,我们有一个长度为 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])
我们仍然可以像数组一样访问我们的切片中的元素,但是通过使用切片和 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)
最后,我们最终得到 [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)
在这种情况下,我们设置的值恰好与我们要使用的索引相同,但是你也可以独立跟踪索引。
比如,如果你想要获取 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
}
这样做很好,因为我们知道我们返回的切片的长度将与 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
}
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
}
现在将此与相同的代码进行比较,但具有预定义的容量。
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
}
在第一个代码示例中,我们的容量从 0
开始,然后增加到 1
、 2
、 4
, 最后是 8
,这意味着我们不得不分配 5 次数组,最后一个容纳我们切片的数组的容量是 8
,这比我们最终需要的要大。
另一方面,我们的第二个例子开始和结束都是相同的容量(5
),它只需要在 keys()
函数的开头分配一次。我们还避免了浪费任何额外的内存,并返回一个能放下这个数组的完美大小的切片。
如前所述,我通常不鼓励任何人做这样的小优化,但如果最后大小的效果真的很明显,那么我强烈建议你尝试为切片设置适当的容量或长度。
这不仅有助于提高程序的性能,还可以通过明确说明输入的大小和输出的大小之间的关系来帮助澄清你的代码。
你好!我写了很多关于Go、Web 开发和其他我觉得有趣的话题。
如果你想跟上最新的文章,请注册我的邮件列表。我会给你发送我新书的样例、Go 的 Web 开发、以及每当有新文章(通常每周 1-2 次)会给你发送邮件。
哦,我保证不会发垃圾邮件。我像你一样讨厌它 :)
本文并不是对切片或数组之间差异的详细讨论,而是简要介绍了容量和长度如何影响切片,以及它们在方案中的用途。
为了进一步阅读,我强烈推荐 Go 博客中的以下文章:
作者简介:
Jon 是一名软件顾问,也是 《Web Development with Go》 一书的作者。在此之前,他创立了 EasyPost,一家 Y Combinator 支持的创业公司,并在 Google 工作。
via: https://www.calhoun.io/how-to-use-slice-capacity-and-length-in-go
作者:Jon Calhoun 译者:geekpi 校对:wxy
OTRS ,即开源 问题单 申请系统,是一个用于客户服务、帮助台和 IT 服务管理的开源问题单软件。该软件是用 Perl 和 javascript 编写的。对于那些需要管理票据、投诉、支持请求或其他类型的报告的公司和组织来说,这是一个问题单解决方案。OTRS 支持包括 MySQL、PostgreSQL、Oracle 和 SQL Server 在内的多个数据库系统,它是一个可以安装在 Windows 和 Linux 上的多平台软件。
在本教程中,我将介绍如何在 Ubuntu 16.04 上安装和配置 OTRS。我将使用 PostgreSQL 作为 OTRS 的数据库,将 Apache Web 服务器用作 Web 服务器。
先决条件
在第一步中,我们将安装 Apache Web 服务器以及 PostgreSQL。我们将从 ubuntu 仓库中使用最新的版本。
使用 SSH 登录到你的 Ubuntu 服务器中:
ssh [email protected]
更新 Ubuntu 仓库。
sudo apt-get update
使用 apt 安装 Apache2 以及 PostgreSQL:
sudo apt-get install -y apache2 libapache2-mod-perl2 postgresql
通过检查服务器端口确保 Apache 以及 PostgreSQL 运行了。
netstat -plntu
你可以看到 80 端口被 apache 使用了,5432 端口被 postgresql 数据库使用了。
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
你可以在 “Loaded Modules” 部分下看到 perl\_module。
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
OTRS 的新用户已经创建了。
在这节中,我们会为 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
使用 exit
回到 root 权限并重启 PostgreSQL:
exit
systemctl restart postgresql
PostgreSQL 已经为 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 已下载,并且我们的服务器可以安装 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”:
在本教程中,我们会使用样本数据库,这可以在脚本目录中找到。因此我们只需要将所有的样本数据库以及表结构导入到第 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
。
数据库以及 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 启动没有错误。
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
接下来,手动收取电子邮件的 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
OTRS 安装以及配置完成了。
打开你的 web 浏览器并输入你的服务器 IP 地址: http://192.168.33.14/otrs/
使用默认的用户 root@localhost
以及密码 root
登录。
使用默认的 root 账户你会看到一个警告。点击警告信息来创建一个新的 admin root 用户。
下面是用另外的 admin root 用户登录后出现的 admin 页面,这里没有出现错误信息。
如果你想作为客户登录,你可以使用 customer.pl
:http://192.168.33.14/otrs/customer.pl
你会看到客户登录界面,输入客户的用户名和密码。
下面是一个创建新单据的客户页面。
如果你仍旧看到 “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
作者:Muhammad Arul 译者:geekpi 校对:wxy