Merge pull request #39 from LCTT/master

更新 20201219
This commit is contained in:
FSSlc 2020-12-19 20:18:41 +08:00 committed by GitHub
commit 71ff532ae5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
443 changed files with 56754 additions and 9065 deletions

64
lctt2020.md Normal file
View File

@ -0,0 +1,64 @@
# Linux 中国旗下贡献者组织 LCTT 七年回顾和展望
> 这是一篇 LCTT 七周年的纪念文章,也是 LCTT 承前启后的一个里程碑。
### 写在 LCTT 七年之际
在 7 年前的今天,我并没有想到,在一个偶然的机会下诞生的 LCTT它能走过这么长的时间留下这么多的印痕。是的一些老朋友或许记得LCTT 这个 Linux 中国旗下的最主要的开源活动/组成部分,最初只是我发心想完善 man 的中文翻译而产生的副产品。结果man 中文翻译项目没有做成,而 LCTT 却持续地运营了下来。
虽然,这些年 LCTT 屡有改进和完善但是总体来说还是相对保守。当然LCTT 这些年已经陆续有 400 多位贡献者实质性的参与了贡献,并在此基础上创建了几个 SIG特别兴趣小组如[红帽代码英雄 SIG](https://linux.cn/article-12436-1.html)、漫画 SIG、LFS SIG 等。
作为回顾,我来介绍一下 LCTT 这 7 年间在主项目TranslateProject上取得的成就
- 贡献者: [435 位](https://linux.cn/lctt-list)
- 翻译文章:[5687 篇](https://linux.cn/)
- GitHub 提交:[54629 次](https://github.com/LCTT/TranslateProject)
- GitHub 拉取请求:[19243 次](https://github.com/LCTT/TranslateProject/pulls)
这是 LCTT 主项目的提交图:
![](https://postimg.aliavv.com/mbp/uglsc.png)
这其中,[钻石级的贡献者有 5 名,五星级贡献者有 6 名13 位 4 星贡献者](https://linux.cn/lctt-list)。那么,请让我来用一段视频展示一下 LCTT 七年来的历程:
![](https://img.linux.net.cn/static/video/LCTT%207%20Years.mp4)
当然,整体的贡献水平呈现长尾分布,大部分贡献者浅尝辄止,我想除了贡献者存在着体验的心态之外,也与 LCTT 没有建立起来合适的社区引导和激励机制有关。此外,就开源社区/开源项目而言,我们也存在一些不足,比如,按 GitHub 建议,我们在如下社区建设方面还缺乏:
- 社区行为准则
- 贡献指南
- 议题模板
- 拉取请求模板
因此,在写这篇文章时,我也要宣布一件事,就是我会逐渐淡出 LCTT 的日常管理,改组 LCTT 管理团队,将更多未来的可能交给社区成员来建设,也希望新的社区管理团队可以为 LCTT 创造出一个不同的明天。
以下,请我们的 Linux 中国的核心合伙人 Bestony 来介绍一下今后 LCTT 的发展计划。
---
大家好,我是 Bestony感谢老王数年来的坚持不懈的投入正是有老王的坚守才能有我们如今的成就。在接下来的时间里我将会帮助老王更好的运作 LCTT让老王可以喘口气也为 LCTT 带来一些新的气象。
在过去的七年里,我们 LCTT 做了很多事情,我们翻译了数千篇文章,有数百位技能精湛的贡献者。如今,到了 7 年的这个节点上,我也在思考,我们下一步应该怎么走。
其实在过去的一年里LCTT 的问题在不断的浮现:选题方向单一、译者进入门槛较高、大家翻译的质量水平参差不齐、校对的人手不足、译稿外发的反馈不足,这些问题都是我们在过去遇见,但一直没有足够的精力和人力来解决的问题。不过,如今我将加入到 LCTT 的管理团队中,配合老王,一起一个个的解决这些过去遇见的问题。
![](https://postimg.aliavv.com/mbp/3kfwy.png)
对于这些问题,有一些我们已经在解决,比如“**选题方向单一**”在今年的年初LCTT 与红帽公司RedHat[联合建立了 LCRH SIG](https://linux.cn/article-12436-1.html),面向红帽旗下的原创播客《<ruby>[代码英雄](https://www.redhat.com/en/command-line-heroes) <rt>Command Line Heroes</rt></ruby>》进行定向的翻译,目前,第一季度的翻译成功已经全部在 Linux 中国公众号上发布,而第二、三季度的内容,也正在不断的发布过程中。
![](https://postimg.aliavv.com/mbp/71eup.png)
LCTT - SIG 将是后续的新的发展方向。**我们将会在保留 LCTT 主体的基础上,鼓励各位译者探索更多的兴趣方向,通过建立起不同的 SIG引入更多的翻译内容来帮助大家更好的达成自己想要的翻译目标。** 并且,通过 LCTT 的技术和经验,赋能每一位译者,帮助译者更好的学习、了解各种不同领域的知识。
而在“**进入门槛较高**”方面,一直以来 Github 的访问慢问题、Git 的概念不熟悉等问题,都是困扰不少新同学的点。而也正是这些点,在不断制约着 LCTT 的发展。在将来,我希望 LCTT 可以打造出自己的翻译工具(也将会为之而奋斗),通过工具辅助的方式,帮助更多人走上翻译的道路,让更多的爱好者们,可以为中文的技术环境贡献一份力。
![](https://postimg.aliavv.com/mbp/8183e.png)
后续,我们将会引入翻译工具、自建关键词表、多轮校对手段等方案,帮助更多的译者完成自己的翻译文章,通过翻译,学到自己想要的知识。
当然,问题并不止我点出来的这些,我们能发展到今天,一定有很多做对了的地方,但同样,我们也有做错了的地方。欢迎你随时联系我,讨论你对于 LCTT 下一步的想法,我相信,你的意见能够帮助 LCTT 变得更好。
![](https://postimg.aliavv.com/mbp/aq5m9.png)
最后,**千里之行,始于足下**,刚刚走过 7 年的 LCTT 希望我们可以在下一个七年,再次相遇。

0
published/201610/20160812 What is copyleft.md Executable file → Normal file
View File

View File

View File

@ -0,0 +1,523 @@
[#]: collector: (lujun9972)
[#]: translator: (chenmu-kk)
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-12883-1.html)
[#]: subject: (Linux Desktop Setup · HookRace Blog)
[#]: via: (https://hookrace.net/blog/linux-desktop-setup/)
[#]: author: (Dennis Felsing http://felsin9.de/nnis/)
十年 Linux 桌面生存指南
======
![](https://img.linux.net.cn/data/attachment/album/202012/03/223817smrej5qwsbqjb3vs.jpg)
从 2006 年开始转战 Linux 系统后,经过几年的实践,我的软件设置在过去十年内出人意料的固定。再过十年回顾一下,看看发生了什么,也许会非常有趣。在写这篇推文时,我迅速回顾了正在运行的内容:
![htop overview][2]
### 动机
我的软件介绍排序不分先后:
* 程序应该运行在本地系统中以便我可以控制它,这其中并不包括云解决方案。
* 程序应在终端中运行,以便于在任何地方连贯地使用它们,包括性能稍差的电脑或手机。
* 通过使用终端软件,可以实现自动聚焦键盘。只有在一些有意义的地方,我会更喜欢使用鼠标,因为在打字期间一直伸手去拿鼠标感觉像在浪费时间。有时候过了一个小时我才注意到甚至还没有插鼠标。
* 最好使用快速高效的软件,我不喜欢听到风扇的声音和感到房间在变热。我还可以继续长久地运行旧硬件,已经使用了 10 年的 Thinkpad x200s 还能很好地支持我所使用的软件。
* 组合。我不想手动执行每个步骤,而是在需要时自动执行更多操作,这时自然是支持 shell。
### 操作系统
十二年前移除 Windows 系统后,我在 Linux 系统上经历了一个艰难的开始,当时我手上只有 [Gentoo Linux][3] 系统的安装光盘和一本打印的说明书,要用它们来实现一个可运行的 Linux 系统。虽然花费了几天的时间去编译和修整,但最终还是觉得自己受益颇多。
自此我再也没有转回 Windows 系统,但在持续的编译压力导致风扇失灵后,我将我的电脑系统切换到 [Arch Linux][4]。之后我将其他的电脑和私人服务器也切换到了 Arch Linux。作为一个滚动发布发行版你可以随时升级软件包但 [Arch Linux News][5] 已经详细报道了其中最主要的漏洞。
不过令人烦恼的是一旦你更新了旧的内核模组Arch Linux 就会移除旧版的相关信息。我经常注意到一旦我试着插入一个 USB 闪存盘,内核就无法加载相关组件。相反,每次内核升级后都应该进行重启。有一些 [方法][6] 可以解决这个问题,但我还没有实际地使用它们。
其他程序也会出现类似的情况,通常 Firefox 、 cron 或者 Samba 在升级后都需要重启,但恼人的是,它们没有警告你存在这种情况。我在工作中使用的 [SUSE][7] 很好地提醒了这种情况。
对于 [DDNet][8] 产品服务器,相较于 Arch Linux ,我更倾向于 [Debian][9] 系统,这样在每次升级时出现故障的几率更低。我的防火墙和路由器使用了 [OpenBSD][10] ,它拥有干净系统、文档和强大的 [pf 防火墙][11],而我现在不需要一个单独的路由器。
### 窗口管理器
从我开始使用 Gentoo 后,我很快注意到 KDE 的编译时间非常长,这让我没办法继续使用它。我四处寻找更简单的解决方案,最初使用了 [Openbox][12] 和 [Fluxbox][13]。某次,为了能更多进行纯键盘操作,我开始尝试转入平铺窗口管理器,并在研究其初始版本的时候学习了 [dwm][14] 和 [awesome][15]。
最终,由于 [xmonad][16]的灵活性、可扩展性以及使用纯 [Haskell][17](一种出色的函数编程语言)编写和配置,最终选择了它。一个例子是,我在家中运行一个 40" 4K 的屏幕,但经常会将它分为四个虚拟屏幕,每个虚拟屏幕显示一个工作区,每个工作区自动排列在我的窗口上。当然, xmonad 有一个对应的 [模块][18]。
[dzen][19] 和 [conky][20] 对我来说是一个非常简单的状态栏。我的整体 conky 配置看起来是这样的:
```
out_to_console yes
update_interval 1
total_run_times 0
TEXT
${downspeed eth0} ${upspeed eth0} | $cpu% ${loadavg 1} ${loadavg 2} ${loadavg 3} $mem/$memmax | ${time %F %T}
```
输入命令直接通过管道输入 dzen2
```
conky | dzen2 -fn '-xos4-terminus-medium-r-normal-*-12-*-*-*-*-*-*-*' -bg '#000000' -fg '#ffffff' -p -e '' -x 1000 -w 920 -xs 1 -ta r
```
对我而言,一项重要功能是在完成工作后使终端发出蜂鸣声。只需要简单地在 zsh 中的 `PR_TITLEBAR` 变量中添加一个 `\a` 字符就可以做到,只要工作完成就可以发出蜂鸣声。当然,我使用了命令:
```
echo "blacklist pcspkr" > /etc/modprobe.d/nobeep.conf
```
`pcspkr` 内核模块列入黑名单来禁用实际的蜂鸣声。相反 urxvt 的 `URxvt.urgentOnBell: true` 设置会将声音变为尖锐。之后 xmonad 有一个 urgency 钩子来捕捉这类信号,并且我可以使用组合键自动聚焦到当前的发出紧急信号的窗口。在 dzen 中我可以看到一个漂亮且明亮的 `#ff0000` 紧急窗口。
在我笔记本上所得到的最终成品是:
![Laptop screenshot][22]
我听说前几年 [i3][23] 变得非常流行,但它要求更多的手动窗口对齐而不是自动对齐。
我意识到也有像 [tmux][24] 那样的终端多路复用器,但我仍想要一些图形化应用程序,因此最终我没有有效地使用它们。
### 终端连续性
为了使终端保持活跃状态,我使用了 [dtach][25] ,它只是模拟屏幕分离功能。为了使计算机上的每个终端都可连接和断开,我编写了一个小的封装脚本。 这意味着,即使必须重新启动 X 服务器,我也可以使所有终端都运行良好,包括本地和远程终端。
### Shell & 编程
对于 shell我使用 [zsh][28] 而不是 [bash][27],因为它有众多的功能。
作为终端模拟,我发现 [urxvt][29] 足够轻巧,支持 Unicode 编码和 256 色,具有出色的性能。另一个重要的功能是可以分别运行 urxvt 客户端和守护进程。因此,即使大量终端也几乎不占用任何内存(回滚缓冲区除外)。
对我而言,只有一种字体看起来绝对干净和完美: [Terminus][30]。 由于它是位图字体,因此所有内容都是完美像素,渲染速度极快且 CPU 使用率低。为了能使用 `CTRL-WIN-[1-7]` 在每个终端按需切换字体,我的 `~/.Xdefaults` 包含:
```
URxvt.font: -xos4-terminus-medium-r-normal-*-14-*-*-*-*-*-*-*
dzen2.font: -xos4-terminus-medium-r-normal-*-14-*-*-*-*-*-*-*
URxvt.keysym.C-M-1: command:\033]50;-xos4-terminus-medium-r-normal-*-12-*-*-*-*-*-*-*\007
URxvt.keysym.C-M-2: command:\033]50;-xos4-terminus-medium-r-normal-*-14-*-*-*-*-*-*-*\007
URxvt.keysym.C-M-3: command:\033]50;-xos4-terminus-medium-r-normal-*-18-*-*-*-*-*-*-*\007
URxvt.keysym.C-M-4: command:\033]50;-xos4-terminus-medium-r-normal-*-22-*-*-*-*-*-*-*\007
URxvt.keysym.C-M-5: command:\033]50;-xos4-terminus-medium-r-normal-*-24-*-*-*-*-*-*-*\007
URxvt.keysym.C-M-6: command:\033]50;-xos4-terminus-medium-r-normal-*-28-*-*-*-*-*-*-*\007
URxvt.keysym.C-M-7: command:\033]50;-xos4-terminus-medium-r-normal-*-32-*-*-*-*-*-*-*\007
URxvt.keysym.C-M-n: command:\033]10;#ffffff\007\033]11;#000000\007\033]12;#ffffff\007\033]706;#00ffff\007\033]707;#ffff00\007
URxvt.keysym.C-M-b: command:\033]10;#000000\007\033]11;#ffffff\007\033]12;#000000\007\033]706;#0000ff\007\033]707;#ff0000\007
```
对于编程和书写,我使用 [Vim][31] 语法高亮显示和 [ctags][32] 进行索引,以及一些带有 `grep` 、`sed` 和其他用于搜索和操作的常用终端窗口。这可能不像 IDE 那样舒适,但可以实现更多的自动化。
Vim 的一个问题是你已经习惯了它的键映射,因此希望在任何地方都使用它们。
在 shell 功能不够强大时,[Python][33] 和 [Nim][34] 作为脚本语言也不错。
### 系统监控
[htop][35] (查看当前站点的后台运行,是托管服务器的实时视图)非常适合快速了解软件的当前运行状态。 [lm_sensors][36] 可以监控硬件温度、风扇和电压。 [powertop][37] 是一款由 Intel 发布的优秀省电小工具。 [ncdu][38] 可以交互式分析磁盘使用情况。
[nmap][39]、 iptraf-ng、 [tcpdump][40] 和 [Wireshark][41] 都是分析网络问题的基本工具。
当然还有很多更优秀的工具。
### 邮件 & 同步
在我的家庭服务器上,我为自己所有的邮箱账号运行了 [fetchmail][42] 守护进程。fetchmail 只是检索收到的邮件并调用 [procmail][43]
```
#!/bin/sh
for i in /home/deen/.fetchmail/*; do
FETCHMAILHOME=$i /usr/bin/fetchmail -m 'procmail -d %T' -d 60
done
```
配置非常简单,然后等待服务器通知我们有新的邮件:
```
poll imap.1und1.de protocol imap timeout 120 user "dennis@felsin9.de" password "XXX" folders INBOX keep ssl idle
```
我的 `.procmailrc` 配置包含一些备份全部邮件的规则,并将邮件整理在对应的目录下面。例如,基于邮件列表名或者邮件标题:
```
MAILDIR=/home/deen/shared/Maildir
LOGFILE=$HOME/.procmaillog
LOGABSTRACT=no
VERBOSE=off
FORMAIL=/usr/bin/formail
NL="
"
:0wc
* ! ? test -d /media/mailarchive/`date +%Y`
| mkdir -p /media/mailarchive/`date +%Y`
# Make backups of all mail received in format YYYY/YYYY-MM
:0c
/media/mailarchive/`date +%Y`/`date +%Y-%m`
:0
* ^From: .*(.*@.*.kit.edu|.*@.*.uka.de|.*@.*.uni-karlsruhe.de)
$MAILDIR/.uni/
:0
* ^list-Id:.*lists.kit.edu
$MAILDIR/.uni-ml/
[...]
```
我使用 [msmtp][44] 来发送邮件,它也很好配置:
```
account default
host smtp.1und1.de
tls on
tls_trust_file /etc/ssl/certs/ca-certificates.crt
auth on
from dennis@felsin9.de
user dennis@felsin9.de
password XXX
[...]
```
但是到目前为止,邮件还在服务器上。 我的文档全部存储在一个目录中,我使用 [Unison][45] 在所有计算机之间进行同步。Unison 可以视为双向交互式 [rsync][46],我的邮件是这个文件目录下的一部分,因此它们最终存储在我的电脑上。
这也意味着,尽管邮件会立即到达我的邮箱,但我只是按需拿取,而不是邮件一到达时就立即收到通知。
从此我使用 [mutt][47] 阅读邮件,使用侧边栏显示我的邮件目录。 `/etc/mailcap` 文件对于显示非纯文本邮件( HTML, Word 或者 PDF不可或缺
```
text/html;w3m -I %{charset} -T text/html; copiousoutput
application/msword; antiword %s; copiousoutput
application/pdf; pdftotext -layout /dev/stdin -; copiousoutput
```
### 新闻 & 通讯
[Newsboat][48] 是一个非常棒的终端 RSS/Atom 阅读器。我在一个有约 150 个提要的 `tach` 会话服务器上运行它。也可以在本地选择提要,例如:
```
ignore-article "https://forum.ddnet.tw/feed.php" "title =~ \"Map Testing •\" or title =~ \"Old maps •\" or title =~ \"Map Bugs •\" or title =~ \"Archive •\" or title =~ \"Waiting for mapper •\" or title =~ \"Other mods •\" or title =~ \"Fixes •\""
```
我以同样的方式使用 [Irssi][49] 进行 IRC 通讯。
### 日历
[remind][50] 是一个可以从命令行获取的日历。通过编辑 `rem` 文件可以设置新的提醒:
```
# One time events
REM 2019-01-20 +90 Flight to China %b
# Recurring Holidays
REM 1 May +90 Holiday "Tag der Arbeit" %b
REM [trigger(easterdate(year(today()))-2)] +90 Holiday "Karfreitag" %b
# Time Change
REM Nov Sunday 1 --7 +90 Time Change (03:00 -> 02:00) %b
REM Apr Sunday 1 --7 +90 Time Change (02:00 -> 03:00) %b
# Birthdays
FSET birthday(x) "'s " + ord(year(trigdate())-x) + " birthday is %b"
REM 16 Apr +90 MSG Andreas[birthday(1994)]
# Sun
SET $LatDeg 49
SET $LatMin 19
SET $LatSec 49
SET $LongDeg -8
SET $LongMin -40
SET $LongSec -24
MSG Sun from [sunrise(trigdate())] to [sunset(trigdate())]
[...]
```
遗憾的是,目前 remind 中还没有中国农历的提醒功能,因此中国的节日不易计算。
我给提醒设置了两个名字:
```
rem -m -b1 -q -g
```
按时间顺序查看待办事项清单
```
rem -m -b1 -q -cuc12 -w$(($(tput cols)+1)) | sed -e "s/\f//g" | less
```
显示适应终端宽度的日历:
![remcal][51]
### 字典
[rdictcc][52] 是鲜为人知的字典工具,它可以使用 [dict.cc][53] 很棒的词典并将他们转存在本地数据库中:
```
$ rdictcc rasch
====================[ A => B ]====================
rasch:
- apace
- brisk [speedy]
- cursory
- in a timely manner
- quick
- quickly
- rapid
- rapidly
- sharpish [Br.] [coll.]
- speedily
- speedy
- swift
- swiftly
rasch [gehen]:
- smartly [quickly]
Rasch {n} [Zittergras-Segge]:
- Alpine grass [Carex brizoides]
- quaking grass sedge [Carex brizoides]
Rasch {m} [regional] [Putzrasch]:
- scouring pad
====================[ B => A ]====================
Rasch model:
- Rasch-Modell {n}
```
### 记录和阅读
我有一个简单记录任务的备忘录,在 Vim 会话中基本上一直处于打开状态。我也使用备忘录作为工作中“已完成”工作的记录,这样就可以检查自己每天完成了哪些任务。
对于写文件、信件和演示文稿,我会使用 [LaTeX][54] 进行高级排版。德式的简单信件可以这样设置,例如:
```
\documentclass[paper = a4, fromalign = right]{scrlttr2}
\usepackage{german}
\usepackage{eurosym}
\usepackage[utf8]{inputenc}
\setlength{\parskip}{6pt}
\setlength{\parindent}{0pt}
\setkomavar{fromname}{Dennis Felsing}
\setkomavar{fromaddress}{Meine Str. 1\\69181 Leimen}
\setkomavar{subject}{Titel}
\setkomavar*{enclseparator}{Anlagen}
\makeatletter
\@setplength{refvpos}{89mm}
\makeatother
\begin{document}
\begin{letter} {Herr Soundso\\Deine Str. 2\\69121 Heidelberg}
\opening{Sehr geehrter Herr Soundso,}
Sie haben bei mir seit dem Bla Bla Bla.
Ich fordere Sie hiermit zu Bla Bla Bla auf.
\closing{Mit freundlichen Grüßen}
\end{letter}
\end{document}
```
在 [我的私人网站][55] 上可以找到更多的示例文档和演示文稿。
[Zathura][56] 读取 PDF 文件速度很快,支持 Vim 类控件,还支持两种不同的 PDF 后端: Poppler 和 MuPDF。另一方面在偶尔遇到 Zathura 无法打开的文件时,[Evince][57] 则显得更全能一些。
### 图片编辑
简便的选择是,[GIMP][58] 和 [Inkscape][59] 分别用于照片编辑和交互式向量图形。
有时 [Imagemagick][60] 已经足够好了,它可以从命令行直接使用,从而自动编辑图片。同样 [Graphviz][61] 和 [TikZ][62] 可以用来绘制曲线图和其他图表。
### Web 浏览器
对于 Web 浏览器,我一直在使用 [Firefox][63]。相较于 Chrome它的可扩展性更好资源使用率更低。
不幸的是,在 Firefox 完全改用 Chrome 风格的扩展之后, [Pentadactyl][64] 扩展的开发就停止了,所以我的浏览器中再也没有令人满意的 Vim 类控件了。
### 媒体播放器
通过设置 `vo=gpu` 以及 `hwdec=vaapi`,具有硬件解码功能的 [mpv][65] 在播放期间 CPU 的占用率保持在 5%。相较于默认的 PulseAudiompv 中的 `audio-channels=2` 似乎可以使我的立体扬声器/耳机获得更清晰的降级混频。一个很棒的小功能是用 `Shift-Q` 退出,而不是只用 `Q` 来保存回放位置。当你与母语是其他语言的人一起看视频时,你可以使用 `--secondary-sid=` 同时显示两种字幕,主字幕位于底部,次字幕位于屏幕顶部。
我的无线鼠标可以简单地通过一个小的配置文件( `~/.config/mpv/input.conf` )实现远程控制 mpv
```
MOUSE_BTN5 run "mixer" "pcm" "-2"
MOUSE_BTN6 run "mixer" "pcm" "+2"
MOUSE_BTN1 cycle sub-visibility
MOUSE_BTN7 add chapter -1
MOUSE_BTN8 add chapter 1
```
[youtube-dl][66] 非常适合观看在线托管的视频,使用 `-f bestvideo+bestaudio/best --all-subs --embed-subs` 命令可获得最高质量的视频。
作为音乐播放器, [MOC][67] 不再活跃开发,但它仍是一个简易的播放器,可以播放各种可能的格式,包括最不常用的 Chiptune 格式。在 AUR 中有一个 [补丁][68] 增加了 PulseAudio 支持。即使在 CPU 时钟频率降到 800 MHz MOC 也只使用了单核 CPU 的 1-2% 。
![moc][69]
我的音乐收藏夹保存在我的家庭服务器上,因此我可以从任何地方访问它。它使用 [SSHFS][70] 挂载并自动安装在 `/etc/fstab/` 目录下:
```
root@server:/media/media /mnt/media fuse.sshfs noauto,x-systemd.automount,idmap=user,IdentityFile=/root/.ssh/id_rsa,allow_other,reconnect 0 0
```
### 跨平台构建
除了 Linux 本身,它对于构建任何主流操作系统的软件包都很优秀! 一开始,我使用 [QEMU][71] 与旧版 Debian、 Windows 以及 Mac OS X VM 一起构建这些平台。
现在我在旧版 Debian 发行版上转而使用 chroot (以获得最大的 Linux 兼容性),在 Windows 上使用 [MinGW][72] 进行交叉编译,在 Mac OS X 上则使用 [OSXCross][73]。
用于 [构建 DDNet][74] 的脚本以及 [更新库构建的说明][75] 的脚本都基于这个。
### 备份
通常,我们都会忘记备份。即使这是最后一节,它也不应该成为事后诸葛。
十年前我写了 [rrb][76] (反向 rsync 备份)重新封装了 `rsync` ,因此我只需要将备份服务器的 root SSH 权限授予正在备份的计算机。令人惊讶地是,尽管我一直在使用 rrb ,但它在过去十年里没有任何改变。
备份文件直接存储在文件系统中。使用硬链接实现增量备份(`--link-dest`)。一个简单的 [配置][77] 定义了备份保存时间,默认为:
```
KEEP_RULES=( \
7 7 \ # One backup a day for the last 7 days
31 8 \ # 8 more backups for the last month
365 11 \ # 11 more backups for the last year
1825 4 \ # 4 more backups for the last 5 years
)
```
因为我的一些计算机没有静态 IP / DNS 但仍想使用 rrb 备份,那我会使用反向安全隧道(作为 systemd 服务):
```
[Unit]
Description=Reverse SSH Tunnel
After=network.target
[Service]
ExecStart=/usr/bin/ssh -N -R 27276:localhost:22 -o "ExitOnForwardFailure yes" server
KillMode=process
Restart=always
[Install]
WantedBy=multi-user.target
```
现在,隧道运行备份时,服务器可以通过 `ssh -p 27276 localhost` 命令或者使用 `.ssh/config` 到达服务器端。
```
Host cr-remote
HostName localhost
Port 27276
```
在谈及 SSH 技巧时,有时由于某些中断的路由会很难访问到服务器。在那种情况下你可以借道其他服务器的 SSH 连接,以获得更好的路由。在这种情况下,你可能通过美国连接访问到我的中国服务器,而来自德国的不可靠连接可能需要几个周:
```
Host chn.ddnet.tw
ProxyCommand ssh -q usa.ddnet.tw nc -q0 chn.ddnet.tw 22
Port 22
```
### 结语
感谢阅读我工具的收藏。这其中我也许遗漏了许多日常中自然成习惯的步骤。让我们来看看我的软件设置在下一年里能多稳定吧。如果你有任何问题,随时联系我 [dennis@felsin9.de][78] 。
在 [Hacker News][79] 下评论吧。
--------------------------------------------------------------------------------
via: https://hookrace.net/blog/linux-desktop-setup/
作者:[Dennis Felsing][a]
选题:[lujun9972][b]
译者:[chenmu-kk](https://github.com/chenmu-kk)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: http://felsin9.de/nnis/
[b]: https://github.com/lujun9972
[1]: https://hookrace.net/public/linux-desktop/htop_small.png
[2]: https://hookrace.net/public/linux-desktop/htop.png
[3]: https://gentoo.org/
[4]: https://www.archlinux.org/
[5]: https://www.archlinux.org/news/
[6]: https://www.reddit.com/r/archlinux/comments/4zrsc3/keep_your_system_fully_functional_after_a_kernel/
[7]: https://www.suse.com/
[8]: https://ddnet.tw/
[9]: https://www.debian.org/
[10]: https://www.openbsd.org/
[11]: https://www.openbsd.org/faq/pf/
[12]: http://openbox.org/wiki/Main_Page
[13]: http://fluxbox.org/
[14]: https://dwm.suckless.org/
[15]: https://awesomewm.org/
[16]: https://xmonad.org/
[17]: https://www.haskell.org/
[18]: http://hackage.haskell.org/package/xmonad-contrib-0.15/docs/XMonad-Layout-LayoutScreens.html
[19]: http://robm.github.io/dzen/
[20]: https://github.com/brndnmtthws/conky
[21]: https://hookrace.net/public/linux-desktop/laptop_small.png
[22]: https://hookrace.net/public/linux-desktop/laptop.png
[23]: https://i3wm.org/
[24]: https://github.com/tmux/tmux/wiki
[25]: http://dtach.sourceforge.net/
[26]: https://github.com/def-/tach/blob/master/tach
[27]: https://www.gnu.org/software/bash/
[28]: http://www.zsh.org/
[29]: http://software.schmorp.de/pkg/rxvt-unicode.html
[30]: http://terminus-font.sourceforge.net/
[31]: https://www.vim.org/
[32]: http://ctags.sourceforge.net/
[33]: https://www.python.org/
[34]: https://nim-lang.org/
[35]: https://hisham.hm/htop/
[36]: http://lm-sensors.org/
[37]: https://01.org/powertop/
[38]: https://dev.yorhel.nl/ncdu
[39]: https://nmap.org/
[40]: https://www.tcpdump.org/
[41]: https://www.wireshark.org/
[42]: http://www.fetchmail.info/
[43]: http://www.procmail.org/
[44]: https://marlam.de/msmtp/
[45]: https://www.cis.upenn.edu/~bcpierce/unison/
[46]: https://rsync.samba.org/
[47]: http://www.mutt.org/
[48]: https://newsboat.org/
[49]: https://irssi.org/
[50]: https://www.roaringpenguin.com/products/remind
[51]: https://hookrace.net/public/linux-desktop/remcal.png
[52]: https://github.com/tsdh/rdictcc
[53]: https://www.dict.cc/
[54]: https://www.latex-project.org/
[55]: http://felsin9.de/nnis/research/
[56]: https://pwmt.org/projects/zathura/
[57]: https://wiki.gnome.org/Apps/Evince
[58]: https://www.gimp.org/
[59]: https://inkscape.org/
[60]: https://imagemagick.org/Usage/
[61]: https://www.graphviz.org/
[62]: https://sourceforge.net/projects/pgf/
[63]: https://www.mozilla.org/en-US/firefox/new/
[64]: https://github.com/5digits/dactyl
[65]: https://mpv.io/
[66]: https://rg3.github.io/youtube-dl/
[67]: http://moc.daper.net/
[68]: https://aur.archlinux.org/packages/moc-pulse/
[69]: https://hookrace.net/public/linux-desktop/moc.png
[70]: https://github.com/libfuse/sshfs
[71]: https://www.qemu.org/
[72]: http://www.mingw.org/
[73]: https://github.com/tpoechtrager/osxcross
[74]: https://github.com/ddnet/ddnet-scripts/blob/master/ddnet-release.sh
[75]: https://github.com/ddnet/ddnet-scripts/blob/master/ddnet-lib-update.sh
[76]: https://github.com/def-/rrb/blob/master/rrb
[77]: https://github.com/def-/rrb/blob/master/config.example
[78]: mailto:dennis@felsin9.de
[79]: https://news.ycombinator.com/item?id=18979731

View File

@ -0,0 +1,103 @@
[#]: collector: (lujun9972)
[#]: translator: (robsean)
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-12891-1.html)
[#]: subject: (Dual booting Windows and Linux using UEFI)
[#]: via: (https://opensource.com/article/19/5/dual-booting-windows-linux-uefi)
[#]: author: (Alan Formy-Duval https://opensource.com/users/alanfdoss/users/ckrzen)
使用 UEFI 双启动 Windows 和 Linux
======
> 这是一份在同一台机器上设置 Linux 和 Windows 双重启动的速成解释使用统一可扩展固件接口UEFI
![](https://img.linux.net.cn/data/attachment/album/202012/06/101431eb02wvkk0nzkk5sw.jpg)
我将强调一些重要点,而不是一步一步地指导你来如何配置你的系统以实现双重启动。作为一个示例,我将提到我在几个月之前新买的笔记本计算机。我先是安装 [Ubuntu Linux][2] 到整个硬盘中,这就摧毁了预装的 [Windows 10][3] 环境。几个月后,我决定安装一个不同的 Linux 发行版 [Fedora Linux][4],也决定在双重启动配置中与它一起再次安装 Windows 10 。我将强调一些极其重要的实际情况。让我们开始吧!
### 固件
双重启动不仅仅是软件问题。或者说它算是软件的问题,因为它需要更改你的固件,以告诉你的机器如何开始启动程序。这里有一些和固件相关的重要事项要铭记于心。
#### UEFI vs BIOS
在尝试安装前,确保你的固件配置是最佳的。现在出售的大多数计算机有一个名为 <ruby>[统一可扩展固件接口][5]<rt>Unified Extensible Firmware Interface</rt></ruby> UEFI的新类型固件UEFI 差不多取代了另一个名为 <ruby>[基本输入输出系统][6]<rt>Basic Input Output System</rt></ruby>BIOS的固件类型包括很多固件供应商在内的很多人通常称 BIOS 为<ruby>传统启动模式<rt>Legacy Boot</rt></ruby>
我不需要 BIOS所以我选择了 UEFI 模式。
#### 安全启动
另一个重要的设置是<ruby>安全启动<rt>Secure Boot</rt></ruby>。这个功能将检测启动路径是否被篡改,并阻止未经批准的操作系统的启动。现在,我禁用这个选项来确保我能够安装 Fedora Linux 。依据 Fedora 项目维基“[功能/安全启动][7]”部分的介绍可知Fedora Linux 在安全启动选项启用的时候也可以工作。这对其它的 Linux 发行版来说可能有所不同 — 我打算今后重新研究这项设置。
简而言之,如果你发现在这项设置启用时你不能安装你的 Linux 操作系统,那么禁用安全启动并再次重新尝试安装。
### 对启动驱动器进行分区
如果你选择双重启动并且两个操作系统都在同一个驱动器上,那么你必须将它分成多个分区。即使你使用两个不同的驱动器进行双重启动,出于各种各样的原因,大多数 Linux 环境也最好分成几个基本的分区。这里有一些选项值得考虑。
#### GPT vs MBR
如果你决定手动分区你的启动驱动器,在动手前,我建议使用<ruby>[GUID 分区表][8]<rt>GUID Partition Table</rt></ruby>GPT而不是使用旧的<ruby>[主启动记录][9]<rt>Master Boot Record</rt></ruby>MBR 。这种更改的原因之一是MBR 有两个特定的限制,而 GPT 却没有:
* MBR 可以最多拥有 15 个分区,而 GPT 可以最多拥有 128 个分区。
* MBR 最多仅支持 2 TB 磁盘,而 GPT 使用 64 位地址,这使得它最多支持 800 万 TB 的磁盘。
如果你最近购买过硬盘,那么你可能会知道现代的很多硬盘都超过了 2 TB 的限制。
#### EFI 系统分区
如果你正在进行一次全新的安装或使用一块新的驱动器,那么这里可能没有可以开始的分区。在这种情况下,操作系统安装程序将先创建一个分区,即<ruby>[EFI 系统分区][10]<rt>EFI System Partition</rt></ruby>ESP。如果你选择使用一个诸如 [gdisk][11] 之类的工具来手动分区你的驱动器,你将需要使用一些参数来创建这个分区。基于现有的 ESP ,我设置它为约 500 MB 的大小,并分配它为 `ef00` EFI 系统 分区类型。UEFI 规范要求格式化为 FAT32/msdos ,很可能是因为这种格式被大量的操作系统所支持。
![分区][12]
### 操作系统安装
在你完成先前的两个任务后,你就可以安装你的操作系统了。虽然我在这里关注的是 Windows 10 和 Fedora Linux ,当安装其它组合时的过程也是非常相似。
#### Windows 10
我开始 Windows 10 的安装,并创建了一个 20 GB 的 Windows 分区。因为我先前在我的笔记本计算机上安装了 Linux ,所以驱动器已经有了一个 ESP ,我选择保留它。我删除所有的现有 Linux 和交换分区来开始一次全新安装,然后开始我的 Windows 安装。Windows 安装程序自动创建另一个 16 MB 的小分区,称为 <ruby>[微软保留分区][13]<rt>Microsoft Reserved Partition</rt></ruby>MSR。在这完成后在 512 GB 启动驱动器上仍然有大约 400 GB 的未分配空间。
接下来,我继续完成了 Windows 10 安装过程。随后我重新启动到 Windows 来确保它是工作的,在操作系统第一次启动时,创建我的用户账号,设置 Wi-Fi ,并完成其它必须的任务。
#### Fedora Linux
接下来,我将心思转移到安装 Linux 。我开始了安装过程,当安装进行到磁盘配置的步骤时,我确保不会更改 Windows NTFS 和 MSR 分区。我也不会更改 ESP ,但是我设置它的挂载点为 `/boot/efi`。然后我创建常用的 ext4 格式分区, `/`(根分区)、`/boot` 和 `/home`。我创建的最后一个分区是 Linux 的交换分区swap
像安装 Windows 一样,我继续完成了 Linux 安装,随后重新启动。令我高兴的是,在启动时<ruby>[大一统启动加载程序][14]<rt>GRand Unified Boot Loader</rt></ruby>GRUB菜单提供选择 Windows 或 Linux 的选项,这意味着我不需要再做任何额外的配置。我选择 Linux 并完成了诸如创建我的用户账号等常规步骤。
### 总结
总体而言,这个过程是不难的,在过去的几年里,从 BIOS 过渡到 UEFI 有一些困难需要解决,加上诸如安全启动等功能的引入。我相信我们现在已经克服了这些障碍,可以可靠地设置多重启动系统。
我不再怀念 [Linux LOader][15]LILO
--------------------------------------------------------------------------------
via: https://opensource.com/article/19/5/dual-booting-windows-linux-uefi
作者:[Alan Formy-Duval][a]
选题:[lujun9972][b]
译者:[robsean](https://github.com/robsean)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://opensource.com/users/alanfdoss/users/ckrzen
[b]: https://github.com/lujun9972
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/linux_keyboard_desktop.png?itok=I2nGw78_ (Linux keys on the keyboard for a desktop computer)
[2]: https://www.ubuntu.com
[3]: https://www.microsoft.com/en-us/windows
[4]: https://getfedora.org
[5]: https://en.wikipedia.org/wiki/Unified_Extensible_Firmware_Interface
[6]: https://en.wikipedia.org/wiki/BIOS
[7]: https://fedoraproject.org/wiki/Features/SecureBoot
[8]: https://en.wikipedia.org/wiki/GUID_Partition_Table
[9]: https://en.wikipedia.org/wiki/Master_boot_record
[10]: https://en.wikipedia.org/wiki/EFI_system_partition
[11]: https://sourceforge.net/projects/gptfdisk/
[12]: /sites/default/files/u216961/gdisk_screenshot_s.png
[13]: https://en.wikipedia.org/wiki/Microsoft_Reserved_Partition
[14]: https://en.wikipedia.org/wiki/GNU_GRUB
[15]: https://en.wikipedia.org/wiki/LILO_(boot_loader)

View File

@ -0,0 +1,82 @@
[#]: collector: (lujun9972)
[#]: translator: (chenmu-kk)
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-12914-1.html)
[#]: subject: (When to use 5G, when to use Wi-Fi 6)
[#]: via: (https://www.networkworld.com/article/3402316/when-to-use-5g-when-to-use-wi-fi-6.html)
[#]: author: (Lee Doyle )
何时使用 5G何时使用 Wi-Fi 6
======
> 5G 是一种蜂窝服务, Wi-Fi 6 则是短程无线接入技术,这两种技术都有使其在特定企业角色中发挥作用的特性。
![Thinkstock][1]
我们已经看到了关于 [5G][2] 蜂窝还是 [Wi-Fi 6][3] 将在企业使用中胜出的大肆宣传,但事实却是这两者在很大程度上互补,这将在 21 世纪 20 年代初形成一个有趣的竞争环境。
### 5G 在企业中的潜力
5G 对企业用户的承诺是在更低的延迟下提供更高的连接速度。蜂窝技术使用许可频段,可在很大程度上消除未经许可的 WiFi 频段可能会发生的潜在干涉。像当前的 4G LTE 技术一样5G 可以由蜂窝无线运营商提供,也可以作为专用网络构建。
5G 的架构需要更多的无线接入点,并且在室内可能会出现连接质量较差或没有连接。因此,典型的组织需要为连接它的 PC、路由器和其他设备评估其 [当前 4G 和潜在 5G 服务配置][4]。部署室内微蜂窝、中继器以及分布式天线可以帮助解决室内 5G 服务问题。与 4G 一样5G 最佳的企业应用案例应该是用于真正的移动连接,例如,公共安全车和非地毯式覆盖区域(如采矿,石油与天然气开采、运输、农业和一些制造业)。
除了广泛的移动性5G 在漫游时的身份验证和部署速度方面也具有优势这正好满足临时办公室或零售点的广域网连接需求。5G 将会拥有在视频直播这样的数据拥塞的情况下分流的能力。随着 5G 标准的成熟,该技术将提高其低功耗 IoT 连接的选择。
未来四到五年内5G 将从大城市和特定地区开始逐步推出4G 技术将在未来数年内继续流行。企业用户将需要新的设备、加密狗和路由器来连接 5G 服务。例如,苹果的 iPhone 预计要到 2020 年才能支持 5G而物联网设备需要特定的蜂窝网络兼容性才能连接到 5G。LCTT 译注:原文发表于 2019 年中)
Doyle Research 预计5G 承诺的 1Gbps 和更高的带宽将对 SD-WAN 市场产生重大影响。4G LTE 已经使蜂窝服务成为主要的 WAN 连接。5G 可能比许多有线 WAN 选项(例如 MPLS 或互联网更具成本竞争力或更便宜。5G 为企业 WAN 管理员提供了更多选择,为他们的分支站点和远程用户提供更多的带宽 —— 随着时间的推移,或将取代 MPLS。
### Wi-Fi 6 在企业中的潜力
Wi-Fi 几乎无处不在它可以将便携式笔记本电脑、平板电脑和其他设备连接到企业网络中。Wi-Fi 6802.11ax)是 Wi-Fi 的最新版本,并有望提高速度、降低延迟、改善聚合带宽并提供高级流量管理。虽然 Wi-Fi 6 与 5G 有一些相似之处(两者均基于正交频分多址),但 Wi-Fi 6 不太容易受到干扰,能耗更低(延长设备电池的寿命),并提高了频谱效率。
与典型的 Wi-Fi 相同,目前许多厂商都有 [Wi-Fi 6 早期厂商专用版本][6]。Wi-Fi 联盟计划在 2020 年获得 Wi-Fi 6 标准设备的认证。大多数企业将按照标准<ruby>接入点<rt>access-point</rt></ruby>AP的生命周期三年左右升级到 Wi-Fi 6除非他们有特定的性能/延迟要求,这将促使它们更快地升级。
Wi-Fi 接入点仍然会受到干涉的影响。设计和配置接入点以提供适当的覆盖范围将会是一项挑战。企业 LAN 管理者将继续需要供应商提供的工具和合作伙伴来为组织配置最理想的 Wi-Fi 覆盖。Wi-Fi 6 解决方案必须与有线区域基础建设集成。Wi-Fi 供应商需要更好地为企业提供无线和有线解决方案的统一网络管理。
### 有线回程的需求
对于这两种技术通过无线与有线网络基础设施相结合可以提供端到端的高速通信。在企业中Wi-Fi 通常与区域和一些较大分支机构的有线以太网交换机搭配使用。一些设备通过电缆连接到交换机,其他设备则通过 Wi-Fi 连接而笔记本电脑可能会同时采用这两种方法。Wi-Fi 接入点通过企业内部的以太网连接,并通过光纤连接连接到 WAN 或 Internet。
5G 的架构广泛使用光纤,将分布式无线接入网络连接回 5G 网络的核心。光纤通常需要提供将 5G 端点连接到基于 SaaS 的应用程序所需的高带宽,并提供实时视频和高速互联网访问。专用 5G 网络也必须满足高速有线连接要求。
### 切换问题
随着手机在 5G 和 Wi-Fi 6 之间切换,企业 IT 管理者要注意到切换挑战。这些问题会影响到性能和用户满意度。一些组织正在努力制定标准,以促进 Wi-Fi 6 和 5G 间更好的互操作性。
由于 Wi-Fi 6 的架构与 5G 接轨,在蜂窝网络与 Wi-Fi 网络间移动的体验应该更加顺滑。
### 5G 和 Wi-Fi 6 的对比取决于位置、应用和设备
Wi-Fi 6 和 5G 在企业环境中的特定情况下相互竞争这取决于位置、应用程序和设备类型。IT 管理者应该仔细评估他们当前和正在出现的连接性需求。Wi-Fi 将继续占领室内环境优势,而移动蜂窝网络将赢得更为广泛的室外覆盖。
一些重叠的情况发生在体育场馆、酒店和其他大型活动场所,许多用户将争夺带宽。政府应用(包括智能城市方面)可适用于 Wi-Fi 和蜂窝。医疗保健设施中有许多分布式医疗设备和需要连接的用户。大型分布式制造环境具有相似的特点。新兴的物联网应用环境可能是最有趣的“重叠使用案例”。
### 对于 IT 领导者的建议
虽然支持它们的无线技术正在融合,但 Wi-Fi 6 和 5G 从根本上来说是不同的网络,在企业连接中都有各自的作用。企业 IT 领导者应关注 Wi-Fi 和蜂窝网络如何相互补足Wi-Fi 将继续作为内置技术,连接 PC 和笔记本电脑,处理手机和平板电脑数据,并实现一些物联网连接。
4G LTE 升级到 5G 后,仍将是手机和平板电脑连接的真正移动技术,也是 PC 连接的一种选择通过加密狗并在连接一些物联网设备方面越来越受欢迎。5G WAN 链路将日益成为标准,作为提高 SD-WAN 可靠性的备份和远程办公室的主要链路。
--------------------------------------------------------------------------------
via: https://www.networkworld.com/article/3402316/when-to-use-5g-when-to-use-wi-fi-6.html
作者:[Lee Doyle][a]
选题:[lujun9972][b]
译者:[chenmu-kk](https://github.com/chenmu-kk)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://www.networkworld.com/author/Lee-Doyle/
[b]: https://github.com/lujun9972
[1]: https://images.idgesg.net/images/article/2017/07/wi-fi_wireless_communication_network_abstract_thinkstock_610127984_1200x800-100730107-large.jpg
[2]: https://www.networkworld.com/article/3203489/what-is-5g-how-is-it-better-than-4g.html
[3]: https://www.networkworld.com/article/3215907/why-80211ax-is-the-next-big-thing-in-wi-fi.html
[4]: https://www.networkworld.com/article/3330603/5g-versus-4g-how-speed-latency-and-application-support-differ.html
[5]: https://pluralsight.pxf.io/c/321564/424552/7490?u=https%3A%2F%2Fwww.pluralsight.com%2Fcourses%2Fmobile-device-management-big-picture
[6]: https://www.networkworld.com/article/3309439/80211ax-preview-access-points-and-routers-that-support-the-wi-fi-6-protocol-on-tap.html
[7]: https://www.facebook.com/NetworkWorld/
[8]: https://www.linkedin.com/company/network-world

View File

@ -0,0 +1,172 @@
[#]: collector: (lujun9972)
[#]: translator: (quinbyjoe)
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-12927-1.html)
[#]: subject: (How to Use VLAN tagged NIC \(Ethernet Card\) on CentOS and RHEL Servers)
[#]: via: (https://www.linuxtechi.com/vlan-tagged-nic-ethernet-card-centos-rhel-servers/)
[#]: author: (Pradeep Kumar https://www.linuxtechi.com/author/pradeep/)
如何在 CentOS/RHEL 系统中使用带 VLAN 标记的网卡
======
在某些场景中,我们希望在 Linux 服务器CentOS/RHEL的同一块以太网卡NIC上分配来自不同 VLAN 的多个 IP。这个可以通过使用 VLAN 标记接口来实现。但是要做到这一点,我们必须确保交换机的端口上连接了多个 VLAN也就是说我们可以在交换机上添加多个 VLAN 来配置<ruby>聚合端口<rt>Trunk port</rt></ruby>LCTT 译注:一般有<ruby>聚合端口<rt>Trunk port</rt></ruby><ruby>接入端口<rt>Access port</rt></ruby><ruby>混合端口<rt>Hybird port</rt></ruby>三种)。
![](https://img.linux.net.cn/data/attachment/album/202012/17/123821uvv3oyonqnhn2bqq.jpg)
假设我们有一个 Linux 服务器,我们在这里有两张以太网卡(`enp0s3` 和 `enp0s8`),第一张网卡(`enp0s3`)会用于数据传输,而第二张网卡(`enp0s8` 会用于控制/流量管理。我会使用多个 VLAN 用于数据传输(或在数据流量网卡上从不同的 VLAN 中分配多个 IP
我假设连接到我服务器的数据网卡的端口,是通过映射多个 VLAN 来配置为聚合端口。
下面是映射到数据传输网卡NIC的 VLAN
* VLAN ID (200), VLAN N/W = 172.168.10.0/24
* VLAN ID (300), VLAN N/W = 172.168.20.0/24
要在 CentOS 7 / RHEL 7 / CentOS 8 / RHEL 8 系统中使用 VLAN 标记接口,必须加载[内核模块][1] `8021q`
加载内核模块 `8021q` 可以使用下面的命令:
```
[root@linuxtechi ~]# lsmod | grep -i 8021q
[root@linuxtechi ~]# modprobe --first-time 8021q
[root@linuxtechi ~]# lsmod | grep -i 8021q
8021q 29022 0
garp 14384 1 8021q
mrp 18542 1 8021q
[root@linuxtechi ~]#
```
可以使用 `modinfo` 命令显示内核模块 `8021q` 的详细信息:
```
[root@linuxtechi ~]# modinfo 8021q
filename: /lib/modules/3.10.0-327.el7.x86_64/kernel/net/8021q/8021q.ko
version: 1.8
license: GPL
alias: rtnl-link-vlan
rhelversion: 7.2
srcversion: 2E63BD725D9DC11C7DA6190
depends: mrp,garp
intree: Y
vermagic: 3.10.0-327.el7.x86_64 SMP mod_unload modversions
signer: CentOS Linux kernel signing key
sig_key: 79:AD:88:6A:11:3C:A0:22:35:26:33:6C:0F:82:5B:8A:94:29:6A:B3
sig_hashalgo: sha256
[root@linuxtechi ~]#
```
现在使用 [ip 命令][2]给 `enp0s3` 网卡标记(或映射)上 `200``300` 的 VLAN 。
LCTT 译注:这是先给 `enp0s3` 网卡映射上 `200` 的 VLAN 标签。)
```
[root@linuxtechi ~]# ip link add link enp0s3 name enp0s3.200 type vlan id 200
```
使用下面的 `ip` 命令打开接口:
```
[root@linuxtechi ~]# ip link set dev enp0s3.200 up
```
同理给 `enp0s3` 网卡映射上 `300` 的 VLAN 标签:
```
[root@linuxtechi ~]# ip link add link enp0s3 name enp0s3.300 type vlan id 300
[root@linuxtechi ~]# ip link set dev enp0s3.300 up
```
现在使用 `ip` 命令查看标记后的接口状态:
![tagged-interface-ip-command][3]
现在我们可以使用下面的 `ip` 命令从它们各自的 VLAN 为已经标记的接口分配 IP 地址:
```
[root@linuxtechi ~]# ip addr add 172.168.10.51/24 dev enp0s3.200
[root@linuxtechi ~]# ip addr add 172.168.20.51/24 dev enp0s3.300
```
使用下面的 `ip` 命令查看是否为已标记的接口分配到 IP
![ip-address-tagged-nic][5]
重启之后,上面所有通过 `ip` 命令的更改都不会保持LCTT 译注修改后可保存至配置文件或数据库中如果未进行保存处理则只有当前环境生效重启后配置失效。系统重启和网络服务重启LCTT 译注:`service network restart`,或 `down``up` 命令)之后这些标记接口将不可用。
因此,要使标记的接口在重启后保持不变,需要使用接口的 `ifcfg` 文件。
编辑接口(`enp0s3`)文件 `/etc/sysconfig/network-scripts/ifcfg-enp0s3`,并且增加下面的内容:
**作者提醒**:替换为你环境中的接口名称。
```
[root@linuxtechi ~]# vi /etc/sysconfig/network-scripts/ifcfg-enp0s3
TYPE=Ethernet
DEVICE=enp0s3
BOOTPROTO=none
ONBOOT=yes
```
保存和退出文件。
为 id 是 `200` 的 VLAN 创建接口文件 `/etc/sysconfig/network-scripts/ifcfg-enp0s3.200`,且增加下面的内容:
```
[root@linuxtechi ~]# vi /etc/sysconfig/network-scripts/ifcfg-enp0s3.200
DEVICE=enp0s3.200
BOOTPROTO=none
ONBOOT=yes
IPADDR=172.168.10.51
PREFIX=24
NETWORK=172.168.10.0
VLAN=yes
```
保存并退出此文件。
同理为 id 是 `300` 的 VLAN 创建接口文件 `/etc/sysconfig/network-scripts/ifcfg-enp0s3.300`,且增加下面的内容:
```
[root@linuxtechi ~]# vi /etc/sysconfig/network-scripts/ifcfg-enp0s3.300
DEVICE=enp0s3.300
BOOTPROTO=none
ONBOOT=yes
IPADDR=172.168.20.51
PREFIX=24
NETWORK=172.168.20.0
VLAN=yes
```
保存并退出文件,这时候使用下面的命令重启网络服务,
```
[root@linuxtechi ~]# systemctl restart network
```
现在使用下面的 `ip` 命令检验标记的接口是否已配置和启动,并且正在运行中:
![tagged-interface-status-ip-command-linux-server][6]
以上就是本文的全部内容,我希望你已经学会了在 CentOS 7 / 8 和 RHEL 7 / 8 服务器上如何去配置和启用 VLAN 标签接口的方法。请分享你的反馈和意见。
--------------------------------------------------------------------------------
via: https://www.linuxtechi.com/vlan-tagged-nic-ethernet-card-centos-rhel-servers/
作者:[Pradeep Kumar][a]
选题:[lujun9972][b]
译者:[quinbyjoe](https://github.com/quinbyjoe)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://www.linuxtechi.com/author/pradeep/
[b]: https://github.com/lujun9972
[1]: https://www.linuxtechi.com/how-to-manage-kernel-modules-in-linux/
[2]: https://www.linuxtechi.com/ip-command-examples-for-linux-users/
[3]: https://www.linuxtechi.com/wp-content/uploads/2019/06/tagged-interface-ip-command-1024x444.jpg
[4]: https://www.linuxtechi.com/wp-content/uploads/2019/06/tagged-interface-ip-command.jpg
[5]: https://www.linuxtechi.com/wp-content/uploads/2019/06/ip-address-tagged-nic-1024x343.jpg
[6]: https://www.linuxtechi.com/wp-content/uploads/2019/06/tagged-interface-status-ip-command-linux-server-1024x656.jpg
[7]: https://www.linuxtechi.com/wp-content/uploads/2019/06/VLAN-Tagged-NIC-Linux-Server.jpg

View File

View File

@ -0,0 +1,164 @@
[#]: collector: (lujun9972)
[#]: translator: (alim0x)
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-12878-1.html)
[#]: subject: (Creating a Chat Bot with Recast.AI)
[#]: via: (https://opensourceforu.com/2019/11/creating-a-chat-bot-with-recast-ai/)
[#]: author: (Athira Lekshmi C.V https://opensourceforu.com/author/athira-lekshmi/)
用 Recast.AI 创建一个聊天机器人
======
[![][1]][2]
> 据 Gartner 2018 年 2 月的报告,“到 2020 年25% 的客户服务和支持业务将在参与渠道中整合虚拟客户助理VCA或聊天机器人技术而 2017 年只有不到 2%。”鉴于此,读者会发现本教程对理解开源的 Recast.AI 机器人创建平台的工作原理很有帮助。
聊天机器人,包括基于语音的以及其他技术的,已经实际使用了有一阵子了。从让用户参与谋杀解密游戏,到帮助完成房地产交易和医疗诊断,聊天机器人已经跨越了多个领域。
有许多平台可以让用户创建和部署机器人。Recast.AI在被 SAP 收购之后现在是 SAP Conversational AI是其中的先行者。
酷炫的界面、协作性以及它所提供的分析工具,让它成为流行的选择。
正如 Recast 官方网站说的,“它是一个创建、训练、部署和监控智能机器人的终极协作平台。”
### 创建一个基础的机器人
让我们来看看如何在 Recast 创建一个基础的机器人。
1. 在 https://cai.tools.sap 创建一个账户。注册可以使用电子邮箱或者 Github 账户。
2. 在你登录之后,你会进入仪表板。点击右上角 “+” 新建机器人图标新建一个机器人。
3. 在下一个界面,你会看到一系列可选的预定义技能。暂时选择<ruby>问候<rt>Greetings</rt></ruby>”(图 1。这个机器人已经经过训练能够理解基本的问候。
![图 1: 设置机器人属性][3]
4. 给机器人提供一个名字。目前来说,你可以让机器人讲一些笑话,所以我们将它命名为 Joke Bot选择英语作为默认语言。
5. 因为你不会处理任何敏感信息,所以在数据策略下选择非个人数据。然后选择公共机器人选项并点击创建一个机器人。
所以这就是你在 Recast 平台创建的机器人。
### 开发一个机器人的五个阶段
用 Recast 官方博客的话说,在机器人的生命中有五个阶段。
* 训练——教授机器人需要理解的内容
* 构建——使用机器人构建工具创建你的对话流
* 编写代码——将机器人连接到外部 API 或数据库
* 连接——将机器人发布到一个或多个消息平台
* 监控——训练机器人让它更敏锐,并且了解其使用情况
### 通过意图训练机器人
你可以在仪表板上看到搜索、分叉或创建一个<ruby>意图<rt>intent</rt></ruby>的选项。“‘意图’是一系列含义相同但构造不同的表达。‘意图’是你的机器人理解能力的核心。每个‘意图’代表了机器人可以理解的一种想法。”(摘自 Recast.AI 网站)
![图 2: 机器人面板][4]
就像先前定的你需要一个讲笑话的机器人。所以底线是这个机器人可以理解用户在要求它讲笑话它不应该在用户仅仅说了“Hi”的情况下回复一个笑话——这可不妙。把用户可能说的话进行分组比如
```
Tell me a joke.(给我讲个笑话。)
Tell me a funny fact.(告诉我一个有趣的事实。)
Can you crack a joke?(你可以讲个笑话吗?)
Whats funny today?(今天有什么有趣的?)
```
……
在继续从头开始创建意图之前,让我们来看看搜索/分叉选项。在搜索框输入 “Joke”图 3。系统给出了全球的 Recast 用户创建的公开的意图清单,这就是为什么说 Recast 天然就是协作性质的。所以其实没有必要从头开始创建所有的意图,可以在已经创建的基础上进行构建。这就降低了训练具有常见意图的机器人所需的投入。
![图 3: 搜索一个意图][5]
* 选择列表中的第一个意图并将其分叉到机器人上。
* 点击<ruby>分叉<rt>Fork</rt></ruby>按钮。这个意图就添加到了机器人中(图 4
![图 4: @joke 意图][6]
* 点击意图 @joke,会显示出这个意图中已经存在的<ruby>表达<rt>expression</rt></ruby>列表(图 5
![图 5: 预定义表达][7]
* 向其添加更多的表达(图 6
![图 6: 建议的表达][8]
添加了一些表达之后,机器人会给出一些建议,像图 7 展示的那样。选择几个将它们添加到意图中。你还可以根据机器人的上下文,标记你自己的自定义实体来检测关键词。
![图 7: 建议的表达][9]
### 技能
<ruby>技能<rt>skill</rt></ruby>是一块有明确目的的对话,机器人可以据此运行并达到目标。它可以像打招呼那么简单,也可以更复杂,比如基于用户提供的信息提供电影建议。
技能需要的不能只是一对问答,它需要多次交互。比如考虑一个帮你学习汇率的机器人。它一开始会问原货币,然后是目标货币,最后给出准确回应。结合技能可以创建复杂的对话流。
下面是如何给笑话机器人创建技能:
* 去到 构建Build 页。点击 “+” 图标创建技能。
* 给技能命名 “Joke”图 8
![图 8: 技能面板][10]
* 创建之后,点击这个技能。你会看到四个标签。<ruby>读我<rt>Read me</rt></ruby><ruby>触发器<rt>Triggers</rt></ruby><ruby>需求<rt>Requirements</rt></ruby><ruby>动作<rt>Actions</rt></ruby>
* 切换到需求页面。只有在笑话意图存在的时候,你才应该存储信息。所以,像图 9 那样添加一个需求。
![图 9: 添加一个触发器][11]
由于这个简单的使用范例,你不需要在需求选项卡中考虑任何特定的需求,但可以考虑只有当某些关键字或实体出现时才需要触发响应的情况——在这种情况下你需要需求。
需求是某个技能执行动作之前需要检索的意图或实体。需求是对话中机器人可以使用的重要信息。例如用户的姓名或位置。一旦一个需求完成,相关的值就会存储在机器人的内存中,供整个对话使用。
现在让我们转到动作页面设置<ruby>回应<rt>response</rt></ruby>(参见图 10
![图 10: 添加动作][12]
点击添加<ruby>新消息组<rt>new message group</rt></ruby>。然后选择<ruby>发送消息<rt>Send message</rt></ruby>并添加一条文本消息,在这个例子中可以是任何笑话。当然,你肯定不想让你的机器人每次都说一样的笑话,你可以添加多条消息,每次从中随机选择一条。
![图 11: 添加文本消息][13]
### 频道集成
一个成功的机器人还依赖于它的易得性。Recast 有不少的内置消息频道集成,如 Skype for Business、Kik Messenger、Telegram、Line、Facebook Messenger、Slack、Alexa 等等。除此之外Recast 还提供了 SDK 用于开发自定义的频道。
此外Recast 还提供一个可立即使用的网页聊天(在连接页面中)。你可以自定义颜色主题、标题、机器人头像等。它给你提供了一个可以添加到页面的脚本标签。你的界面现在就可以使用了(图 12
![图 12: 设置网络聊天][14]
网页聊天的代码是开源的,开发者可以更方便地定制外观、标准回应类型等等。面板提供了如何将机器人部署到各种频道的逐步过程说明。这个笑话机器人部署在 Telegram 和网页聊天上,就像图 13 展示的那样。
![图 13: 网页聊天部署][15]
![图 14: Telegram 中开发的机器人][16]
### 还有更多
Recast 支持多语言,创建机器人的时候选择一个语言作为基础,但之后你有选项可以添加更多你想要的语言。
![图 15: 多语言机器人][17]
这里的例子是一个简单的静态笑话机器人实际使用中可能需要更多的和不同系统的交互。Recast 有 Web 钩子功能,用户可以连接到不同的系统来获取回应。同时它还有详细的 API 文档来帮助使用平台的每个独立功能。
至于分析Recast 有一个监控面板,帮助你了解机器人的准确度以及更加深入地训练机器人。
--------------------------------------------------------------------------------
via: https://opensourceforu.com/2019/11/creating-a-chat-bot-with-recast-ai/
作者:[Athira Lekshmi C.V][a]
选题:[lujun9972][b]
译者:[alim0x](https://github.com/alim0x)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://opensourceforu.com/author/athira-lekshmi/
[b]: https://github.com/lujun9972
[1]: https://i0.wp.com/opensourceforu.com/wp-content/uploads/2019/04/Build-ChatBoat.jpg?resize=696%2C442&ssl=1 (Build ChatBoat)
[2]: https://i0.wp.com/opensourceforu.com/wp-content/uploads/2019/04/Build-ChatBoat.jpg?fit=900%2C572&ssl=1
[3]: https://i1.wp.com/opensourceforu.com/wp-content/uploads/2019/11/Figure-1-Setting-the-bot-properties.jpg
[4]: https://i1.wp.com/opensourceforu.com/wp-content/uploads/2019/11/Figure-2-Setting-the-bot-properties.jpg
[5]: https://i0.wp.com/opensourceforu.com/wp-content/uploads/2019/11/Figure-3-Searching-an-intent.jpg
[6]: https://i0.wp.com/opensourceforu.com/wp-content/uploads/2019/11/Figure-4-@joke-intent.jpg
[7]: https://i0.wp.com/opensourceforu.com/wp-content/uploads/2019/11/Figure-5-Predefined-expressions.jpg
[8]: https://i2.wp.com/opensourceforu.com/wp-content/uploads/2019/11/Figure-6-Suggested-expressions.jpg
[9]: https://i1.wp.com/opensourceforu.com/wp-content/uploads/2019/11/Figure-7-Suggested-expressions.jpg
[10]: https://i0.wp.com/opensourceforu.com/wp-content/uploads/2019/11/Figure-8-Skills-dashboard.jpg
[11]: https://i0.wp.com/opensourceforu.com/wp-content/uploads/2019/11/Figure-9-Adding-a-trigger.jpg
[12]: https://i0.wp.com/opensourceforu.com/wp-content/uploads/2019/11/Figure-10-Adding-actions.jpg
[13]: https://i1.wp.com/opensourceforu.com/wp-content/uploads/2019/11/Figure-11-Adding-text-messages.jpg
[14]: https://i2.wp.com/opensourceforu.com/wp-content/uploads/2019/11/Figure-12-Setting-up-webchat.jpg
[15]: https://i0.wp.com/opensourceforu.com/wp-content/uploads/2019/11/Figure-13-Webchat-deployed.jpg
[16]: https://i2.wp.com/opensourceforu.com/wp-content/uploads/2019/11/Figure-14-Bot-deployed-in-Telegram.jpg
[17]: https://i1.wp.com/opensourceforu.com/wp-content/uploads/2019/11/Figure-15-Multi-language-bot.jpg
[18]: https://secure.gravatar.com/avatar/d24503a2a0bb8bd9eefe502587d67323?s=100&r=g
[19]: https://opensourceforu.com/author/athira-lekshmi/
[20]: https://opensourceforu.com/wp-content/uploads/2019/11/assoc.png
[21]: https://feedburner.google.com/fb/a/mailverify?uri=LinuxForYou&loc=en_US

0
published/202007/20200701 Customizing Bash.md Executable file → Normal file
View File

View File

@ -0,0 +1,78 @@
[#]: collector: (lujun9972)
[#]: translator: (geekpi)
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-12886-1.html)
[#]: subject: (scanimage: scan from the command line!)
[#]: via: (https://jvns.ca/blog/2020/07/11/scanimage--scan-from-the-command-line/)
[#]: author: (Julia Evans https://jvns.ca/)
scanimage从命令行扫描!
======
![](https://img.linux.net.cn/data/attachment/album/202012/05/105822m30t6x66hz3hx6x3.jpg)
这又是一篇关于我很喜欢的一个命令行工具的文章。
昨晚,出于官僚原因,我需要扫描一些文档。我以前从来没有在 Linux 上使用过扫描仪,我担心会花上好几个小时才弄明白。我从使用 `gscan2pdf` 开始,但在用户界面上遇到了麻烦。我想同时扫描两面(我知道我们的扫描仪支持),但无法使它工作。
### 遇到 scanimage
`scanimage` 是一个命令行工具,在 `sane-utils` Debian 软件包中。我想所有的 Linux 扫描工具都使用 `sane` “scanner access now easy” 库,所以我猜测它和其他扫描软件有类似的能力。在这里,我不需要 OCR所以我不打算谈论 OCR。
### 用 scanimage -L 得到你的扫描仪的名字
`scanimage -L` 列出了你所有的扫描设备。
一开始我不能让它工作,我有点沮丧,但事实证明,我把扫描仪连接到了我的电脑上,但没有插上电源。
插上后,它马上就能工作了。显然我们的扫描仪叫 `fujitsu:ScanSnap S1500:2314`。万岁!
### 用 --help 列出你的扫描仪选项
显然每个扫描仪有不同的选项(有道理!),所以我运行这个命令来获取我的扫描仪的选项:
```
scanimage --help -d 'fujitsu:ScanSnap S1500:2314'
```
我发现我的扫描仪支持 `--source` 选项(我可以用它来启用双面扫描)和 `--resolution` 选项(我把它改为 150以减少文件大小使扫描更快
### scanimage 不支持输出 PDF 文件(但你可以写一个小脚本)
唯一的缺点是:我想要一个 PDF 格式的扫描文件,而 scanimage 似乎不支持 PDF 输出。
所以我写了这个 5 行的 shell 脚本在一个临时文件夹中扫描一堆 PNG 文件,并将结果保存到 PDF 中。
```
#!/bin/bash
set -e
DIR=`mktemp -d`
CUR=$PWD
cd $DIR
scanimage -b --format png -d 'fujitsu:ScanSnap S1500:2314' --source 'ADF Front' --resolution 150
convert *.png $CUR/$1
```
我像这样运行脚本:`scan-single-sided output-file-to-save.pdf`
你可能需要为你的扫描仪设置不同的 `-d``-source`
### 这真是太简单了!
我一直以为在 Linux 上使用打印机/扫描仪是一个噩梦,我真的很惊讶 `scanimage` 可以工作。我可以直接运行我的脚本 `scan-single-sided receipts.pdf`,它将扫描文档并将其保存到 `receipts.pdf`
--------------------------------------------------------------------------------
via: https://jvns.ca/blog/2020/07/11/scanimage--scan-from-the-command-line/
作者:[Julia Evans][a]
选题:[lujun9972][b]
译者:[geekpi](https://github.com/geekpi)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://jvns.ca/
[b]: https://github.com/lujun9972

View File

@ -0,0 +1,115 @@
[#]: collector: (lujun9972)
[#]: translator: (silentdawn-zz)
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-12594-1.html)
[#]: subject: (Why Sorting is O\(N log N\))
[#]: via: (https://theartofmachinery.com/2019/01/05/sorting_is_nlogn.html)
[#]: author: (Simon Arneaud https://theartofmachinery.com)
为什么排序的复杂度为 O(N log N)
======
基本上所有正而八经的算法教材都会解释像<ruby>快速排序<rt>quicksort</rt></ruby><ruby>堆排序<rt>heapsort</rt></ruby>这样的排序算法有多快,但并不需要复杂的数学就能证明你可以逐渐趋近的速度有多快。
> 关于标记的一个严肃说明:
>
> 大多数计算机专业的科学家使用大写字母 O 标记来指代“趋近,直到到达一个常数比例因子”,这与数学专业所指代的意义是有所区别的。这里我使用的大 O 标记的含义与计算机教材所指相同,但至少不会和其他数学符号混用。
### 基于比较的排序
先来看个特例,即每次比较两个值大小的算法(快速排序、堆排序,及其它通用排序算法)。这种思想后续可以扩展至所有排序算法。
#### 一个简单的最差情况下的计数角度
假设有 4 个互不相等的数,且顺序随机,那么,可以通过只比较一对数字完成排序吗?显然不能,证明如下:根据定义,要对该数组排序,需要按照某种顺序重新排列数字。换句话说,你需要知道用哪种排列方式?有多少种可能的排列?第一个数字可以放在四个位置中的任意一个,第二个数字可以放在剩下三个位置中的任意一个,第三个数字可以放在剩下两个位置中的任意一个,最后一个数字只有剩下的一个位置可选。这样,共有 $4×3×2×1 = 4! = 24$ 种排列可供选择。通过一次比较大小,只能产生两种可能的结果。如果列出所有的排列,那么“从小到大”排序对应的可能是第 8 种排列,按“从大到小”排序对应的可能是第 24 种排列,但无法知道什么时候需要的是其它 22 种排列。
通过 2 次比较,可以得到 2×2=4 种可能的结果,这仍然不够。只要比较的次数少于 5对应 $2^{5} = 32$ 种输出),就无法完成 4 个随机次序的数字的排序。如果 $W(N)$ 是最差情况下对 $N$ 个不同元素进行排序所需要的比较次数,那么,
$$
2^{W(N)} \geq N!
$$
两边取以 2 为底的对数,得:
$$
W(N) \geq \log_{2}{N!}
$$
$N!$ 的增长近似于 $N^{N}$ (参阅 [Stirling 公式][1]),那么,
$$
W(N) \succeq \log N^{N} = N\log N
$$
这就是最差情况下从输出计数的角度得出的 $O(N\log N)$ 上限。
#### 从信息论角度的平均状态的例子
使用一些信息论知识,就可以从上面的讨论中得到一个更有力的结论。下面,使用排序算法作为信息传输的编码器:
1. 任取一个数,比如 15
2. 从 4 个数字的排列列表中查找第 15 种排列
3. 对这种排列运行排序算法,记录所有的“大”、“小”比较结果
4. 用二进制编码发送比较结果
5. 接收端重新逐步执行发送端的排序算法,需要的话可以引用发送端的比较结果
6. 现在接收端就可以知道发送端如何重新排列数字以按照需要排序,接收端可以对排列进行逆算,得到 4 个数字的初始顺序
7. 接收端在排列表中检索发送端的原始排列,指出发送端发送的是 15
确实,这有点奇怪,但确实可以。这意味着排序算法遵循着与编码方案相同的定律,包括理论所证明的不存在通用的数据压缩算法。算法中每次比较发送 1 比特的比较结果编码数据,根据信息论,比较的次数至少是能表示所有数据的二进制位数。更技术语言点,[平均所需的最小比较次数是输入数据的香农熵,以比特为单位][2]。熵是衡量信息等不可预测量的数学度量。
包含 $N$ 个元素的数组,元素次序随机且无偏时的熵最大,其值为 $\log_{2}{N!}$ 个比特。这证明 $O(N\log N)$ 是一个基于比较的对任意输入排序的最优平均值。
以上都是理论说法,那么实际的排序算法如何做比较的呢?下面是一个数组排序所需比较次数均值的图。我比较的是理论值与快速排序及 [Ford-Johnson 合并插入排序][3] 的表现。后者设计目的就是最小化比较次数(整体上没比快速排序快多少,因为生活中相对于最大限度减少比较次数,还有更重要的事情)。又因为<ruby>合并插入排序<rt>merge-insertion sort</rt></ruby>是在 1959 年提出的,它一直在调整,以减少了一些比较次数,但图示说明,它基本上达到了最优状态。
![随机排列 100 个元素所需的平均排序次数图。最下面的线是理论值,约 1% 处的是合并插入算法,原始 quicksort 大约在 25% 处。][4]
一点点理论导出这么实用的结论,这感觉真棒!
#### 小结
证明了:
1. 如果数组可以是任意顺序,在最坏情况下至少需要 $O(N\log N)$ 次比较。
2. 数组的平均比较次数最少是数组的熵,对随机输入而言,其值是 $O(N\log N)$ 。
注意,第 2 个结论允许基于比较的算法优于 $O(N\log N)$,前提是输入是低熵的(换言之,是部分可预测的)。如果输入包含很多有序的子序列,那么合并排序的性能接近 $O(N)$。如果在确定一个位之前,其输入是有序的,插入排序性能接近 $O(N)$。在最差情况下,以上算法的性能表现都不超出 $O(N\log N)$。
### 一般排序算法
基于比较的排序在实践中是个有趣的特例,但从理论上讲,计算机的 [CMP][5] 指令与其它指令相比,并没有什么特别之处。在下面两条的基础上,前面两种情形都可以扩展至任意排序算法:
1. 大多数计算机指令有多于两个的输出,但输出的数量仍然是有限的。
2. 一条指令有限的输出意味着一条指令只能处理有限的熵。
这给出了 $O(N\log N)$ 对应的指令下限。任何物理上可实现的计算机都只能在给定时间内执行有限数量的指令,所以算法的执行时间也有对应 $O(N\log N)$ 的下限。
#### 什么是更快的算法?
一般意义上的 $O(N\log N)$ 下限,放在实践中来看,如果听人说到任何更快的算法,你要知道,它肯定以某种方式“作弊”了,其中肯定有圈套,即它不是一个可以处理任意大数组的通用排序算法。可能它是一个有用的算法,但最好看明白它字里行间隐含的东西。
一个广为人知的例子是<ruby>基数排序<rt>radix sort</rt></ruby>算法,它经常被称为 $O(N)$ 排序算法,但它只能处理所有数字都能放入 $k$ 比特的情况,所以实际上它的性能是 $O({kN})$。
什么意思呢?假如你用的 8 位计算机,那么 8 个二进制位可以表示 $2^{8} = 256$ 个不同的数字,如果数组有上千个数字,那么其中必有重复。对有些应用而言这是可以的,但对有些应用就必须用 16 个二进制位来表示16 个二进制位可以表示 $2^{16} = 65,536$ 个不同的数字。32 个二进制位可以表示 $2^{32} = 4,294,967,296$ 不同的数字。随着数组长度的增长,所需要的二进制位数也在增长。要表示 $N$ 个不同的数字,需要 $k \geq \log_{2}N$ 个二进制位。所以,只有允许数组中存在重复的数字时,$O({kN})$ 才优于 $O(N\log N)$。
一般意义上输入数据的 $O(N\log N)$ 的性能已经说明了全部问题。这个讨论不那么有趣因为很少需要在 32 位计算机上对几十亿整数进行排序,[如果有谁的需求超出了 64 位计算机的极限,他一定没有告诉别人][6]。
--------------------------------------------------------------------------------
via: https://theartofmachinery.com/2019/01/05/sorting_is_nlogn.html
作者:[Simon Arneaud][a]
选题:[lujun9972][b]
译者:[silentdawn-zz](https://github.com/silentdawn-zz)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://theartofmachinery.com
[b]: https://github.com/lujun9972
[1]: http://hyperphysics.phy-astr.gsu.edu/hbase/Math/stirling.html
[2]: https://en.wikipedia.org/wiki/Shannon%27s_source_coding_theorem
[3]: https://en.wikipedia.org/wiki/Merge-insertion_sort
[4]: https://theartofmachinery.com/images/sorting_is_nlogn/sorting_algorithms_num_comparisons.svg
[5]: https://c9x.me/x86/html/file_module_x86_id_35.html
[6]: https://sortbenchmark.org/

View File

@ -0,0 +1,81 @@
[#]: collector: (lujun9972)
[#]: translator: (leommxj)
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-12591-1.html)
[#]: subject: (Reducing security risks with centralized logging)
[#]: via: (https://opensource.com/article/19/2/reducing-security-risks-centralized-logging)
[#]: author: (Hannah Suarez https://opensource.com/users/hcs)
通过集中日志记录来减少安全风险
======
> 集中日志并结构化待处理的日志数据可缓解与缺少日志相关的风险
![](https://img.linux.net.cn/data/attachment/album/202009/07/231016a8v8gva9gmc5hgv9.jpg)
日志记录和日志分析对于保护基础设施安全来说至关重要,尤其是当我们考虑到通用漏洞的时候。这篇文章基于我在 FOSDEM'19 上的闪电秀《[Let's use centralized log collection to make incident response teams happy][1]》,目的是提高大家对日志匮乏这种安全问题的重视,提供一种避免风险的方法,并且倡议更多的安全实践(利益声明: 我为 NXLog 工作)。
### 为什么要收集日志?为什么要集中日志记录?
确切的说,日志是写入磁盘的仅追加的记录序列。在实际生活中,日志可以在你尝试寻找异常的根源时帮助你调查基础设施的问题。当你有多个使用自己的标准与格式的日志的异构系统,并且想用一种可靠的方法来接收和处理它们的时候,挑战就来临了。这通常以元数据为代价的。集中日志记录解决方案需要共性,这种共性常常会去除许多开源日志记录工具所提供的丰富的元数据。
### 日志记录与监控匮乏的安全风险
<ruby>开源 Web 应用程序安全项目<rt>Open Web Application Security Project</rt></ruby>[OWASP][2])是一个为业界贡献了许多杰出项目(包括许多专注于软件安全的[工具][3]的非营利组织。OWASP 定期为应用开发人员和维护者报告最危险的安全挑战。在最新一版《[10 项最严重的 Web 应用程序安全风险][4]》中OWASP 将日志记录和监控匮乏加入了列表中。OWASP 警告下列情况会导致日志记录、检测、监控和主动响应的匮乏:
* 未记录重要的可审计性事件,如:登录、登录失败和高额交易。
* 告警和错误事件未能产生、产生不足或不清晰的日志信息。
* 日志信息仅在本地存储。
* 对于实时或准实时的主动攻击,应用程序无法检测、处理和告警。
可以通过集中日志记录(例如,不仅将日志本地存储)和结构化日志数据以进一步分析来缓解上述情形(例如,在告警仪表盘和安全套件中)。
举例来说, 假设一个 DNS 查询会导向名为 hacked.badsite.net 的恶意网站。通过 DNS 监控,管理员监控并且主动的分析 DNS 请求与响应。DNS 监控的效果依赖于充足的日志记录与收集来发现潜在问题,同样也依赖于结构化 DNS 日志的结果来进一步分析。
```
2019-01-29
Time (GMT)      Source                  Destination             Protocol-Info
12:42:42.112898 SOURCE_IP               xxx.xx.xx.x             DNS     Standard query 0x1de7  A hacked.badsite.net
```
你可以在 [NXLog 社区版][5] 中自己尝试一下这个例子,也可以尝试其他例子和代码片段。 (再次声明:我为 NXLog 工作)
### 重要的一点:非结构化数据与结构化数据
花费一点时间来考虑下日志数据格式是很重要的。例如,让我们来考虑以下日志消息:
```
debug1: Failed password for invalid user amy from SOURCE_IP port SOURCE_PORT ssh2
```
这段日志包含了一个预定义的结构,例如冒号前面的元数据关键词(`debug1`)然而,余下的日志字段是一个未结构化的字符串(`Failed password for invalid user amy from SOURCE_IP port SOURCE_PORT ssh2`)。因此,即便这个消息是人类可轻松阅读的格式,但它不是一个计算机容易解析的格式。
非结构化的事件数据存在局限性,包括难以解析、搜索和分析日志。重要的元数据通常以一种自由字符串的形式作为非结构化数据字段,就像上面的例子一样。日志管理员会在他们尝试标准化/归一化日志数据与集中日志源的过程中遇到这个问题。
### 接下来怎么做
除了集中和结构化日志之外确保你收集了正确的日志数据——Sysmon、PowerShell、Windows 事件日志、DNS 调试日志、ETW、内核监控、文件完整性监控、数据库日志、外部云日志等等。同样也要选用适当的工具和流程来来收集、汇总和帮助理解数据。
希望这对你从不同日志源中集中日志收集提供了一个起点将日志发送到仪表盘、监控软件、分析软件以及像安全性资讯与事件管理SIEM套件等外部源。
你的集中日志策略会是怎么样?请在评论中分享你的想法。
--------------------------------------------------------------------------------
via: https://opensource.com/article/19/2/reducing-security-risks-centralized-logging
作者:[Hannah Suarez][a]
选题:[lujun9972][b]
译者:[leommxj](https://github.com/leommxj)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://opensource.com/users/hcs
[b]: https://github.com/lujun9972
[1]: https://fosdem.org/2019/schedule/event/lets_use_centralized_log_collection_to_make_incident_response_teams_happy/
[2]: https://www.owasp.org/index.php/Main_Page
[3]: https://github.com/OWASP
[4]: https://www.owasp.org/index.php/Top_10-2017_Top_10
[5]: https://nxlog.co/products/nxlog-community-edition/download

View File

@ -0,0 +1,239 @@
[#]: collector: "lujun9972"
[#]: translator: "jlztan"
[#]: reviewer: "wxy"
[#]: publisher: "wxy"
[#]: url: "https://linux.cn/article-12634-1.html"
[#]: subject: "Monitor and Manage Docker Containers with Portainer.io (GUI tool) Part-1"
[#]: via: "https://www.linuxtechi.com/monitor-manage-docker-containers-portainer-part1/"
[#]: author: "Shashidhar Soppin https://www.linuxtechi.com/author/shashidhar/"
用 Portainer.io 来监控和管理 Docker 容器1
======
![](https://img.linux.net.cn/data/attachment/album/202009/20/225425zaepvexqvg7nndqv.jpg)
随着 Docker 的使用量越来越大,监控 Docker 容器正在变得更有挑战性。每天都有大量的 Docker 容器被创建,因此如何监控它们就变得非常重要。目前已经有一些内置的工具和技术,不过对它们进行配置有一些复杂。随着基于微服务的架构正在变成接下来事实上的标准,学会这种技术将为你的知识库再添一项新技能。
基于上述场景对一种轻量、健壮的镜像管理工具的需求日益增加。Portainer.io 解决了这个问题。 Portainer.io最新版本是 1.20.2)非常轻量,只需 2-3 个命令就可以配置好,已经在 Docker 用户中流行起来。
比起其他工具,这个工具有很多优势,其中一些如下所示:
* 轻量(安装此工具仅需 2 到 3 个命令,与此同时安装镜像的大小在 26 M 到 30 M 之间)
* 健壮且易用
* 可用于 Docker 监控和构建
* 提供对 Docker 环境的详细概况
* 可以管理容器、镜像、网络和卷
* Portainer 部署方便,仅需一个 Docker 命令(可以在任意地方运行)
* 可以对完整的 Docker 容器环境进行监控
Portainer 同时具有以下服务:
- 社区支持
- 企业支持
- 与合作伙伴 OEM 服务一起的专业服务
Portainer 的功能和特性如下:
1. 配备了漂亮的仪表盘,易于使用和监控
2. 自带大量内置模板,便于操作和创建
3. 服务支持(仅 OEM 和企业用户)
4. 对容器、镜像、网络、卷以及配置进行几乎实时的监控
5. 包含 Docker 集群监控功能
6. 功能多样的用户管理
另请阅读:[如何在 Ubuntu 16.04 / 18.04 LTS 版本中安装 Docker CE][1]
### 如何在 Ubuntu Linux / RHEL / CentOS 系统上安装和配置 Portainer.io
注意:下面的安装过程是在 Ubuntu 18.04 上完成的,但是对 RHEL 和 CentOS 同样适用,同时假设你已经在系统上安装了 Docker CE。
```
root@linuxtechi:~$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 18.04 LTS
Release: 18.04
Codename: bionic
root@linuxtechi:~$
```
为 Portainer 创建卷:
```
root@linuxtechi:~$ sudo docker volume create portainer_data
portainer_data
root@linuxtechi:~$
```
使用下面的 Docker 命令来运行 Portainer 容器:
```
root@linuxtechi:~$ sudo docker run -d -p 9000:9000 -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer
Unable to find image 'portainer/portainer:latest' locally
latest: Pulling from portainer/portainer
d1e017099d17: Pull complete
0b1e707a06d2: Pull complete
Digest: sha256:d6cc2c20c0af38d8d557ab994c419c799a10fe825e4aa57fea2e2e507a13747d
Status: Downloaded newer image for portainer/portainer:latest
35286de9f2e21d197309575bb52b5599fec24d4f373cc27210d98abc60244107
root@linuxtechi:~$
```
安装完成之后,通过主机或 Docker 的 IP 加上 Docker 引擎使用的 9000 端口在浏览器中打开 Portainer。
注意:如果 Docker 所在主机的系统防火墙开启,需要确保 9000 端口被放行,否则浏览器页面将无法打开。
在我这边,我的 Docker 主机/引擎的 IP 是 `192.168.1.16`,所以 URL 就是 `http://192.168.1.16:9000`
![Portainer-Login-User-Name-Password][2]
在创建管理员用户时,请确保密码是 8 个字符,同时用户名为 `admin`,然后点击 “Create User”。
接下来进入如下所示的页面,选中 “Local” 矩形框。
![Connect-Portainer-Local-Docker][4]
点击 “Connect”
可以看到 admin 用户的漂亮首页如下所示,
![Portainer-io-Docker-Monitor-Dashboard][6]
现在 Portainer 已经准备好运行和管理你的 Docker 容器了,同时也可用于容器监控。
### 在 Portainer 中管理容器镜像
![Portainer-Endpoints][8]
检查当前的状态,可以看到有两个容器已经在运行了,如果你创建另一个也会立即显示出来。
像下面这样,在命令行中启动一个或两个容器,
```
root@linuxtechi:~$ sudo docker run --name test -it debian
Unable to find image 'debian:latest' locally
latest: Pulling from library/debian
e79bb959ec00: Pull complete
Digest: sha256:724b0fbbda7fda6372ffed586670573c59e07a48c86d606bab05db118abe0ef5
Status: Downloaded newer image for debian:latest
root@linuxtechi:/#
```
然后在 Portainer 页面中点击刷新按钮(会出现一条让你确认的消息,点击上面的 “Continue”就可以像下面高亮显示的一样看到 3 个容器了。
![Portainer-io-new-container-image][10]
点击上图中红圈圈出来的 “containers”下一个页面会显示 “Dashboard Endpoint summary”。
![Portainer-io-Docker-Container-Dash][12]
在这个页面中,点击上图高亮和红圈圈出来的 “Containers”就可以对容器进行监控了。
### 以简单的方式对容器进行监控
继续上面的步骤,就会出现一个如下所示精致、漂亮的 “Container list” 页面。
![Portainer-Container-List][14]
所有的容器都可以在这里进行控制(停止、启动等等)。
1、在这个页面上停止我们之前启动的 “test” 容器(这是一个我们早先启动的 debian 容器)。
选中此容器前面的复选框然后点击上面的“Stop”按钮来停止。
![Stop-Container-Portainer-io-dashboard][16]
在命令行中,你也会看到这个容器现在已经停止或退出了:
```
root@linuxtechi:~$ sudo docker container ls -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d45902e717c0 debian "bash" 21 minutes ago Exited (0) 49 seconds ago test
08b96eddbae9 centos:7 "/bin/bash" About an hour ago Exited (137) 9 minutes ago mycontainer2
35286de9f2e2 portainer/portainer "/portainer" 2 hours ago Up About an hour 0.0.0.0:9000->9000/tcp compassionate_benz
root@linuxtechi:~$
```
2、现在在 Portainer 页面中启动已经停止的两个容器test 和 mycontainer2
选中已停止的这两个容器前面的复选框,然后点击 “Start”。
![Start-Containers-Portainer-GUI][18]
你会立即看到两条窗口提醒,内容是“容器成功启动”,并且两个容器的状态变为正在运行。
![Conatiner-Started-successfully-Portainer-GUI][20]
### 一步步探索其他多种选项和特性
1、点击高亮的“Images”你会看到如下页面
![Docker-Container-Images-Portainer-GUI][22]
这是可用的容器列表,其中一些可能没在运行。这些容器可以被导入、导出或者上传到不同的位置,截图如下所示。
![Upload-Docker-Container-Image-Portainer-GUI][24]
2、点击高亮的“Volumes”显示如下页面
![Volume-list-Portainer-io-gui][26]
3、通过下面的操作可以很容易的添加卷。点击添加卷按钮出现如下页面在名称输入框中输入卷名称例如 “myvol”然后点击 “Create the volume” 按钮:
![Volume-Creation-Portainer-io-gui][28]
新创建的卷如下所示(状态为未使用):
![Volume-unused-Portainer-io-gui][30]
### 结论
通过上面的安装步骤,你可以到配置和使用 Portainer.io 的多种选项是多么简单和精美,它提供了用于构建和监控 Docker 容器的多种功能和选项。如前所述,这个一个非常轻量的工具,因此不会给主机系统增加任何负担。下一组选项将在本系列的第 2 部分中进行探讨。
另请阅读: [用 Portainer.io 来监控和管理 Docker 容器2][32]
--------------------------------------------------------------------------------
via: https://www.linuxtechi.com/monitor-manage-docker-containers-portainer-part1/
作者:[Shashidhar Soppin][a]
选题:[lujun9972][b]
译者:[jlztan](https://github.com/jlztan)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://www.linuxtechi.com/author/shashidhar/
[b]: https://github.com/lujun9972
[1]: https://www.linuxtechi.com/how-to-setup-docker-on-ubuntu-server-16-04/
[2]: https://www.linuxtechi.com/wp-content/uploads/2019/05/Portainer-Login-User-Name-Password-1024x681.jpg
[3]: https://www.linuxtechi.com/wp-content/uploads/2019/05/Portainer-Login-User-Name-Password.jpg
[4]: https://www.linuxtechi.com/wp-content/uploads/2019/05/Connect-Portainer-Local-Docker-1024x538.jpg
[5]: https://www.linuxtechi.com/wp-content/uploads/2019/05/Connect-Portainer-Local-Docker.jpg
[6]: https://www.linuxtechi.com/wp-content/uploads/2019/05/Portainer-io-Docker-Monitor-Dashboard-1024x544.jpg
[7]: https://www.linuxtechi.com/wp-content/uploads/2019/05/Portainer-io-Docker-Monitor-Dashboard.jpg
[8]: https://www.linuxtechi.com/wp-content/uploads/2019/05/Portainer-Endpoints-1024x252.jpg
[9]: https://www.linuxtechi.com/wp-content/uploads/2019/05/Portainer-Endpoints.jpg
[10]: https://www.linuxtechi.com/wp-content/uploads/2019/05/Portainer-io-new-container-image-1024x544.jpg
[11]: https://www.linuxtechi.com/wp-content/uploads/2019/05/Portainer-io-new-container-image.jpg
[12]: https://www.linuxtechi.com/wp-content/uploads/2019/05/Portainer-io-Docker-Container-Dash-1024x544.jpg
[13]: https://www.linuxtechi.com/wp-content/uploads/2019/05/Portainer-io-Docker-Container-Dash.jpg
[14]: https://www.linuxtechi.com/wp-content/uploads/2019/05/Portainer-Container-List-1024x538.jpg
[15]: https://www.linuxtechi.com/wp-content/uploads/2019/05/Portainer-Container-List.jpg
[16]: https://www.linuxtechi.com/wp-content/uploads/2019/05/Stop-Container-Portainer-io-dashboard-1024x447.jpg
[17]: https://www.linuxtechi.com/wp-content/uploads/2019/05/Stop-Container-Portainer-io-dashboard.jpg
[18]: https://www.linuxtechi.com/wp-content/uploads/2019/05/Start-Containers-Portainer-GUI-1024x449.jpg
[19]: https://www.linuxtechi.com/wp-content/uploads/2019/05/Start-Containers-Portainer-GUI.jpg
[20]: https://www.linuxtechi.com/wp-content/uploads/2019/05/Conatiner-Started-successfully-Portainer-GUI-1024x538.jpg
[21]: https://www.linuxtechi.com/wp-content/uploads/2019/05/Conatiner-Started-successfully-Portainer-GUI.jpg
[22]: https://www.linuxtechi.com/wp-content/uploads/2019/05/Docker-Container-Images-Portainer-GUI-1024x544.jpg
[23]: https://www.linuxtechi.com/wp-content/uploads/2019/05/Docker-Container-Images-Portainer-GUI.jpg
[24]: https://www.linuxtechi.com/wp-content/uploads/2019/05/Upload-Docker-Container-Image-Portainer-GUI-1024x544.jpg
[25]: https://www.linuxtechi.com/wp-content/uploads/2019/05/Upload-Docker-Container-Image-Portainer-GUI.jpg
[26]: https://www.linuxtechi.com/wp-content/uploads/2019/05/Volume-list-Portainer-io-gui-1024x544.jpg
[27]: https://www.linuxtechi.com/wp-content/uploads/2019/05/Volume-list-Portainer-io-gui.jpg
[28]: https://www.linuxtechi.com/wp-content/uploads/2019/05/Volume-Creation-Portainer-io-gui-1024x544.jpg
[29]: https://www.linuxtechi.com/wp-content/uploads/2019/05/Volume-Creation-Portainer-io-gui.jpg
[30]: https://www.linuxtechi.com/wp-content/uploads/2019/05/Volume-unused-Portainer-io-gui-1024x544.jpg
[31]: https://www.linuxtechi.com/wp-content/uploads/2019/05/Volume-unused-Portainer-io-gui.jpg
[32]: https://www.linuxtechi.com/monitor-manage-docker-containers-portainer-io-part-2/

View File

@ -0,0 +1,271 @@
[#]: collector: (lujun9972)
[#]: translator: (wxy)
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-12658-1.html)
[#]: subject: (Advance your awk skills with two easy tutorials)
[#]: via: (https://opensource.com/article/19/10/advanced-awk)
[#]: author: (Dave Neary https://opensource.com/users/dneary)
通过两个简单的教程来提高你的 awk 技能
======
> 超越单行的 awk 脚本,学习如何做邮件合并和字数统计。
![](https://img.linux.net.cn/data/attachment/album/202009/28/154624jk8w4ez6oujbur8j.jpg)
`awk` 是 Unix 和 Linux 用户工具箱中最古老的工具之一。`awk` 由 Alfred Aho、Peter Weinberger 和 Brian Kernighan即工具名称中的 A、W 和 K在 20 世纪 70 年代创建,用于复杂的文本流处理。它是流编辑器 `sed` 的配套工具,后者是为逐行处理文本文件而设计的。`awk` 支持更复杂的结构化程序,是一门完整的编程语言。
本文将介绍如何使用 `awk` 完成更多结构化的复杂任务,包括一个简单的邮件合并程序。
### awk 的程序结构
`awk` 脚本是由 `{}`(大括号)包围的功能块组成,其中有两个特殊的功能块,`BEGIN` 和 `END`,它们在处理第一行输入流之前和最后一行处理之后执行。在这两者之间,块的格式为:
```
模式 { 动作语句 }
```
当输入缓冲区中的行与模式匹配时,每个块都会执行。如果没有包含模式,则函数块在输入流的每一行都会执行。
另外,以下语法可以用于在 `awk` 中定义可以从任何块中调用的函数。
```
function 函数名(参数列表) { 语句 }
```
这种模式匹配块和函数的组合允许开发者结构化的 `awk` 程序,以便重用和提高可读性。
### awk 如何处理文本流
`awk` 每次从输入文件或流中一行一行地读取文本,并使用字段分隔符将其解析成若干字段。在 `awk` 的术语中,当前的缓冲区是一个*记录*。有一些特殊的变量会影响 `awk` 读取和处理文件的方式:
* `FS`<ruby>字段分隔符<rt>field separator</rt></ruby>)。默认情况下,这是任何空格字符(空格或制表符)。
* `RS`<ruby>记录分隔符<rt>record separator</rt></ruby>)。默认情况下是一个新行(`n`)。
* `NF`<ruby>字段数<rt>number of fields</rt></ruby>)。当 `awk` 解析一行时,这个变量被设置为被解析出字段数。
* `$0:` 当前记录。
* `$1`、`$2`、`$3` 等:当前记录的第一、第二、第三等字段。
* `NR`<ruby>记录数<rt>number of records</rt></ruby>)。迄今已被 `awk` 脚本解析的记录数。
影响 `awk` 行为的变量还有很多,但知道这些已经足够开始了。
### 单行 awk 脚本
对于一个如此强大的工具来说,有趣的是,`awk` 的大部分用法都是基本的单行脚本。也许最常见的 `awk` 程序是打印 CSV 文件、日志文件等输入行中的选定字段。例如,下面的单行脚本从 `/etc/passwd` 中打印出一个用户名列表:
```
awk -F":" '{print $1 }' /etc/passwd
```
如上所述,`$1` 是当前记录中的第一个字段。`-F` 选项将 `FS` 变量设置为字符 `:`
字段分隔符也可以在 `BEGIN` 函数块中设置:
```
awk 'BEGIN { FS=":" } {print $1 }' /etc/passwd
```
在下面的例子中,每一个 shell 不是 `/sbin/nologin` 的用户都可以通过在该块前面加上匹配模式来打印出来:
```
awk 'BEGIN { FS=":" } ! /\/sbin\/nologin/ {print $1 }' /etc/passwd
```
### awk 进阶:邮件合并
现在你已经掌握了一些基础知识,尝试用一个更具有结构化的例子来深入了解 `awk`:创建邮件合并。
邮件合并使用两个文件,其中一个文件(在本例中称为 `email_template.txt`)包含了你要发送的电子邮件的模板:
```
From: Program committee <pc@event.org>
To: {firstname} {lastname} <{email}>
Subject: Your presentation proposal
Dear {firstname},
Thank you for your presentation proposal:
{title}
We are pleased to inform you that your proposal has been successful! We
will contact you shortly with further information about the event
schedule.
Thank you,
The Program Committee
```
而另一个则是一个 CSV 文件(名为 `proposals.csv`),里面有你要发送邮件的人:
```
firstname,lastname,email,title
Harry,Potter,hpotter@hogwarts.edu,"Defeating your nemesis in 3 easy steps"
Jack,Reacher,reacher@covert.mil,"Hand-to-hand combat for beginners"
Mickey,Mouse,mmouse@disney.com,"Surviving public speaking with a squeaky voice"
Santa,Claus,sclaus@northpole.org,"Efficient list-making"
```
你要读取 CSV 文件,替换第一个文件中的相关字段(跳过第一行),然后把结果写到一个叫 `acceptanceN.txt` 的文件中,每解析一行就递增文件名中的 `N`
`awk` 程序写在一个叫 `mail_merge.awk` 的文件中。在 `awk` 脚本中的语句用 `;` 分隔。第一个任务是设置字段分隔符变量和其他几个脚本需要的变量。你还需要读取并丢弃 CSV 中的第一行,否则会创建一个以 `Dear firstname` 开头的文件。要做到这一点,请使用特殊函数 `getline`,并在读取后将记录计数器重置为 0。
```
BEGIN {
  FS=",";
  template="email_template.txt";
  output="acceptance";
  getline;
  NR=0;
}
```
主要功能非常简单:每处理一行,就为各种字段设置一个变量 —— `firstname`、`lastname`、`email` 和 `title`。模板文件被逐行读取,并使用函数 `sub` 将任何出现的特殊字符序列替换为相关变量的值。然后将该行以及所做的任何替换输出到输出文件中。
由于每行都要处理模板文件和不同的输出文件,所以在处理下一条记录之前,需要清理和关闭这些文件的文件句柄。
```
{
        # 从输入文件中读取关联字段
        firstname=$1;
        lastname=$2;
        email=$3;
        title=$4;
        # 设置输出文件名
        outfile=(output NR ".txt");
        # 从模板中读取一行,替换特定字段,
        # 并打印结果到输出文件。
        while ( (getline ln &lt; template) &gt; 0 )
        {
                sub(/{firstname}/,firstname,ln);
                sub(/{lastname}/,lastname,ln);
                sub(/{email}/,email,ln);
                sub(/{title}/,title,ln);
                print(ln) &gt; outfile;
        }
        # 关闭模板和输出文件,继续下一条记录
        close(outfile);
        close(template);
}
```
你已经完成了! 在命令行上运行该脚本:
```
awk -f mail_merge.awk proposals.csv
```
```
awk -f mail_merge.awk < proposals.csv
```
你会在当前目录下发现生成的文本文件。
### awk 进阶:字频计数
`awk` 中最强大的功能之一是关联数组,在大多数编程语言中,数组条目通常由数字索引,但在 `awk` 中,数组由一个键字符串进行引用。你可以从上一节的文件 `proposals.txt` 中存储一个条目。例如,在一个单一的关联数组中,像这样:
```
        proposer["firstname"]=$1;
        proposer["lastname"]=$2;
        proposer["email"]=$3;
        proposer["title"]=$4;
```
这使得文本处理变得非常容易。一个使用了这个概念的简单的程序就是词频计数器。你可以解析一个文件,在每一行中分解出单词(忽略标点符号),对行中的每个单词进行递增计数器,然后输出文本中出现的前 20 个单词。
首先,在一个名为 `wordcount.awk` 的文件中,将字段分隔符设置为包含空格和标点符号的正则表达式:
```
BEGIN {
# ignore 1 or more consecutive occurrences of the characters
# in the character group below
FS="[ .,:;()<>{}@!\"'\t]+";
}
```
接下来,主循环函数将遍历每个字段,忽略任何空字段(如果行末有标点符号,则会出现这种情况),并递增行中单词数:
```
{
        for (i = 1; i &lt;= NF; i++) {
                if ($i != "") {
                        words[$i]++;
                }
        }
}
```
最后,处理完文本后,使用 `END` 函数打印数组的内容,然后利用 `awk` 的能力,将输出的内容用管道输入 shell 命令,进行数字排序,并打印出 20 个最常出现的单词。
```
END {
        sort_head = "sort -k2 -nr | head -n 20";
        for (word in words) {
                printf "%s\t%d\n", word, words[word] | sort_head;
        }
        close (sort_head);
}
```
在这篇文章的早期草稿上运行这个脚本,会产生这样的输出:
```
[dneary@dhcp-49-32.bos.redhat.com]$ awk -f wordcount.awk < awk_article.txt
the 79
awk 41
a 39
and 33
of 32
in 27
to 26
is 25
line 23
for 23
will 22
file 21
we 16
We 15
with 12
which 12
by 12
this 11
output 11
function 11
```
### 下一步是什么?
如果你想了解更多关于 `awk` 编程的知识,我强烈推荐 Dale Dougherty 和 Arnold Robbins 所著的《[Sed 和 awk][8]》这本书。
`awk` 编程进阶的关键之一是掌握“扩展正则表达式”。`awk` 为你可能已经熟悉的 sed [正则表达式][9]语法提供了几个强大的补充。
另一个学习 `awk` 的好资源是 [GNU awk 用户指南][10]。它有一个完整的 `awk` 内置函数库的参考资料,以及很多简单和复杂的 `awk` 脚本的例子。
--------------------------------------------------------------------------------
via: https://opensource.com/article/19/10/advanced-awk
作者:[Dave Neary][a]
选题:[lujun9972][b]
译者:[wxy](https://github.com/wxy)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://opensource.com/users/dneary
[b]: https://github.com/lujun9972
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/checklist_hands_team_collaboration.png?itok=u82QepPk (a checklist for a team)
[2]: mailto:pc@event.org
[3]: mailto:hpotter@hogwarts.edu
[4]: mailto:reacher@covert.mil
[5]: mailto:mmouse@disney.com
[6]: mailto:sclaus@northpole.org
[7]: mailto:dneary@dhcp-49-32.bos.redhat.com
[8]: https://www.amazon.com/sed-awk-Dale-Dougherty/dp/1565922255/book
[9]: https://en.wikibooks.org/wiki/Regular_Expressions/POSIX-Extended_Regular_Expressions
[10]: https://www.gnu.org/software/gawk/manual/gawk.html

View File

@ -1,44 +1,38 @@
[#]: collector: (lujun9972)
[#]: translator: (gxlct008)
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-12615-1.html)
[#]: subject: (3 Methods to Install the Latest PHP 7 Package on CentOS/RHEL 7 and CentOS/RHEL 6)
[#]: via: (https://www.2daygeek.com/install-php-7-on-centos-6-centos-7-rhel-7-redhat-7/)
[#]: author: (Magesh Maruthamuthu https://www.2daygeek.com/author/magesh/)
3 Methods to Install the Latest PHP 7 Package on CentOS/RHEL 7 and CentOS/RHEL 6
在 CentOS/RHEL 7/6 上安装最新 PHP 7 软件包的 3 种方法
======
PHP is the most popular open-source general-purpose scripting language and is widely used for web development.
![](https://img.linux.net.cn/data/attachment/album/202009/14/235431i92iqjj2we0vegyj.jpg)
Its part of the LAMP stack application suite and is used to create dynamic websites.
PHP 是最流行的开源通用脚本语言,被广泛用于 Web 开发。它是 LAMP 栈应用程序套件的一部分,用于创建动态网站。流行的 CMS 应用程序 WordPressJoomla 和 Drupal 都是用 PHP 语言开发的。这些应用程序的安装和配置都需要 PHP 7。PHP 7 可以更快地加载你的 Web 应用程序,并消耗更少的服务器资源。
Popular CMS applications WordPress, Joomla and Drupal are developed in PHP language.
在默认情况下CentOS/RHEL 6 操作系统在其官方存储库中提供 PHP 5.3,而 CentOS/RHEL 7 则提供 PHP 5.4。
These applications require PHP 7 for their installation and configuration.
在本文中,我们将向你展示如何在 CentOS/RHEL 7 和 CentOS/RHEL 6 系统上安装最新版本的 PHP。
PHP 7 loads your web application faster and consumes less server resources.
这可以通过在系统中添加必要的 [附加第三方 RPM 存储库][1] 来完成。
By default the CentOS/RHEL 6 operating system provides PHP 5.3 in their official repository and CentOS/RHEL 7 provides PHP 5.4.
### 方法-1如何使用软件集合存储库SCL在 CentOS 6/7 上安装 PHP 7
In this article we will show you how to install the latest version of PHP on CentOS/RHEL 7 and CentOS/RHEL 6 systems.
现在SCL 存储库由 CentOS SIG 维护,该组织不仅重新构建了 Red Hat Software Collections还提供了自己的一些其他软件包。
This can be done by adding the necessary **[additional third-party RPM repository][1]** to the system.
它包含各种程序的较新版本,这些程序可以与现有的旧软件包一起安装,并可以使用 `scl` 命令调用。
### Method-1 : How to Install PHP 7 on CentOS 6/7 Using the Software Collections Repository (SCL)
The SCL repository is now maintained by a CentOS SIG, which rebuilds the Red Hat Software Collections and also provides some additional packages of their own.
It contains newer versions of various programs that can be installed alongside existing older packages and invoked by using the scl command.
Run the following **[yum command][2]** to install Software Collections Repository (SCL) on CentOS
要想在 CentOS 上安装软件集合存储库SCL请运行以下 [yum 命令][2]
```
# yum install centos-release-scl
```
Run the following command to verify the PHP 7 version available in the scl repository.
运行以下命令可以验证 SCL 存储库中可用的 PHP 7 版本:
```
# yum --disablerepo="*" --enablerepo="centos-sclo-rh" list *php
@ -54,21 +48,21 @@ rh-php71-php.x86_64 7.1.30-2.el7 centos-sclo-rh
rh-php72-php.x86_64 7.2.24-1.el7 centos-sclo-rh
```
Run the command below to install the PHP 7.2 on your system from scl.
运行以下命令可以从 SCL 中安装 PHP 7.2 到你的系统中:
```
# yum --disablerepo="*" --enablerepo="centos-sclo-rh" install rh-php72-php
```
If you need to install additional modules for PHP 7.2, you can install them by running the command format below. For instance, you can install the **“gd”** and **“pdo”** packages by executing the command below.
如果需要为 PHP 7.2 安装其他模块,则可以通过运行以下命令格式来安装它们。 例如,你可以通过执行以下命令来安装 `gd``pdo` 软件包:
```
# yum --disablerepo="*" --enablerepo="centos-sclo-rh" install rh-php72-php-gd rh-php72-php-pdo
```
### Method-1a : How to Install PHP 7 on RHEL 7 Using the Software Collections Repository (SCL)
### 方法-1a如何使用软件集合存储库SCL在 RHEL 7 上安装 PHP 7
For Red Hat 7, enable the following repositories to install the latest PHP 7 package.
对于 Red Hat 7启用以下存储库以安装最新的 PHP 7 软件包:
```
# sudo subscription-manager repos --enable rhel-7-server-extras-rpms
@ -76,27 +70,27 @@ For Red Hat 7, enable the following repositories to install the latest PHP 7 pac
# sudo subscription-manager repos --enable rhel-server-rhscl-7-rpms
```
Run the command below to search the available PHP 7 version from the RHSCL repository.
运行以下命令从 RHSCL 库中搜索可用的 PHP 7 版本:
```
# yum search rh-php*
```
You can easily install PHP 7.3 on the RHEL 7 machine by running the command below from the RHSCL repository.
运行以下命令,你可以轻松地从 RHSCL 存储库中把 PHP7.3 安装到你的 RHEL 7 计算机上:
```
# yum install rh-php73
```
### Method-2 : How to Install PHP 7 on CentOS 6/7 Using the Remi Repository
### 方法-2如何使用 Remi 存储库在 CentOS 6/7 上安装 PHP 7
The **[Remi repository][3]** stores and maintains the latest version of PHP packages with a large collection of libraries, extensions and tools. Some of them are back-ported from Fedora and EPEL.
[Remi 存储库][3] 存储和维护着最新版本的 PHP 软件包,其中包含大量的库,扩展和工具。 有一些是从 Fedora 和 EPEL 反向移植的。
This is a CentOS community-recognized repository and doesnt modify or affect any underlying packages.
这是 CentOS 社区认可的存储库,它不会修改或影响任何基础软件包。
As a prerequisite, this installs the **[EPEL repository][4]** if it is not already installed on your system.
作为前提条件,如果你的系统上尚未安装 [EPEL 存储库][4],该操作会首先安装它。
You can easily find the available version of the PHP 7 package from the Remy repository because it adds a separate repo to each version. You can view them using the **[ls command][5]**.
你可以轻松地从 Remi 存储库中找到可用的 PHP 7 软件包版本,因为它会为每个版本添加一个单独的存储库。 你可以使用 [ls 命令][5] 查看它们:
```
# ls -lh /etc/yum.repos.d/remi-php*
@ -109,41 +103,41 @@ You can easily find the available version of the PHP 7 package from the Remy rep
-rw-r--r--. 1 root root 1.3K Sep 6 01:31 /etc/yum.repos.d/remi-php74.repo
```
You can easily install PHP 7.4 on the CentOS 6/7 systems by running the command below from the remi repository.
运行以下命令,你可以轻松地从 Remi 存储库中把 PHP7.4 安装到你的 CentOS 6/7 计算机上:
```
# yum --disablerepo="*" --enablerepo="remi-php74" install php php-mcrypt php-cli php-gd php-curl php-mysql php-ldap php-zip php-fileinfo
```
### Method-2a : How to Install PHP 7 on RHEL 7 Using the Remi Reposiotry
### 方法-2a如何使用 Remi 存储库在 RHEL 7 上安装 PHP 7
For Red Hat 7, install the following repositories to install the latest PHP 7 package.
对于 Red Hat 7请安装以下存储库以安装最新的 PHP 7 软件包。
To install EPEL Repository on RHEL 7
在 RHEL 7 上安装 EPEL 存储库:
```
# yum install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
```
To install Remi Repository on RHEL 7
在 RHEL 7 上安装 Remi 存储库:
```
# yum install http://rpms.remirepo.net/enterprise/remi-release-7.rpm
```
To enable the optional RPMS repository.
启用可选的 RPMS 存储库:
```
# subscription-manager repos --enable=rhel-7-server-optional-rpms
```
You can easily install PHP 7.4 on the RHEL 7 systems by running the below command from the remi repository.
运行以下命令,可以轻松地从 remi 存储库中,把 PHP 7.4 安装在 RHEL 7 系统上:
```
# yum --disablerepo="*" --enablerepo="remi-php74" install php php-mcrypt php-cli php-gd php-curl php-mysql php-ldap php-zip php-fileinfo
```
To verify the PHP 7 installation, run the following command
要验证 PHP 7 的安装版本,请运行以下命令:
```
# php -v
@ -153,19 +147,19 @@ Copyright (c) The PHP Group
Zend Engine v3.4.0, Copyright (c) Zend Technologies
```
### Method-3 : How to Install PHP 7 on CentOS 6/7 Using the IUS Community Repository
### 方法-3如何使用 IUS 社区存储库在 CentOS 6/7 上安装 PHP 7
IUS Community is a CentOS Community Approved third-party RPM repository which contains latest upstream versions of PHP, Python, MySQL, etc.., packages for Enterprise Linux (RHEL &amp; CentOS) 5, 6 &amp; 7.
IUS 社区存储库是 CentOS 社区批准的第三方 RPM 存储库,其中包含 PHP、Python、MySQL 等软件的最新上游版本,以及用于 Enterprise LinuxRHEL 和 CentOS5、6 和 7 的软件包。
**[IUS Community Repository][6]** have dependency with EPEL Repository so we have to install EPEL repository prior to IUS repository installation. Follow the below steps to install &amp; enable EPEL &amp; IUS Community Repository to RPM systems and install the packages.
[IUS 社区存储库][6] 与 EPEL 存储库具有依赖性,因此我们必须在安装 IUS 存储库之前先安装 EPEL 存储库。 请按照以下步骤将 EPEL 和 IUS 社区存储库安装并启用到 RPM 系统,然后再安装软件包。
EPEL package is included in the CentOS Extras repository and enabled by default so, we can install this by running below command.
EPEL软件包包含在 CentOS Extras 存储库中,并默认启用,因此,我们可以通过运行以下命令来安装它:
```
# yum install epel-release
```
Download IUS Community Repository Shell script
下载 IUS 社区存储库的 Shell 脚本如下:
```
# curl 'https://setup.ius.io/' -o setup-ius.sh
@ -174,13 +168,13 @@ Download IUS Community Repository Shell script
100 1914 100 1914 0 0 6563 0 --:--:-- --:--:-- --:--:-- 133k
```
Install/Enable IUS Community Repository.
安装/启用 IUS 社区存储库:
```
# sh setup-ius.sh
```
Run the following command to check available PHP 7 version in the IUS repository.
运行如下命来检查 IUS 存储库中可用的 PHP 7 版本:
```
# yum --disablerepo="*" --enablerepo="ius" list *php7*
@ -200,7 +194,7 @@ php71u-devel.x86_64 7.1.33-1.el7.ius
php71u-embedded.x86_64 7.1.33-1.el7.ius ius
```
You can easily install PHP 7.3 on the CentOS 6/7 systems by running the command below from the IUS Community repository.
运行以下命令你可以轻松地从 IUS 存储库中安装 PHP 7.3 到你 CentOS 6/7 系统上:
```
# yum --disablerepo="*" --enablerepo="ius" install php73-common php73-cli php73-gd php73-gd php73-mysqlnd php73-ldap php73-soap php73-mbstring
@ -212,8 +206,8 @@ via: https://www.2daygeek.com/install-php-7-on-centos-6-centos-7-rhel-7-redhat-7
作者:[Magesh Maruthamuthu][a]
选题:[lujun9972][b]
译者:[译者ID](https://github.com/译者ID)
校对:[校对者ID](https://github.com/校对者ID)
译者:[gxlct008](https://github.com/gxlct008)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出

View File

@ -0,0 +1,189 @@
[#]: collector: (lujun9972)
[#]: translator: (wxy)
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-12596-1.html)
[#]: subject: (Tweaking history on Linux)
[#]: via: (https://www.networkworld.com/article/3537214/tweaking-history-on-linux.html)
[#]: author: (Sandra Henry-Stocker https://www.networkworld.com/author/Sandra-Henry_Stocker/)
在 Linux 上调整命令历史
======
> 在 Linux 系统上bash shell 的 history 命令可以方便地回顾和重用命令,但是你要控制它记住多少,忘记多少,有很多事情要做。
![](https://img.linux.net.cn/data/attachment/album/202009/08/232418c2121m2euw3aaw58.jpg)
Linux 系统中的 bash `history` 命令有助于记住你以前运行过的命令,并重复这些命令,而不必重新输入。
如果可以的话,你肯定会很高兴不用翻阅十几页的手册,每过一会再次列出你的文件,而是通过输入 `history` 查看以前运行的命令。在这篇文章中,我们将探讨如何让 `history` 命令记住你希望它记住的内容,并忘记那些可能没有什么“历史价值”的命令。
### 查看你的命令历史
要查看以前运行过的命令,你只需输入 `history`。你可能会看到一长串命令。记忆的命令数量取决于在 `~/.bashrc` 文件中设置的名为 `$HISTSIZE` 的环境变量,但是如果你想保存更多或更少的命令,你可以根据你的需要改变这个设置。
要查看历史记录,请使用 `history` 命令:
```
$ history
209 uname -v
210 date
211 man chage
...
```
要查看将显示的最大命令数量:
```
$ echo $HISTSIZE
500
```
你可以通过运行这样的命令来改变 `$HISTSIZE` 并使之永久化:
```
$ export HISTSIZE=1000
$ echo "HISTSIZE=1000" >> ~/.bashrc
```
在为你保留多少历史记录和当你输入 `history` 时显示多少历史记录之间也有区别。`$HISTSIZE` 变量控制显示多少历史记录,而 `$HISTFILESIZE` 变量控制在你的 `.bash_history` 文件中保留多少命令。
```
$ echo $HISTSIZE
1000
$ echo $HISTFILESIZE
2000
```
你可以通过计算历史文件中的行数来验证第二个变量:
```
$ wc -l .bash_history
2000 .bash_history
```
需要注意的是,在登录会话中输入的命令在注销前不会被添加到你的 `.bash_history` 文件中,尽管它们会立即显示在 `history` 命令输出中。
### 使用历史
有三种方法可以重发你在 `history` 中发现的命令。最简单的方法,特别是当你想重用的命令是最近运行的时候,通常是输入一个 `!` 后面跟上命令中足够多的首字母来唯一地识别它。
```
$ !u
uname -v
#37-Ubuntu SMP Thu Mar 26 20:41:27 UTC 2020
```
另一种简单的重复命令的方法是,只需按上箭头键,直到显示了该命令,然后按回车键。
另外,如果你运行 `history` 命令,并看到你想重新运行的命令被列出,你可以输入一个 `!` 后面跟着命令左边显示的序号。
```
$ !209
uname -v
#37-Ubuntu SMP Thu Mar 26 20:41:27 UTC 2020
```
### 隐藏历史
如果你想在一段时间内停止记录命令,你可以使用这个命令:
```
$ set +o history
```
当你输入 `history` 时,你输入的命令不会显示出来,当你退出会话或退出终端时,它们也不会被添加到你的 `.bash_history` 文件中。
要取消这个设置,使用 `set -o history`
要使它永久化,你可以把它添加到你的 `.bashrc` 文件中,尽管不使用命令历史记录通常不是一个好主意。
```
$ echo 'set +o history' >> ~/.bashrc
```
要暂时清除历史记录,这样在输入 `history` 时只显示之后输入的命令,可以使用 `history -c`(清除)命令:
```
$ history | tail -3
209 uname -v
210 date
211 man chage
$ history -c
$ history
1 history
```
注意:在输入 `history -c` 后输入的命令不会被添加到 `.bash_history` 文件中。
### 控制历史
许多系统上的 `history` 命令的设置会默认包括一个名为 `$HISTCONTROL` 的变量,以确保即使你连续运行同一命令七次,也只会被记住一次。它还可以确保你在首先输入一个或多个空格后跟着的命令将从你的命令历史记录中忽略。
```
$ grep HISTCONTROL .bashrc
HISTCONTROL=ignoreboth
```
`ignoreboth` 的意思是“忽略重复的命令和以空格开头的命令”。例如,如果你输入这些命令:
```
$ echo try this
$ date
$ date
$ date
$ pwd
$ history
```
你的 `history` 命令应该像这样报告:
```
$ history
$ echo try this
$ date
$ history
```
请注意,连续的 `date` 命令被缩减为一条,以空格缩进的命令被省略。
### 忽略历史
要忽略某些命令,使它们在你输入 `history` 时不会出现,也不会被添加到你的 `.bash_history` 文件中,可以使用 `$HISTIGNORE` 设置。例如:
```
$ export HISTIGNORE=”history:cd:exit:ls:pwd:man”
```
这个设置将导致所有的 `history`、`cd`、`exit`、`ls`、`pwd` 和 `man` 命令从你的 `history` 命令的输出和 `.bash_history` 文件中被忽略。
如果你想把这个设置变成永久性的,你必须把它添加到你的 `.bashrc` 文件中。
```
$ echo 'HISTIGNORE="history:cd:exit:ls:pwd:man"' >> .bashrc
```
这个设置只是意味着当你回看以前运行的命令时,列表不会被你在查看命令历史记录时不想看到的命令所干扰。
### 记住、忽略和忘记过去的命令
命令历史记录很有用,因为它可以帮助你记住最近使用过的命令,并提醒你最近所做的更改。它还可以让你更容易地重新运行命令,特别是那些有一串参数但你不一定想重新创建的命令。定制你的历史设置可以让你对命令历史的使用变得更容易,更有效率。
--------------------------------------------------------------------------------
via: https://www.networkworld.com/article/3537214/tweaking-history-on-linux.html
作者:[Sandra Henry-Stocker][a]
选题:[lujun9972][b]
译者:[wxy](https://github.com/wxy)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://www.networkworld.com/author/Sandra-Henry_Stocker/
[b]: https://github.com/lujun9972
[1]: https://unsplash.com/photos/iqeG5xA96M4
[2]: https://creativecommons.org/publicdomain/zero/1.0/
[3]: https://www.networkworld.com/blog/itaas-and-the-corporate-storage-technology/?utm_source=IDG&utm_medium=promotions&utm_campaign=HPE22140&utm_content=sidebar (ITAAS and Corporate Storage Strategy)
[4]: https://www.facebook.com/NetworkWorld/
[5]: https://www.linkedin.com/company/network-world

View File

@ -0,0 +1,77 @@
[#]: collector: (lujun9972)
[#]: translator: (chenmu-kk)
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-12650-1.html)
[#]: subject: (Wi-Fi 6E: When its coming and what its good for)
[#]: via: (https://www.networkworld.com/article/3563832/wi-fi-6e-when-its-coming-and-what-its-good-for.html)
[#]: author: (Zeus Kerravala https://www.networkworld.com/author/Zeus-Kerravala/)
Wi-Fi 6E它何时到来又有何作用
======
> Extreme Networks 的一位高管表示,近来专用于 Wi-Fi 的新无线频谱可以提供更多的信道和更高的密度部署,但是要支持它的设备要到 2020 年才能得到广泛部署。
![](https://images.idgesg.net/images/article/2019/09/cso_wireless_network_management_security_alert_iot_internet_of_things_thinkstock_685417850_1200x800-100810374-large.jpg)
今年开春 [FCC 在 6GHz 频段内开辟了一系列新的未授权的无线频谱][1],该频谱旨在用于 Wi-Fi以提供更低的延迟和更快的数据速率。新频谱的范围更短与已经专用于 Wi-Fi 的频段相比支持的信道也更多,因此适合在体育场馆等高密度区域部署。
为了进一步了解什么是 Wi-Fi 6E 以及它与 Wi-Fi 6 有何不同,我最近与网络解决方案提供商 Extreme Networks 的产品管理总监 Perry Correll 进行了交谈。
**了解更多关于 5G 和 WiFi 6 的信息**
* [什么是 5G相较于 4G 它更好吗?][2]
* [如何确定 WiFi 6 是否适合你?][3]
* [什么是 MU-MIMO为什么它在你的无线路由器中不可或缺][4]
* [何时使用 5G何时使用 WiFi 6][5]
* [企业如何为5G网络做准备呢][6]
**Kerravala Wi-Fi 6 似乎得到了许多热捧,而 Wi-Fi 6E 却没有。为什么?**
**Correll** 所有这些带 666 的数字会混乱得会吓死你。我们已经有了 Wi-Fi 6、Wi-Fi 6E之后Wi-Fi 6 还有其它的增强功能,比如多用户多入多出(多用户 MIMO功能。还有就是 6GHz 频谱,但这并不是 Wi-Fi 6 的名称的由来:它是第六代 Wi-Fi。最重要的是我们刚刚掌握了 5G并且已经在谈论 6G —— 认真的讲,这更容易搞混了。
**Kerravala 为什么我们需要 Wi-Fi 6E 和普通的 Wi-Fi 6**
**Correll** 上一次我们在 UNII-2 和 UNII-2 扩展中得到提升是在 15 年前,而在当时智能手机甚至还没有兴起。现在能够获得 1.2GHz 的频谱已经非常大了。使用 Wi-Fi 6E我们不是将 Wi-Fi 空间增加一倍,事实上,我们将可用空间增加了三倍。根据你所处的地点,频谱的数量要多三倍、四倍或五倍。此外,你不必担心 DFS<ruby>动态频率选择<rt>dynamic frequency selection</rt></ruby>),尤其是在室内。
Wi-Fi 6E 不会比 Wi-Fi 6 更快,也不会添加增强的技术功能。最妙的是运行 6GHz 需要 Wi-Fi 6 或以上的客户端。所以,我们不会有任何缓慢的客户端,也不会有很多噪声。我们将在更干净的环境中使用更快的设备来得到高性能。
**Kerravala 也能用更宽的信道吗**
**Correll** 没错那是一件很酷的事情。如果你处于一个典型的企业环境中20 和 40MHz 基本上就是你需要的。在体育馆这种高密度环境中,想要使用 80 或 160MHz 的带宽就会变得很困难了。更宽的信道将会真正有助于像虚拟现实这类应用,它可以利用这些信道占用频谱中剩余的部分。这可能是最大的用例了。
在未来的三四年里,如果你想在体育场做数字标识牌或者边缘屏幕处理,则可以使用 160MHz 的 80 带宽,而不会受到其他任何影响。已经有传言说 Wi-Fi 7 将会有 320MHz 宽的频道。
**Kerravala 这将主要是对大多数 Wi-Fi 策略的增强吗?**
**Correll** 短期内肯定会处于先锐领域。首批产品大概会在今年底发布,它们将是消费类产品。对于企业来说,支持 6GHz 的产品将会在明年亮相。在 2022 年之前你不会真正看到它密集出现——所以短期内不会。对于智能手机公司来说Wi-Fi 并不是什么大事,他们更愿意关注其他功能。
但它仍是一个巨大的机会。6GHz 与 CBRS公民宽带无线电服务或 5G 相比,最棒的一点是(许多人)宁愿坚持使用 Wi-Fi也不愿迁移到不同的架构。这些用户将推动驱动部件制造商转向物联网设备或机器人或任何需要 6GHz 的设备。这是一个干净的频谱,可能比普通的 Wi-Fi 6 还要便宜也更节能。
**Kerravala 有人说 5G 会替代 Wi-Fi 6。但这有什么实际意义呢**
**Correll** 现实中,你不可能在每个设备中插入 SIM 卡。但是其中一个大问题是数据所有权,因为运营商将拥有你的数据,而不是你。如果你想使用你的数据进行任何类型的业务分析,运营商是否会以一定价格将数据返还给你?这是一个可怕的想法。
Wi-Fi 不会消失有太多的理由。当具备 Wi-Fi 6 和 5G 功能的设备问世时,其他只有 Wi-Fi 功能的笔记本电脑、平板电脑和物联网设备将会发生什么呢?要么是只支持 Wi-Fi 的设备,要么是支持 Wi-Fi 和 5G 的设备,但 5G 不会完全取代 Wi-Fi。如果你看看 5G 无线网络的骨干网Wi-Fi 就是其中的一个组成部分。这是一个幸福的大家庭。这些技术是为了共存而设计的。
--------------------------------------------------------------------------------
via: https://www.networkworld.com/article/3563832/wi-fi-6e-when-its-coming-and-what-its-good-for.html
作者:[Zeus Kerravala][a]
选题:[lujun9972][b]
译者:[chenmu-kk](https://github.com/chenmu-kk)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://www.networkworld.com/author/Zeus-Kerravala/
[b]: https://github.com/lujun9972
[1]: https://www.networkworld.com/article/3540288/how-wi-fi-6e-boosts-wireless-spectrum-five-fold.html
[2]: https://www.networkworld.com/article/3203489/what-is-5g-how-is-it-better-than-4g.html
[3]: https://www.networkworld.com/article/3356838/how-to-determine-if-wi-fi-6-is-right-for-you.html
[4]: https://www.networkworld.com/article/3250268/what-is-mu-mimo-and-why-you-need-it-in-your-wireless-routers.html
[5]: https://www.networkworld.com/article/3402316/when-to-use-5g-when-to-use-wi-fi-6.html
[6]: https://www.networkworld.com/article/3306720/mobile-wireless/how-enterprises-can-prep-for-5g.html
[7]: https://www.facebook.com/NetworkWorld/
[8]: https://www.linkedin.com/company/network-world

View File

@ -0,0 +1,125 @@
[#]: collector: (lujun9972)
[#]: translator: (LazyWolfLin)
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-12621-1.html)
[#]: subject: (6 best practices for teams using Git)
[#]: via: (https://opensource.com/article/20/7/git-best-practices)
[#]: author: (Ravi Chandran https://opensource.com/users/ravichandran)
6 个在团队中使用 Git 的最佳实践
======
> 采用这些 Git 协作策略,让团队工作更高效。
![](https://img.linux.net.cn/data/attachment/album/202009/16/234908ge77j9j799i4eaj7.jpg)
Git 非常有助于小团队管理他们的软件开发进度,但有些方法能让你变得更高效。我发现了许多有助于我的团队的最佳实践,尤其是当不同 Git 水平的新人加入时。
### 在你的团队中正式确立 Git 约定
每个人都应当遵循对于分支命名、标记和编码的规范。每个组织都有自己的规范或者最佳实践,并且很多建议都可以从网上免费获取,而重要的是尽早选择合适的规范并在团队中遵循。
同时,不同的团队成员的 Git 水平参差不齐。你需要创建并维护一组符合团队规范的基础指令,用于执行通用的 Git 操作。
### 正确地合并变更
每个团队成员都需要在一个单独的功能分支上开发。但即使是使用了单独的分支,每个人也会修改一些共同的文件。当把更改合并回 `master` 分支时,合并通常无法自动进行。可能需要手动解决不同的人对同一文件不同变更的冲突。这就是你必须学会如何处理 Git 合并的原因。
现代编辑器具有协助解决 [Git 合并冲突][2]的功能。它们对同一文件的每个部分提供了合并的各种选择,例如,是否保留你的更改,或者是保留另一分支的更改,亦或者是全部保留。如果你的编辑器不支持这些功能,那么可能是时候换一个代码编辑器了。
### 经常变基你的功能分支
当你持续地开发你的功能分支时,请经常对它做<ruby>变基<rt>rebase</rt></ruby>`rebase master`。这意味着要经常执行以下步骤:
```
git checkout master
git pull
git checkout feature-xyz  # 假设的功能分支名称
git rebase master  # 可能需要解决 feature-xyz 上的合并冲突
```
这些步骤会在你的功能分支上[重写历史][3](这并不是件坏事)。首先,它会使你的功能分支获得 `master` 分支上当前的所有更新。其次,你在功能分支上的所有提交都会在该分支历史的顶部重写,因此它们会顺序地出现在日志中。你可能需要一路解决遇到的合并冲突,这也许是个挑战。但是,这是解决冲突最好的时机,因为它只影响你的功能分支。
在解决完所有冲突并进行回归测试后,如果你准备好将功能分支合并回 `master`,那么就可以在再次执行上述的变基步骤几次后进行合并:
```
git checkout master
git pull
git merge feature-xyz
```
在此期间,如果其他人也将和你有冲突的更改推送到 `master`,那么 Git 合并将再次发生冲突。你需要解决它们并重新进行回归测试。
还有一些其他的合并哲学(例如,只使用合并而不使用变基以防止重写历史),其中一些甚至可能更简单易用。但是,我发现上述方法是一个干净可靠的策略。提交历史日志将以有意义的功能序列进行排列。
如果使用“纯合并”策略(上面所说的,不进行定期的变基),那么 `master` 分支的历史将穿插着所有同时开发的功能的提交。这样混乱的历史很难回顾。确切的提交时间通常并不是那么重要。最好是有一个易于查看的历史日志。
### 在合并前压扁提交
当你在功能分支上开发时,即使再小的修改也可以作为一个提交。但是,如果每个功能分支都要产生五十个提交,那么随着不断地增添新功能,`master` 分支的提交数终将无谓地膨胀。通常来说,每个功能分支只应该往 `master` 中增加一个或几个提交。为此,你需要将多个提交<ruby>压扁<rt>Squash</rt></ruby>成一个或者几个带有更详细信息的提交中。通常使用以下命令来完成:
```
git rebase -i HEAD~20  # 查看可进行压扁的二十个提交
```
当这条命令执行后,将弹出一个提交列表的编辑器,你可以通过包括<ruby>遴选<rt>pick</rt></ruby><ruby>压扁<rt>squash</rt></ruby>在内的数种方式编辑它。“遴选”一个提交即保留这个提交。“压扁”一个提交则是将这个提交合并到前一个之中。使用这些方法,你就可以将多个提交合并到一个提交之中,对其进行编辑和清理。这也是一个清理不重要的提交信息的机会(例如,带错字的提交)。
总之,保留所有与提交相关的操作,但在合并到 `master` 分支前,合并并编辑相关信息以明确意图。注意,不要在变基的过程中不小心删掉提交。
在执行完诸如变基之类的操作后,我会再次看看 `git log` 并做最终的修改:
```
git commit --amend
```
最后,由于重写了分支的 Git 提交历史,必须强制更新远程分支:
```
git push -f
```
### 使用标签
当你完成测试并准备从 `master` 分支部署软件到线上时,又或者当你出于某种原因想要保留当前状态作为一个里程碑时,那么可以创建一个 Git 标签。对于一个积累了一些变更和相应提交的分支而言,标签就是该分支在那一时刻的快照。一个标签可以看作是没有历史记录的分支,也可以看作是直接指向标签创建前那个提交的命名指针。
所谓的“配置控制”就是在不同的里程碑上保存代码的状态。大多数项目都有一个需求能够重现任一里程碑上的软件源码以便在需要时重新构建。Git 标签为每个代码的里程碑提供了一个唯一标识。打标签非常简单:
```
git tag milestone-id -m "short message saying what this milestone is about"
git push --tags   # 不要忘记将标签显式推送到远程
```
考虑这样一种情况Git 标签对应的软件版本已经分发给客户,而客户报告了一个问题。尽管代码库中的代码可能已经在继续开发,但通常情况下为了准确地重现客户问题以便做出修复,必须回退到 Git 标签对应的代码状态。有时候新代码可能已经修复了那个问题,但并非一直如此。通常你需要切换到特定的标签并从那个标签创建一个分支:
```
git checkout milestone-id        # 切换到分发给客户的标签
git checkout -b new-branch-name  # 创建新的分支用于重现 bug
```
此外,如果带附注的标记和带签名的标记有助于你的项目,可以考虑使用它们。
### 让软件运行时打印标签
在大多数嵌入式项目中,从代码版本构建出的二进制文件有固定的名称,这样无法从它的名称推断出对应的 Git 标签。在构建时“嵌入标签”有助于将未来发现的问题精准地关联到特定的构建版本。在构建过程中可以自动地嵌入标签。通常,`git describe` 生成的标签字符串会在代码编译前插入到代码中,以便生成的可执行文件能够在启时时输出标签字符串。当客户报告问题时,可以指导他们给你发送启动时输出的内容。
### 总结
Git 是一个需要花时间去掌握的复杂工具。使用这些实践可以帮助团队成功地使用 Git 协作,无论他们的知识水平。
--------------------------------------------------------------------------------
via: https://opensource.com/article/20/7/git-best-practices
作者:[Ravi Chandran][a]
选题:[lujun9972][b]
译者:[LazyWolfLin](https://github.com/LazyWolfLin)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://opensource.com/users/ravichandran
[b]: https://github.com/lujun9972
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/christina-wocintechchat-com-rg1y72ekw6o-unsplash_1.jpg?itok=MoIv8HlK (Women in tech boardroom)
[2]: https://opensource.com/article/20/4/git-merge-conflict
[3]: https://opensource.com/article/20/4/git-rebase-i

View File

@ -1,45 +1,45 @@
[#]: collector: "lujun9972"
[#]: translator: "FSSlc"
[#]: reviewer: " "
[#]: publisher: " "
[#]: url: " "
[#]: reviewer: "wxy"
[#]: publisher: "wxy"
[#]: url: "https://linux.cn/article-12599-1.html"
[#]: subject: "Manage network connections from the Linux command line with nmcli"
[#]: via: "https://opensource.com/article/20/7/nmcli"
[#]: author: "Dave McKay https://opensource.com/users/davemckay"
在命令行中使用 nmcli 来管理网络连接
在命令行中使用 nmcli 来管理网络连接
======
nmcli 命令赋予你直接在 Linux 命令行操作 NetworkManager 工具的能力。
> nmcli 命令赋予你直接在 Linux 命令行操作 NetworkManager 工具的能力。
![坐在窗前笔记本电脑的一位商业女士][1]
![](https://img.linux.net.cn/data/attachment/album/202009/10/100302z2xq9cieqyekxbdc.jpg)
[nmcli][2] 命令赋予你直接在 Linux 命令行操作 NetworkManager 工具的能力。它是 NetworkManager 软件包集成的一部分,通过使用一些 [应用程序接口][3]API来获取 NetworkManager 的功能。
[nmcli][2] 命令赋予你直接在 Linux 命令行操作 NetworkManager 工具的能力。它是 NetworkManager 软件包集成的一部分,通过使用一些 [应用程序接口][3]API来获取 NetworkManager 的功能。
nmcli 于 2010 年发布,用以替代其他配置网络接口和连接的方法,例如 [ifconfig][4]。因为它是 [命令行界面][5]CLI工具 被设计用在终端窗口和脚本中,所以对于那些工作在没有 [图形界面][6]GUI的系统管理员来说是它是一个非常理想的工具。
`nmcli` 发布于 2010 年,用以替代其他配置网络接口和连接的方法,例如 [ifconfig][4]。因为它是一个 [命令行界面][5]CLI工具被设计用在终端窗口和脚本中所以对于那些工作在没有 [图形用户界面][6]GUI的系统的管理员来说它是一个非常理想的工具。
### ncmli 的语法
nmcli 命令接受 __选项__ (options) 来更改 nmcli 的行为,接受 __子命令__ (section) 来告诉 nmcli 想使用它的那部分功能,使用 __操作__ (action) 来告诉 nmcli 你想执行什么操作。
`nmcli` 命令可以使用*选项*来更改它的行为,使用*子命令*来告诉 `nmcli` 想使用它的那部分功能,使用*操作*来告诉 `nmcli` 你想执行什么操作。
```
$ nmcli <options> <section> <action>
$ nmcli <选项> <子命令> <操作>
```
nmcli 一共有 8 个子命令,每个子命令有一些相关的网络操作:
`nmcli` 一共有 8 个子命令,每个子命令有一些相关的网络操作:
* **help** 提供有关 nmcli 命令和使用方法的帮助信息
* **general** 返回 NetworkManager 的状态和总体配置信息
* **networking** 提供命令来查询某个网络连接的状态和启动、禁用连接的功能
* **radio** 提供命令来查询某个 WiFi 网络连接的状态和启动、禁用连接的功能
* **monitor** 提供命令来监控 NetworkManager 的活动并观察网络连接的状态改变
* **connection** 提供命令来启用或禁用网络接口、添加新的连接、删除已有连接等功能
* **device** 主要被用于更改与某个设备(例如接口名称)相关联的连接参数或者使用一个已有的连接来连接设备
* **secret** 注册 nmcli 来作为一个 NetworkManager 的秘密代理,用以监听秘密信息。这个子命令很少会被用到,因为当连接到网络时, nmcli 会自动做这些事
* `help` 提供有关 `nmcli` 命令和使用方法的帮助信息
* `general` 返回 NetworkManager 的状态和总体配置信息
* `networking` 提供命令来查询某个网络连接的状态和启动、禁用连接的功能
* `radio` 提供命令来查询某个 WiFi 网络连接的状态和启动、禁用连接的功能
* `monitor` 提供命令来监控 NetworkManager 的活动并观察网络连接的状态改变
* `connection` 提供命令来启用或禁用网络接口、添加新的连接、删除已有连接等功能
* `device` 主要被用于更改与某个设备(例如接口名称)相关联的连接参数或者使用一个已有的连接来连接设备
* `secret` 注册 `nmcli` 来作为一个 NetworkManager 的秘密代理,用以监听秘密信息。这个子命令很少会被用到,因为当连接到网络时,`nmcli` 会自动做这些事
### 简单的示例
首先,我们验证一下 NetworkManager 正在运行并且 nmcli 可以与之通信:
首先,我们验证一下 NetworkManager 正在运行并且 `nmcli` 可以与之通信:
```
$ nmcli general
@ -63,20 +63,20 @@ Wired connection 3  52d89737-de92-35ec-b082-8cf2e5ac36e6  ethernet  enp0s9
### 连接管理
理解 nmcli 的术语是非常重要的。一个网络 **连接** 包含了一个连接的所有信息。你可以将它看作一个网络**配置**。一个连接包含了与一个连接相关的所有信息,包括 [数据链路层][7] 和 [IP 地址信息][8] 。它们是 [OSI 网络模型][9] 中的第 2 和第 3 层。
理解 `nmcli` 的术语是非常重要的。一个网络<ruby>连接<rt>connection</rt></ruby>包含了一个连接的所有信息。你可以将它看作一个网络<ruby>配置<rt>configuration</rt></ruby>。“连接”包含了与其相关的所有信息,包括 [数据链路层][7] 和 [IP 地址信息][8] 。它们是 [OSI 网络模型][9] 中的第 2 和第 3 层。
当你在 LInux 上配置网络时,通常来说你在为某个网络设备(它们是安装在一个电脑中的网络接口)配置连接。当一个连接被某个设备所使用,那么就可以说这个连接被**激活**或者**启用**了,反之是**停用**或**下线**
当你在 Linux 上配置网络时,通常来说你是在为某个网络设备(它们是安装在一个电脑中的网络接口)配置连接。当一个连接被某个设备所使用,那么就可以说这个连接被<ruby>激活<rt>active</rt></ruby>或者<ruby>上线<rt>up</rt></ruby>了,反之是<ruby>停用<rt>inactive</rt></ruby><ruby>下线<rt>down</rt></ruby>
#### 添加网络连接
nmcli 允许你快速地创建网络连接并同时为该连接指定参数。为了通过使用 有线连接 2 `enp0s8`来创建一个新的连接,你可以利用`sudo` 来运行下面的命令:
`nmcli` 允许你快速地创建网络连接并同时为该连接指定参数。为了通过使用“有线连接 2” `enp0s8` 来创建一个新的连接,你可以利用 `sudo` 来运行下面的命令:
```
$ sudo nmcli connection add type ethernet ifname enp0s8
Connection 'ethernet-enp0s8' (09d26960-25a0-440f-8b20-c684d7adc2f5) successfully added.
```
其中 `type` 选项指定需要一个 [Ethernet][10] 的连接,而 `ifname`(接口名)选项指定你想要为这个连接使用的网络接口设备。
其中 `type` 选项指定需要一个 [Ethernet][10] 类型的连接,而 `ifname`(接口名)选项指定你想要为这个连接使用的网络接口设备。
让我们看看发生了什么变化:
@ -89,7 +89,7 @@ Wired connection 3  52d89737-de92-35ec-b082-8cf2e5ac36e6  ethernet  enp0s9
ethernet-enp0s8     09d26960-25a0-440f-8b20-c684d7adc2f5  ethernet  --  
```
通过上图可以看到新的连接 `ethernet-enp0s8` 已经创建好了。它的 [通用唯一标识符][11]UUID也一同被赋予并且其连接类型为 Ethernet。我们可以使用 `up` 子命令再加上连接名称(或 UUID来使得这个连接被激活
通过上图可以看到新的连接 `ethernet-enp0s8` 已经创建好了。它的 <ruby>[通用唯一标识符][11]<rt>Universally Unique IDentifier</rt></ruby>UUID也一同被赋予并且其连接类型为 Ethernet。我们可以使用 `up` 子命令再加上连接名称(或 UUID来使得这个连接被激活
```
$ nmcli connection up ethernet-enp0s8
@ -110,16 +110,16 @@ Wired connection 3  52d89737-de92-35ec-b082-8cf2e5ac36e6  ethernet  enp0s9
#### 调整连接
nmcli 命令使得调整现有连接的参数变得更加容易。也许你想将某个网络接口从 [动态主机配置协议][12]DHCP改为静态 IP 地址。
`nmcli` 命令使得调整现有连接的参数变得更加容易。也许你想将某个网络接口从 <ruby>[动态主机配置协议][12]<rt>Dynamic Host Configuration Protocol</rt></ruby>DHCP改为静态 IP 地址。
假设你需要为你的新连接分配一个固定的 IP 地址 `192.168.4.26`,那么你需要使用两个命令,一个用于设定 IP 地址,另一个用来将获取 IP 地址的方法改为 `manual`
假设你需要为你的新连接分配一个固定的 IP 地址 `192.168.4.26`,那么你需要使用两个命令,一个用于设定 IP 地址,另一个用来将获取 IP 地址的方法改为 `manual`(手动)
```
$ nmcli connection modify ethernet-enp0s8 ipv4.address 192.168.4.26/24
$ nmcli connection modify ethernet-enp0s8 ipv4.method manual
```
记得特别指定 [子网掩码][13],在我们这个测试的连接中,它是 [无类域间路由][14]CIDR中的 `255.255.255.0``/24`
记得指定 [子网掩码][13],在我们这个测试的连接中,它是 <ruby>[无类域间路由][14]<rt> Classless Inter-Domain Routing</rt></ruby>CIDR中的 `255.255.255.0``/24`
为了使得你的更改生效,你需要通过停止再重新启用该连接。下面的第一个命令是停用该连接,第二个命令则是启用它:
@ -130,15 +130,15 @@ $ nmcli connection up ethernet-enp0s8
Connection successfully activated (D-Bus active path: /org/freedesktop/NetworkManager/ActiveConnection/6)
```
假如你想将连接设置为使用 DHCP则需要将上面的 manual` 改为 `auto`
假如你想将连接设置为使用 DHCP则需要将上面的 `manual` 改为 `auto`(自动)
```
`$ nmcli connection modify ethernet-enp0s8 ipv4.method auto`
$ nmcli connection modify ethernet-enp0s8 ipv4.method auto
```
### 设备管理
nmcli 命令中的 `device` 子命令允许你管理安装在你电脑中的网络接口。
`nmcli` 命令中的 `device` 子命令允许你管理安装在你电脑中的网络接口。
#### 检查设备状态
@ -155,9 +155,9 @@ lo      loopback  unmanaged  --  
#### 显示设备详情
为了检查某个网络接口的详情,可以使用 `device` 设备中的 `show` 操作。假如你不提供某个设备的名称,那么所有设备的详情都将会被获取再进行展示。你可以上下翻动来查看这些信息。
为了检查某个网络接口的详情,可以使用 `device` 子命令中的 `show` 操作。假如你不提供某个设备的名称,那么会获取并展示所有设备的详情。你可以上下翻动来查看这些信息。
要查看你最近添加的连接所对应的设备 `enp0s8`,你可以使用下面的命令,请注意验证它使用的 IP 地址是否为先前你请求的那个:
要查看你最近添加的连接所对应的设备 `enp0s8`,你可以使用下面的命令,请注意验证它使用的 IP 地址是否为先前你要求设置的那个:
```
$ nmcli device show enp0s8
@ -180,25 +180,25 @@ IP6.ROUTE[2]:                           dst = ff00::/8, nh = ::, mt
上面的输出非常细致,它主要显示了下面这些内容:
* **网络接口名称**,在这个示例中是`enp0s8`,它是 [udev][15] 分配的
* **网络接口名称**,在这个示例中是 `enp0s8`,它是 [udev][15] 分配的
* **网络连接类型**,在这个示例中是物理的 Ethernet 连接
* 设备的 **媒体访问控制MAC地址**,它被用来在网络中识别该设备
* 设备的<ruby>媒介访问控制<rt>media access control</rt></ruby>MAC地址,它被用来在网络中识别该设备
* [最大传输单元][17],在单个传输中最大协议数据单位的大小,任何大于这个大小的数据将被分为多个包来进行传输
* 该设备 **当前已经处于连接状态**
* 这个设备使用的连接名称是`ethernet-enp0s8`
* 这个设备使用的 IP 地址如上面所求的那样,被设置为 `192.168.4.26/24`
* 该设备**当前已经处于连接状态**
* 这个设备使用的连接名称是 `ethernet-enp0s8`
* 这个设备使用的 IP 地址如上面所求的那样,被设置为 `192.168.4.26/24`
其他的信息则是与这个设备连接的网络相关的默认路由和网关设置信息。
#### nmcli 的交互式编辑器
尽管 nmcli 是一个命令行工具,但它还包含一个交互式工具, `edit` 子命令将为你指定的连接打开一个交互式编辑器,例如:
尽管 `nmcli` 是一个命令行工具,但它还包含一个基本的交互式编辑器,`edit` 子命令将为你指定的连接打开一个交互式编辑器,例如:
```
$ nmcli connection edit ethernet-enp0s8
```
它将显示少量的帮助文字,接着是 nmcli 的命令提示符:
它将显示少量的帮助文字,接着是 `nmcli` 的命令提示符:
```
===| nmcli interactive connection editor |===
@ -213,7 +213,7 @@ You may edit the following settings: connection, 802-3-ethernet (ethernet), 802-
nmcli>
```
假如你输入 `print` 然后敲击 **Enter** 键, nmcli 将列举出与这个接口相关的所有属性。这些属性有很多,你可以上下翻动来查看这个列表:
假如你输入 `print` 然后敲击 `Enter` 键, `nmcli` 将列举出与这个接口相关的所有属性。这些属性有很多,你可以上下翻动来查看这个列表:
```
===============================================================================
@ -239,7 +239,7 @@ connection.autoconnect-slaves:          -1 (default)
connection.secondaries:                 --
```
如果你想将你的连接改为 DHCP则请输入 `goto ipv4` 然后敲 **Enter**键:
如果你想将你的连接改为 DHCP则请输入 `goto ipv4` 然后敲 `Enter` 键:
```
nmcli> goto ipv4
@ -247,14 +247,14 @@ You may edit the following properties: method, dns, dns-search, dns-options, dns
nmcli ipv4>
```
你想改变的属性是 `method`,再继续敲 `set method auto` 然后敲 **Enter** 键:
你想改变的属性是 `method`,再继续敲 `set method auto` 然后敲 `Enter` 键:
```
nmcli ipv4> set method auto
Do you also want to clear 'ipv4.addresses'? [yes]:
```
假如你想让这个连接清除掉这个静态 IP 地址,则请敲 **Enter**键,如果要保留,则输入 `no` 然后敲 **Enter**键。假如你想在将来再次使用它,你可以保留这个 IP 地址。即便存储了一个静态的 IP 地址,如果 `method` 被设置为 `auto` ,它仍然会使用 DHCP。
假如你想让这个连接清除掉这个静态 IP 地址,则请敲 `Enter` 键,如果要保留,则输入 `no` 然后敲 `Enter` 键。假如你想在将来再次使用它,你可以保留这个 IP 地址。即便存储了一个静态的 IP 地址,如果 `method` 被设置为 `auto` ,它仍然会使用 DHCP。
最后输入 `save` 来保存你的更改:
@ -264,13 +264,13 @@ Connection 'ethernet-enp0s8' (09d26960-25a0-440f-8b20-c684d7adc2f5) successfully
nmcli ipv4>
```
输入 `quit` 来离开 nmcli 的交互式编辑器窗口。假如你不想离开,可以输入 `back` 来回到最开始的命令行提示符界面,然后继续使用这个编辑器。
输入 `quit` 来离开 `nmcli` 的交互式编辑器窗口。假如你不想离开,可以输入 `back` 来回到最开始的命令行提示符界面,然后继续使用这个编辑器。
### nmcli 的更多内容
浏览交互式编辑器,你就可以看到 nmcli 有多少设定和每个设定有多少属性。交互式编辑器是一个简洁的工具,但如果需要在命令行或者在脚本中使用 nmcli你还是需要使用常规的命令行版本。
浏览交互式编辑器,你就可以看到 `nmcli` 有多少设定和每个设定有多少属性。交互式编辑器是一个简洁的工具,但如果需要在命令行或者在脚本中使用 `nmcli`,你还是需要使用常规的命令行版本。
现在你有了这些基础知识,你还可以查看 nmcli 的 [man 页面][2] 来查看它还可以提供什么额外功能。
现在你有了这些基础知识,你还可以查看 `nmcli` 的 [man 页面][2] 来查看它还可以提供什么更多功能。
--------------------------------------------------------------------------------
@ -279,7 +279,7 @@ via: https://opensource.com/article/20/7/nmcli
作者:[Dave McKay][a]
选题:[lujun9972][b]
译者:[FSSLC](https://github.com/FSSlc)
校对:[校对者ID](https://github.com/校对者ID)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出

View File

@ -0,0 +1,141 @@
[#]: collector: (lujun9972)
[#]: translator: (JonnieWayy)
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-12614-1.html)
[#]: subject: (Leaving Google: Five Years On)
[#]: via: (https://theartofmachinery.com/2020/08/04/leaving_google.html)
[#]: author: (Simon Arneaud https://theartofmachinery.com)
离开 Google五年以来
======
![](https://img.linux.net.cn/data/attachment/album/202009/14/231115kqsf6q25s25ms66m.jpg)
大约五年前的今天,我上交了 Google 员工证,然后走出了悉尼 Google 办公室,开启了一段自谋职业的崭新生活。我认为我应该详述一下这个故事,因为我通过阅读 [Michael Lynch][1] 的作品而收获颇丰。正如你所看到的,我仍然花费了几年时间才开始考虑写这篇文章,但是最终我告诉自己,倘若我不在五周年纪念日写它,我就永远也不会写了。
这篇文章有点儿长,但是我希望它对那些对于在大型技术公司工作感兴趣的新开发人员或是想要离职的大型企业雇员能够有所帮助。我将谈谈我进入 Google在 Google 工作和辞职的故事,以及之后我做了什么。如果你想了解更多的细节,可以随时询问,不过我已经有很多博文要写,所以不能保证有什么深入的内容。
同样地,冒着显而易见的劳工风险:我已经有 5 年不在 Google 工作了,所以请不要以这个故事来作为当今 Google 或是 Google 雇员经历全貌的字面描述。但是,我认为其中的许多内容仍然与一般性的技术职业有关。
### 通往 Google 的艰辛道路
2005 年,我获得了第一份带薪的编程工作,是在当地的电力公司工作,把一些旧的 Pascal 代码用不同的编译器在不同的操作系统上运行。这基本上只是我为了挣外快而做的暑期工,同年我还刚刚开始攻读我数学和物理的学位。他们很高兴有一个本科生能够胜任这份工作。我被这些大人吓了一跳,因为他们不仅只是对我的编程爱好感兴趣,而且真的还会为此给我钱。
直到 2007 年毕业以前,我一直在做类似的工作。我喜欢编程工作,而 Google 是一家从事着很酷的编程工作的很酷的公司,因此我申请了实习。 Google 的面试过程以困难而著称,所以我花了好几个星期时间练习了所有我在网上能够找到的 Google 面试题。我认为 13 年里面试流程并没有发生太大的变化 —— 我提交了简历,受邀参加了几轮电话面试,这些面试问的几乎都是算法问题(我记得有一个动态规划问题和一个分治几何问题)。我通过了最初的几轮面试,然后受邀前往悉尼接受了由 Google 的工程师们进行的为期一天的现场面试。我回到家里,等待 Google HR 的电话,这个过程漫长得像是有一辈子。我被拒绝了。
对于我们收到的拒绝和失败感到难过很自然,因此我们并不会经常谈及它们。但是出于同样的原因,其他人也不会去谈论他们自己的失败,这只会使得情况变得更加糟糕。当我后来真的进入 Google 时,我觉得作为一个此前被拒绝过的人,我一定有哪里做得不对,但是有一天我和一群同事坐在一张桌子旁,开始交谈。那时候我才发现,实际上我身边的很多人都至少被拒绝过一次。我甚至都不是“最差的”。有个家伙开玩笑说,他肯定是因为 Google HR 厌倦了拒绝他才得以进来的。我说的也是一些相当厉害的工程师 —— 有些人负责着我一直在用的代码,而我打赌你也在用。
进行面试的公司通常会为每个名额面试两名或更多的候选人。这意味着比起录用,会有更多的拒绝,所以一般面试参与者被拒绝的可能性要大于被录用。然而我们一直忘记了这一点。四个开发人员参加面试,一个被录用了,其他三个在社交媒体上抱怨这场面试是如何的漏洞百出,因为他们个人被拒绝了。当然,面试远非完美,但是我们需要停止如此个人化地谈论它。
只要你能够找到问题所在并知道如何去改进自己拒绝和失败就没有那么糟糕。Google 的面试主要针对算法,我在其中磕磕拌拌地摸索,但绝对没有能够脱颖而出。
在被 Google 拒绝以后我得到了两样东西并进行了为期一年的休假。第一件东西是澳大利亚商务编号ABN我用它来提供数学与科学补习课程以及技术工作合同。我获得的另一样东西是一张大学科技图书馆的借书证。我当时并不打算再次去参加 Google 的面试,但是那次的面试经历告诉我还有很多东西是我所不知道的。我就在图书馆开设课程给大家做辅导,并在期间阅读书籍。顺便说一句,有些人认为我为我的补习业务所做的所有这些财务工作和其他东西很奇怪,而大多数补习老师都只收现金。但是我学到了许多对我日后生活很有帮助的东西,所以我一点儿都不后悔。
2009 年,我根据一个叫 Persi Diaconis 的魔术师转行为数学家的作品,进行了一个数学荣誉课程(也就是学士学位四年级)。计算机科学系让我选修他们的一个算法单元作为其中的一部分。
就像我所说的那样,我本来并没有打算再去 Google 面试,但是让我快速地讲讲这是怎么发生的。我从高中就开始学习日语,因此在 2012 年,我决定尝试在东京生活。这基本上行得通,除了我犯了一个相当大的错误 —— 我没有任何日语方面的纸质资质证明,因此很难获得工作面试。最终,我的一个已经被 Google 录用的朋友建议我再试一次。与 Google 所有的办事处一样, Google 东京的官方商务语言是英语,因此他们不要求我具有日语资质证明。
### Google 面试,再一次
我的朋友向 Google HR 推荐了我。这绝对有帮助,但是如果你自己得到了被推荐的机会,也不要太过于兴奋。它所能够确保的是你的简历会被注意到(不是小事)并且免去一次电话面试,但你仍然得通过剩下的电话面试和现场面试。
这一次我用来自 [Project Euler][2] 和 [Google CodeJam][3] 的题进行练习。电话面试过程中,我不得不在 Google Doc 上进行一些在线编程,这有点儿尴尬,但是除此以外电话面试一切顺利。然后我受邀前往六本木的 Mori Tower 办公室进行了为期一天的现场面试。
![Mori Tower in Tokyo, where I interviewed for Google. It's the sixth tallest building in the city, which means it's huge. \(Photo from here.\)][4]
我的首个面试非常糟糕。我的脑子僵住了。我知道我能够解出那些题目,但是直到面试官走出房间我才想出答案。我立刻就感到很放松,并且意识到这是一个三元搜索问题。这是在是很令人沮丧,但是我觉得继续前进,看看剩下的面试进展如何。
其中的两道面试题很糟糕。其中之一直至今日仍然是我遇到过的最糟糕的面试问题。面试官说:“你用同一输入运行一个程序两次,得到了两个不同的结果。告诉我这是为什么。”我回答道:“当这种情况在现代计算机上发生而且并不在我的预期之中时,通常是竞态条件。”他只说:“不,这不是竞态条件。”然后看着我等着我的下一个回答。如果他有兴趣讨论一下的话,这个问题本该是一个很棒的问题,但是很显然他实际上只想玩“猜猜神秘数”。对于我所说的几乎全部内容,他只是回答:“不。”显然,该程序完全是确定性的,不存储任何状态,并且不依赖于环境(例如磁盘或是实时时钟),但却在每次执行时都给出不同的结果。我怀疑我们对于“被存储的状态”或是“环境”的含义还是某些东西有着不同的理解,但是我无法区分。有一次(变得绝望了)我试着问电子元件的温度变化是否会有影响,而他说:“不,那会是一个竞态条件,我已经告诉过你这不是竞态条件了。”最终,面试结束了,而我仍然不知道那个秘密数字是什么。
我讲这个故事的原因是,我听说过许多更为平淡的恐怖故事,用以证明面试官是憎恶面试者的坏人。然而,与流行的刻板印象所相反的是,当天的大多数面试基本上都还可以,面试官也很友好并且很尊重人。面试也着实很困难,因此最好减少面试官的工作量。希望那个“猜数字”面试官从 Google HR 那里得到的反馈是,他的问题对于作出聘用决定没什么帮助。
这次面试带来了一份要约但是有一个小问题这份工作在悉尼担任站点可靠性工程师SRE。我以前从未听说过 SRE但是我和一位悉尼的资深 SRE 通了电话,他解释说他注意到了我在天然气行业从事嵌入式工程的经历,并且认为 SRE 会和适合我,因为同样强调可靠性与拟合紧密约束。
在东京花了大约一年时间来建立起自己的生活,我不想抛弃一切然后搬到悉尼,但是我绝不可能会拒绝一份来自 Google 的要约。与招聘人员交谈时,我确实犯了一个非常愚蠢的错误:我被问到当时能赚多少钱,然后我就脱口而出。[别这么做][5]。这意味着不管在面试中发生了什么事情,或是你上一份工作中被底薪了多少,或者其它什么。你可能会被拒绝,或者会在原来的薪水基础上得到一些象征性的提升,并且如果你试图进一步协商,会被认为疯狂而又不合理。就我而言,我的收入甚至远远低于 Google 的入门级职位。我无法肯定地说全是这样,但是在 2013 年我搬到了悉尼,在 Google Maps 成为了一名新毕业生级别的 SRE。
### 悉尼的 Google Maps SRE
像 Maps 这样的产品实际上是若干个软件项目,每个都有自己的开发人员团队。甚至诸如路线查找之类的功能实际上也是多个软件项目 —— 从交通时刻表数据收集,到线路计算,再到结果渲染,等等等等。 SRE 的工作包含两个方面一方面是为各个项目提供待命实时响应任何生产事故另一方面在无需救火时则是将生产事故中所积攒的经验应用到其他项目中去并且发现其中可能出错的方式或是发现使其性能更好的机会。Google 的 SRE 还需要像开发人员的内部咨询小组一样,对部署实践、自动化、监控或是类似的问题提供咨询。
这项工作相当紧张。作为一个团队,我们每周至少需要处理一次生产事故,否则就要为更多的服务提供支持。每个礼拜,悉尼的所有 SRE 都会聚在一起,交流发生过的故障事件或是有关如何使事情更好地运转的新技巧。学习曲线的感觉就像是再次成为了一名本科生。
我有时会感到震惊,听说我选择离开 Google 的人会问:“但是你不会想念那些福利吗?!”物质上的福利(例如伙食等等)绝对很棒,但是它们是你可以买到的东西,因此,不,它们不是我所想念的东西。如果你问我所想念的是什么,我会说是在那里工作的人们。与你可能听说过的不同,傲慢的人不喜欢在 Google 之类的地方工作。有一个臭名昭著的故事,一个自恋的人在 Google 找了份工作并假装自己是各方面的顶级专家让自己尴尬不已。他待了不到半年就离开了。总的来说与我工作过的其他地方相比这里的文化在傲慢、指责以及政治方面很少。另一方面Google 并没有垄断好同事。
不过,有一种公司政治是个大问题。晋升需要“展示影响”,而众所周知的是,要做到这一点最简单的方法是发布一些新事物(不是惟一的方法,但是最简单)。结果是 Googler 们比起改进现有的解决方案,对于推广他们自己内测品质的原型方案更感兴趣。在 SRE 之间,我们经常开玩笑说, Google 内部有两种软件:一种是老的东西,工作得很好,但已经废弃了,甚至连考虑使用都是不够谷歌化的;另一种是热门的新东西,尽管它们还不能用,但却是今天 100% 可以使用的官方工具。作为 SRE我们经常亲眼看到新的热点事物出了什么问题有时甚至在没出 alpha 之前它就已经成了过时的旧东西)。([我此前已经对这类事物进行了更为深入的讨论。][6]
这不是我们这些愤世疾俗的 SRE 所想象的东西;这在公司中被公认为是一个问题,而我记得有人向我保证,晋升委员会已经开始通过维护工作等方式寻找关于其影响的证据。
### 晋升申请
2015 年,在 Google 工作了两年之后,我的经理告诉我,现在是时候申请一个高于我新毕业生水准的晋升了。晋升过程是每年两次由晋升委员会进行集中管理的。你可以先提出申请,然后加上一份对你所从事过的项目的简短描述,再加上同事的推荐信。委员会将会进行审查,然后给你赞成或反对的意见。仅仅有你经理的推荐是不够的,因为你的经理有想让你获得晋升的动机。手下有高级别的员工有助于你自己的职业发展。
长话短说,我提交了我的申请,而委员会说不。事实上,这是个相当糟糕的拒绝。我不记得详细的答复了,但感觉就像是委员会在我的申请中寻找可以不屑一顾的东西。例如,我从事过的一个项目是一个内部工具,它出现了功能需求的积压。我查看了这个项目,发现根本问题在于它已经超出了构建它的键值存储,需要一个合适的数据库。我主张切换到关系数据库,并实现了它:模式、数据迁移、查询、实时站点迁移等等。新查询的速度要快得多,而且(更重要的是)可以有效地支持新功能。在进行迁移之前,我必须要解决的一个问题是大部分代码没有被测试所覆盖,而这是由于大部分的代码都不可测试。我使用依赖注入以及[我此前讨论过的其他技巧][7]重构了代码,而这使我能够构建一组回归测试套件。我记得这个项目被驳回主要是被评价为测试单元的编写是“新毕业生水平的工作”。
我的经理真的很支持我,并且写了上诉。他没有给我看,但是我认为这是可以被缩减成 “WTF” 的若干页(更雄辩而详尽地论述)。以下是一些我也认为这一回复有点 “WTF” 的原因:
Google SRE 有一种“关键人物”的概念。一个项目的关键人物有两个角色:一个是比起其他 SRE 对于软件项目有着更为深入的了解,以便你能够回答他们可能会提出的问题;另一个角色是作为项目本身的开发人员的第一联络人,以便他们的所有 SRE 问题都能得到回答。 Google 的职业阶梯指南说,关键人物不应该处于“新毕业生水准”,而应该晋升。正如我在申请中所写的,我是三个项目的关键人物。
我的关键人物经历使得想要找到同意支持我的晋升申请的资深开发人员很容易。当他们发现我是新毕业生级别时都十分震惊。他们都同意支持我的申请,认可我已经处在了一个更高的级别。
在我的申请之中,我提到曾担任过一组新毕业实习生的导师。当我提出申请时,他们之中的许多人都已经被聘用为了正式雇员。我足够资深,可以去担任他们的导师,但是还绝不足以晋升到比他们更高的级别。
给我经理上诉的回复与最初的审查截然不同。这次,我“大大超出了对于我‘新毕业生’级别工作的期望”,但是问题在于他们需要稍多一些时间来确保我能够晋升到新毕业生加一的级别。我被告知在接下来的 6 个月时间里,倘若我能够继续超出预期,直到下一个晋升周期,也许那时我就会得到晋升。上诉结束了;这就是最终结果。
我写了一封电子邮件,表示我要采取另一种选择。就像许多科技公司一样, Google 也有员工持股计划。在开始工作时,你会得到一笔象征性的补助金,而在各个“投资”里程碑时刻,你会收到真正的股份。我的下一次股票授予是在几个月之后。从那以后,我将不再为 Google 工作。
### 我离开的原因
任何辞职的决定并不容易,而某天你或许会面临同样的抉择。以下是一些有助于我作出决定的因素。([我在以前的一篇贴子里对一些这类想法进行了更深入的解释。][8]
如果你思考一下,考虑到我并不是字面意义上真正的应届毕业生, Google 的评价应该是这样的:“你正在做一些非常错误的事情。在 X、 Y 还有 Z 方面有所改进之前,你根本不会得到晋升。”被告知“你远远超出了预期,但是我们还需要 6 个月左右的时间”,这是毫无道理的。没有人关注我是否有能力做好我的工作。我得到了许多借口,但是没有能够帮助我提高的任何有用反馈。(注意:有时候你必须要明确地要求反馈。经理们可能会陷入捍卫自己所给出的绩效评级的陷阱,而不会去考虑报告是否需要反馈。)
我也不确定晋升委员会会在 6 个月里看到什么他们在已经过去的 2 年时间里都没有看到的问题。他们难保不会再要求 6 个月时间?如果我需要花上多年时间来证明自己以获得新毕业生加一的级别晋升,那么我升到新毕业生加二的时候得有多老呢?
刚加入 Google 时,我的工作级别无关紧要,因为我当时学到了那么多东西,并且能在我的简历里写入一家著名的公司。两年过后,等式变得不同了。 Google 所提供给我的未来所具有的价值正在下降,而 Google 之外机会的价值却正在上升。 Google 的职位实际上在 Google 之外几乎毫无意义。在过去的 5 年间,许多人都问过我在 Google 做过什么,但是没有一个人问我在 Google 是什么职位,也没人称我为“新毕业生”。尽管我在短期内受到了财务方面的打击,但实际上在我上交员工证的那天我就已经得到了晋升。
值得称赞的是Google 没有做过任何类似于以下的事情,但是在其他公司中却很常见:试图让员工对于要求加薪感到内疚。在几年前我工作过的地方,一些工程师在一次成功发布会后,在许多紧要关头要求加薪。管理层扮演起了受害者的角色,并且指责工程师们是在“强迫他们”。(大约 6 个月时间后,他们失去了自己大部分的工程团队。)如果你真的愿意就辞职时间进行配合(例如,在发布日期之后,而不是前一周),并且愿意记录下你的知识并做了整理等等,那么你仅仅是由于雇主支付给你的工资不足而“强迫他们”。
名义上,我在 Google 留下了大量未授予的股票。但是知道你拥有股票时,股票才属于你。我只是得到了未来会有分红的承诺,而我可以将其除以所需的时间来将其转换为同等的工资率。为这项投资工作 2 个月是值得的,为了剩余的投资工作数年是不值得的。不要被授予股票的偏见所迷惑。
什么时候不应该辞职呢?嗯,与在其他地方相比,你能得到的很多吗?公司的职业发展道路不是天上掉下来的,他们是一系列的业务报价,代表着你将为什么样的公司评估而工作。如果你认为自己能得到很多(考虑到所有的薪酬和像是工作环境之类的无形资产),很好!否则,是时候认真考虑一下下一步该做什么了。
### 离开 Google 之后
我应当警告你的是,我采取了高增长的战略,但是牺牲了短期稳定性。如果对你而言稳定性更为重要,你应该做出不一样的选择。我的 A 计划、 B 计划、 C 计划都失败了,我最终花费了几个月时间苦苦找寻出路。最后,我在一家小型网店得到了一份合同,为 [Safety Town][9] 工作,一家政府建立的面向孩子们的道路安全网站。那里的薪水较之于 Google 是一个巨大的缩减,尤其是考虑到这是我几个月以来的第一份工作。但是,你知道,我真的很享受这个项目。当然了,它不像 Google 那么“酷”,而且可能一些学校里的孩子也不觉得它酷。另一方面,在 Google我只是机器中的一个螺丝钉。 Safety Town 有一个小团队,每个人都扮演着至关重要的角色。在 Safety Town 项目中,我是后端工程师, Safety Town 当时是我唯一需要费心的事情。而且可能一些孩子已经在这个网站上学到了一两件有关道路安全的事情。从那以后,我做了很多项目,大多数都更大,但是我仍然会向人们展示 Safety Town。
![Screenshot of Safety Town home page, owned by Australian NSW government.][10]
我记得 Google 悉尼办事处的一张海报,上面写着:“飞向月球吧!即使你错过了,你也会降落在群星之中!”人们很容易忘记,即使你不是在为知名公司或初创公司做“登月计划”,你也可以拥有高质量的生活。
这儿有一个帮助我获得合同的窍门。我会去参加悉尼的科技活动,站在能看到求职公告板的范围之中,等着看见有人在上面写东西。假设他们正在为一个保险公司项目写 CSS 开发方面的信息。即使我对 CSS 或保险不是特别感兴趣,我也会晃悠过去说:“嗨,这是个什么类型的保险项目?”这是最容易的开启谈话的方式,因为在他们努力往求职公告板上的狭小缝隙中写字的时候,满脑子都是这个项目。通常情况下,这样的谈话仍然不会为我带来一份工作,但是偶尔也会发现一些我能够帮上忙的东西。有些活动没有求职公告板,但是组织者们往往很乐意把麦克风递给别人几分钟。这为他们的活动增添了社区参与度。
我在做了一个政府采购的网站后,我取得了重大的突破,因为我学会了不至于对政府采购一窍不通。很难确切说出这些知识的价值,但是不到一年过后,我就签署了一份政府合同,比我此前所期望的要多了 40%。(不过,我如今没有做那么多的政府和大型企业的工作了。)
大约一年半过后,我有了自己的一人公司。随着我声誉的建立,我逐渐获得了更多类似于 SRE 的工作。基本上,从事开发工作是我的“工作”,然后几个月后就有一个需要 SRE/DevOps 帮助的人联系了我。我事实上既喜欢 SRE也喜欢纯开发工作但是供求关系意味着 SRE 工作是个好工作。我仍然可以在空余时间编程。
说起这个,工作与生活的平衡是我在新生活中最喜欢的事情。没有人在两份合同之间给我酬劳,但是我可以通过在业余项目中学习新东西来充分利用这一间隙。在一个漫长而又紧张的合同之后,我休息了一下,[进行了为期一个月的背包徒步旅行,探索了日本乡村][11]。这是我期待了很长时间的一次旅行,但是在入职 Google 之前我需要更多的钱,而在 Google 供职期间我又需要更多的时间。自营职业远非没有压力,也不是适合每一个人的,但是有的压力会让你感到死气沉沉,有的压力则会让你越发充满活力。于我而言,自主营生是第二种,我想说,和在 Google 时相比,过去的 5 年间我的压力总体上有所减轻。对于我来说,至少我能够诚实地说我不后悔当初加入 Google也不后悔当初离开 Google。
--------------------------------------------------------------------------------
via: https://theartofmachinery.com/2020/08/04/leaving_google.html
作者:[Simon Arneaud][a]
选题:[lujun9972][b]
译者:[JonnieWayy](https://github.com/JonnieWayy)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://theartofmachinery.com
[b]: https://github.com/lujun9972
[1]: https://mtlynch.io/why-i-quit-google/
[2]: https://projecteuler.net
[3]: https://codingcompetitions.withgoogle.com/codejam
[4]: https://theartofmachinery.com/images/leaving_google/mori-tower.jpg
[5]: https://www.kalzumeus.com/2012/01/23/salary-negotiation/
[6]: https://theartofmachinery.com/2019/03/19/hello_world_marketing.html
[7]: https://theartofmachinery.com/2016/03/28/dirtying_pure_functions_can_be_useful.html
[8]: https://theartofmachinery.com/2018/10/07/payrise_by_switching_jobs.html
[9]: https://www.safetytown.com.au/
[10]: https://theartofmachinery.com/images/leaving_google/safetytown.png

View File

@ -0,0 +1,170 @@
[#]: collector: (lujun9972)
[#]: translator: (geekpi)
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-12612-1.html)
[#]: subject: (Recognize more devices on Linux with this USB ID Repository)
[#]: via: (https://opensource.com/article/20/8/usb-id-repository)
[#]: author: (Alan Formy-Duval https://opensource.com/users/alanfdoss)
利用这个 USB ID 仓库识别更多 Linux 上的设备
======
> 这是一个包含了所有已知 USB 设备 ID 的开源项目。
![](https://img.linux.net.cn/data/attachment/album/202009/13/225426zpfbfopxhjxomuxf.jpg)
市场上有成千上万的 USB 设备:键盘、扫描仪、打印机、鼠标和其他无数的设备,都能在 Linux 上工作。它们的供应商详情都存储在 USB ID 仓库中。
### lsusb
Linux `lsusb` 命令列出了连接到系统的 USB 设备的信息,但有时信息不完整。例如,我最近注意到我的一个 USB 设备的品牌没有被识别。设备是可以使用的,但是在列出我所连接的 USB 设备的详情中没有提供任何识别信息。以下是我的 `lsusb` 命令的输出:
```
$ lsusb
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 004: ID 046d:082c Logitech, Inc.
Bus 001 Device 003: ID 0951:16d2 Kingston Technology
Bus 001 Device 002: ID 18f8:1486  
Bus 001 Device 005: ID 051d:0002 American Power Conversion Uninterruptible Power Supply
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
```
正如你在最后一栏中看到的,有一个设备没有制造商描述。要确定这个设备是什么,我必须对我的 USB 设备树进行更深入的检查。幸运的是,`lsusb` 命令有更多的选项。其中一个选项是 `-D device`,来获取每个设备的详细信息,正如手册页面所解释的那样:
> “不会扫描 `/dev/bus/usb` 目录,而只显示给定设备文件所属设备的信息。设备文件应该是类似 `/dev/bus/usb/001/001` 这样的文件。这个选项会像 `v` 选项一样显示详细信息,但你必须是 root 用户才行。"
我认为如何将设备路径传递给 `lsusb` 命令并不容易但在仔细阅读手册页和初始输出后我能够确定如何构造它。USB 设备驻留在 UDEV 文件系统中。它们的设备路径始于 USB 设备目录 `/dev/bus/usb/`。路径的其余部分由设备的总线 ID 和设备 ID 组成。我的无描述设备是 `Bus 001 Device 002`,被翻译成了 `001/002`,完成的路径为 `/dev/bus/usb/001/002`。现在我可以把这个路径传给 `lsusb`。我还会用管道传给 `more`,因为这里往往有很多信息:
```
$ lsusb -D /dev/bus/usb/001/002 |more
Device: ID 18f8:1486  
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               1.10
  bDeviceClass            0 (Defined at Interface level)
  bDeviceSubClass         0
  bDeviceProtocol         0
  bMaxPacketSize0         8
  idVendor           0x18f8
  idProduct          0x1486
  bcdDevice            1.00
  iManufacturer           0
  iProduct                1
  iSerial                 0
  bNumConfigurations      1
  Configuration Descriptor:
    bLength                 9
    bDescriptorType         2
    wTotalLength           59
    bNumInterfaces          2
    bConfigurationValue     1
    iConfiguration          0
    bmAttributes         0xa0
      (Bus Powered)
      Remote Wakeup
    MaxPower              100mA
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        0
      bAlternateSetting       0
      bNumEndpoints           1
      bInterfaceClass         3 Human Interface Device
      bInterfaceSubClass      1 Boot Interface Subclass
      bInterfaceProtocol      2 Mouse
      iInterface              0
        HID Device Descriptor:
```
不幸的是,这里并没有提供我希望找到的细节。初始输出中出现的两个字段 `idVendor``idProduct` 都是空的。这有些帮助,因为往下看一下,就会发现 `Mouse` 这个词。所以,这个设备就是我的鼠标。
### USB ID 仓库
这让我不禁想知道如何才能填充这些字段,不仅是为了自己,也是为了其他 Linux 用户。原来已经有了一个开源项目:[USB ID 仓库][2]。它是一个公共仓库,它包含了 USB 设备中使用的所有已知 ID。它也被用于各种程序中包括 [USB Utilities][3],用于显示人类可读的设备名称。
![The USB ID Repository Site][4]
你可以从网站上或通过下载数据库来浏览特定设备的仓库。也欢迎用户提交新的数据。我要为我的鼠标提交数据,因为它没有在里面。
### 更新你的 USB ID
USB ID 数据库存储在一个名为 `usb.ids` 的文件中。这个文件的位置可能会因 Linux 发行版的不同而不同。
在 Ubuntu 18.04 中,这个文件位于 `/var/lib/usbutils`。要更新数据库,使用命令 `update-usbids`,你需要用 root 权限或 `sudo` 来运行。
```
$ sudo update-usbids
```
如果有新文件,它就会被下载。当前的文件将被备份,并被替换为新文件:
```
$ ls -la
total 1148
drwxr-xr-x  2 root root   4096 Jan 15 00:34 .
drwxr-xr-x 85 root root   4096 Nov  7 08:05 ..
-rw-r--r--  1 root root 614379 Jan  9 15:34 usb.ids
-rw-r--r--  1 root root 551472 Jan 15 00:34 usb.ids.old
```
最新版本的 Fedora Linux 将数据库文件保存在 `/usr/share/hwdata` 中。而且,没有更新脚本。而是,数据库由一个名为 `hwdata` 的软件包维护。
```
# dnf info hwdata
Installed Packages
Name         : hwdata
Version      : 0.332
Release      : 1.fc31
Architecture : noarch
Size         : 7.5 M
Source       : hwdata-0.332-1.fc31.src.rpm
Repository   : @System
From repo    : updates
Summary      : Hardware identification and configuration data
URL          : https://github.com/vcrhonek/hwdata
License      : GPLv2+
Description  : hwdata contains various hardware identification and configuration data,
             : such as the pci.ids and usb.ids databases.
```
现在我的 USB 设备列表在这个之前未命名的设备旁边显示了一个名字。比较一下上面的输出:
```
$ lsusb
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 004: ID 046d:082c Logitech, Inc. HD Webcam C615
Bus 001 Device 003: ID 0951:16d2 Kingston Technology
Bus 001 Device 014: ID 18f8:1486 [Maxxter]
Bus 001 Device 005: ID 051d:0002 American Power Conversion Uninterruptible Power Supply
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
```
你可能会注意到,随着仓库定期更新新设备和现有设备的详细信息,其他设备的描述也会发生变化。
### 提交新数据
提交新数据有两种方式:使用网站或通过电子邮件发送特殊格式的补丁文件。在开始之前,我阅读了提交指南。首先,我必须注册一个账户,然后我需要使用项目的提交系统提供我鼠标的 ID 和名称。添加任何 USB 设备的过程都是一样的。
你使用过 USB ID 仓库么?如果有,请在评论中分享你的反馈。
--------------------------------------------------------------------------------
via: https://opensource.com/article/20/8/usb-id-repository
作者:[Alan Formy-Duval][a]
选题:[lujun9972][b]
译者:[geekpi](https://github.com/geekpi)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://opensource.com/users/alanfdoss
[b]: https://github.com/lujun9972
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/usb-hardware.png?itok=ROPtNZ5V (Multiple USB plugs in different colors)
[2]: http://www.linux-usb.org/usb-ids.html
[3]: https://sourceforge.net/projects/linux-usb/files/
[4]: https://opensource.com/sites/default/files/uploads/theusbidrepositorysite.png (The USB ID Repository Site)
[5]: https://creativecommons.org/licenses/by-sa/4.0/

View File

@ -1,22 +1,24 @@
[#]: collector: (lujun9972)
[#]: translator: (geekpi)
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-12582-1.html)
[#]: subject: (Create and run Python apps on your Android phone)
[#]: via: (https://opensource.com/article/20/8/python-android-mobile)
[#]: author: (Phani Adabala https://opensource.com/users/adabala)
在你的 Android 手机上创建和运行 Python 应用
======
使用 Termux 和 Flask 在你的移动设备上创建、开发和运行一个网络应用。
![Tux and Android stuffed animals on shelf][1]
学习和使用 Python 是很有趣的。由于它越来越受欢迎,有大量的方式可以让计算世界比现在更好
> 使用 Termux 和 Flask 在你的移动设备上创建、开发和运行一个网页应用。
想象一下,构建和运行 python 应用,无论是开发一个命令行工具,从互联网上获取你最喜欢的文章,还是启动一个直接在掌上运行的网络服务器,所有这些都只需要一个 Android 移动设备和开源工具。这将完全改变你对移动设备的看法,将它从一个仅仅让你消费内容的设备变成一个帮助你发挥创造力的设备。
![](https://img.linux.net.cn/data/attachment/album/202009/04/214901zsohgryndzrcs6zz.jpg)
在本文中,我将演示运行和测试一个简单的 Python 应用所需的所有的工具、软件包、步骤等等。我使用 [Flask 框架][2]来创建一个简单的 “Hello, World!” 应用,并在一个简单而强大的 Web 服务器上运行。最棒的是,这一切都发生在手机上。不需要笔记本或台式机。
学习和使用 Python 是很有趣的。由于它越来越受欢迎,有越来越多的方式可以让计算世界比现在更好。
想象一下,只需一个 Android 移动设备和开源工具,就可以构建和运行一个 Python 应用,无论是开发一个命令行工具从互联网上获取你最喜欢的文章,还是启动一个直接在掌上设备运行的网页服务器,所有这些都可以实现。这将完全改变你对移动设备的看法,将它从一个仅仅让你消费内容的设备变成一个帮助你发挥创造力的设备。
在本文中,我将演示运行和测试一个简单的 Python 应用所需的所有的工具、软件包、步骤和各种零零散散的东西。我使用 [Flask 框架][2]来创建一个简单的 “Hello, World!” 应用,并在一个简单而强大的网页服务器上运行。最棒的是,这一切都发生在手机上。不需要笔记本或台式机。
### 在 Android 上安装 Termux
@ -24,27 +26,24 @@
![Welcome to Termux][6]
安装 Termux 后,启动它并使用 Termux 的 **pkg** 命令执行一些必要的软件安装。
订阅额外的仓库 “root-repo”
安装 Termux 后,启动它并使用 Termux 的 `pkg` 命令执行一些必要的软件安装。
订阅附加仓库 `root-repo`
```
`$ pkg install root-repo`
$ pkg install root-repo
```
执行更新,使所有安装的软件达到最新状态。
```
`$ pkg update`
$ pkg update
```
最后,安装 Python
```
`$ pkg install python`
$ pkg install python
```
![Install Python][7]
@ -57,7 +56,6 @@
首先创建一个项目目录:
```
$ mkdir Source
$ cd Source
@ -65,55 +63,50 @@ $ cd Source
接下来,创建一个 Python 虚拟环境。这是 Python 开发者的常见做法,它有助于让你的 Python 项目独立于你的开发系统(在本例中是你的手机)。在你的虚拟环境中,你将能够安装特定于你应用的 Python 模块。
```
`$ python -m venv venv`
$ python -m venv venv
```
激活你的新虚拟环境(注意,开头的两个点用空格隔开)
```
$ . ./venv/bin/activate
(env)$
```
请注意你的 shell 提示符现在以 **(env)** 开头,表示你在虚拟环境中。
现在使用 **pip** 安装 Flask Python 模块。
请注意你的 shell 提示符现在以 `(env)` 开头,表示你在虚拟环境中。
现在使用 `pip` 安装 Flask Python 模块。
```
`(env) $ pip install flask`
(env) $ pip install flask
```
### 在 Android 上写 Python 代码
你已经准备好了。现在你需要为你的应用编写代码。
要做到这一点,你需要有经典文本编辑器的经验。我使用的是 **vi**。如果你不熟悉 **vi**,请安装并试用 **vimtutor**,它(如其名称所暗示的)可以教你如何使用这个编辑器。如果你有其他你喜欢的编辑器,如 **jove**、**jed**、**joe** 或 **emacs**,你可以安装并使用其中一个。
现在,由于这个演示程序非常简单,你也可以直接使用 shell 的 **heredoc** 功能,它允许你直接在提示符中输入文本。
要做到这一点,你需要有经典文本编辑器的经验。我使用的是 `vi`。如果你不熟悉 `vi`,请安装并试用 `vimtutor`,它(如其名称所暗示的)可以教你如何使用这个编辑器。如果你有其他你喜欢的编辑器,如 `jove`、`jed`、`joe` 或 `emacs`,你可以安装并使用其中一个。
现在,由于这个演示程序非常简单,你也可以直接使用 shell 的 heredoc 功能,它允许你直接在提示符中输入文本。
```
(env)$ cat &lt;&lt; EOF &gt;&gt; hello_world.py
&gt; from flask import Flask
&gt; app = Flask(__name__)
&gt;
&gt; @app.route('/')
&gt; def hello_world():
&gt;     return 'Hello, World!'
&gt; EOF
(env)$ cat << EOF >> hello_world.py
> from flask import Flask
> app = Flask(__name__)
>
> @app.route('/')
> def hello_world():
> return 'Hello, World!'
> EOF
(env)$
```
是仅六行的代码,但有了它,你可以导入 Flask创建一个应用并将传入流量路由到名为 **hello_world** 的函数。
只有六行代码,但有了它,你可以导入 Flask创建一个应用并将传入流量路由到名为 `hello_world` 的函数。
![Vim on Android][8]
现在你已经准备好了 Web 服务器的代码。现在是时候设置一些[环境变量][9],并在你的手机上启动一个 Web 服务器了。
现在你已经准备好了网页服务器的代码。现在是时候设置一些[环境变量][9],并在你的手机上启动一个网页服务器了。
```
(env) $ export FLASK_APP=hello_world.py
@ -125,32 +118,30 @@ $ . ./venv/bin/activate
启动应用后,你会看到这条消息:
```
`serving Flask app… running on http://127.0.0.1:5000/`
serving Flask app… running on http://127.0.0.1:5000/
```
这表明你现在在 **localhost**(也就是你的设备)上运行着一个微型 Web 服务器。该服务器正在监听来自 5000 端口的请求。
这表明你现在在 localhost也就是你的设备上运行着一个微型网页服务器。该服务器正在监听来自 5000 端口的请求。
打开你的手机浏览器并进入到 **<http://localhost:5000>**,查看你的网络应用。
打开你的手机浏览器并进入到 `http://localhost:5000`,查看你的网页应用。
![Your web app][11]
你并没有损害手机的安全性。你只运行了一个本地服务器,这意味着你的手机不接受来自外部世界的请求。只有你可以访问你的 Flask 服务器。
为了让别人看到你的服务器,你可以在**运行**命令中加入 **/\--host=0.0.0.0** 来禁用 Flask 的调试模式。这确实会打开手机上的端口,所以要谨慎使用。
为了让别人看到你的服务器,你可以在 `run` 命令中加入 `--host=0.0.0.0` 来禁用 Flask 的调试模式。这会打开你的手机上的端口,所以要谨慎使用。
```
(env) $ export FLASK_ENV=””
(env) $ flask run host=0.0.0.0
```
**Ctrl+C** 停止服务器(使用特殊的 Termux 控制键)
`Ctrl+C` 停止服务器(使用特殊的 `Termux` 键来作为 `Ctrl` 键)
### 决定下一步怎么做
你的手机可能不是一个严肃的网应用的理想服务器平台,但这个例子证明了可能性是无限的。你可能会在 Android 手机上编程,只是因为这是一种方便的实践方式,或者因为你有一个令人兴奋的本地化网应用的新想法,或者你只是碰巧使用 Flask 应用来完成自己的日常任务。正如爱因斯坦曾经说过的”想象力比知识更重要“,对于任何一个新手编码者,或者一个经验丰富的 Linux 或 Android 爱好者来说,这是一个有趣的小项目。它可以扩展到无穷的层次,所以让你的好奇心接手,并做出一些令人兴奋的东西!
你的手机可能不是一个严肃的网应用的理想服务器平台,但这个例子证明了可能性是无限的。你可能会在 Android 手机上编程,只是因为这是一种方便的实践方式,或者因为你有一个令人兴奋的本地化网应用的新想法,或者你只是碰巧使用 Flask 应用来完成自己的日常任务。正如爱因斯坦曾经说过的“想象力比知识更重要”,对于任何一个新手编码者,或者一个经验丰富的 Linux 或 Android 爱好者来说,这是一个有趣的小项目。它可以扩展到无穷的层次,所以让你的好奇心接手,并做出一些令人兴奋的东西!
--------------------------------------------------------------------------------
@ -159,7 +150,7 @@ via: https://opensource.com/article/20/8/python-android-mobile
作者:[Phani Adabala][a]
选题:[lujun9972][b]
译者:[geekpi](https://github.com/geekpi)
校对:[校对者ID](https://github.com/校对者ID)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出

View File

@ -1,84 +1,76 @@
[#]: collector: (lujun9972)
[#]: translator: (geekpi)
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-12586-1.html)
[#]: subject: (Customize your GNOME desktop theme)
[#]: via: (https://opensource.com/article/20/8/gnome-themes)
[#]: author: (Alan Formy-Duval https://opensource.com/users/alanfdoss)
自定义你的 GNOME 桌面主题
======
使用 Tweaks 和它的用户主题扩展来改变你的 Linux UI。
![Gnomes in a window.][1]
GNOME 是一个相当简单和精简的 Linux 图形用户界面 (GUI),很多用户喜欢它的简约外观。虽然它初始非常基本,但你可以根据自己的喜好来定制 [GNOME][2] 。多亏了 GNOME Tweaks 和用户主题扩展,你可以改变顶部栏、窗口标题栏、图标、光标和许多其他 UI 选项的外观。
> 使用“优化”和它的用户主题扩展来改变你的 Linux UI。
![](https://img.linux.net.cn/data/attachment/album/202009/06/110116kmufkkc31akwfp1w.jpg)
GNOME 是一个相当简单和精简的 Linux 图形用户界面GUI很多用户喜欢它的简约外观。虽然它基本上是开箱即用的但你可以根据自己的喜好来定制 [GNOME][2] 。有了 GNOME “优化” 和用户主题扩展,你可以改变顶部栏、窗口标题栏、图标、光标和许多其他 UI 选项的外观。
### 开始使用
在你改变你的 GNOME 主题之前,你必须安装 [Tweaks][3] 并启用用户主题扩展。
在你改变你的 GNOME 主题之前,你必须安装 <ruby>[优化][3]<rt>Tweaks</rt></ruby> 并启用用户主题扩展。
#### 安装 GNOME Tweaks
#### 安装 GNOME “优化”
你可以在 GNOME 软件中心找到 Tweaks,只需点击一个按钮就可以快速安装。
你可以在 GNOME “软件”中找到“优化”,只需点击一个按钮就可以快速安装。
![Install Tweaks in Software Center][4]
(Alan Formy-Duval, [CC BY-SA 4.0][5])
如果你喜欢命令行,请使用你的软件包管理器。例如,在 Fedora 或 CentOS 上:
```
`$ sudo dnf install gnome-tweaks`
$ sudo dnf install gnome-tweaks
```
在 Debian 或类似的发行版:
```
`$ sudo apt install gnome-tweaks`
$ sudo apt install gnome-tweaks
```
#### 启用用户主题
要启用用户主题扩展,启动 Tweaks 并选择 **Extensions**。找到 **User themes**,点击滑块启用。
要启用用户主题扩展,启动“优化”并选择“<ruby>扩展<rt>Extensions</rt></ruby>”。找到 “用户主题<rt>User themes</rt></ruby>,点击滑块启用。
![Enable User Themes Extension][6]
(Alan Formy-Duval, [CC BY-SA 4.0][5])
### 获取主题
现在你已经完成了这些预先条件,你已经准备好寻找和下载一些主题了。一个寻找新主题的好网站是 [GNOME-Look.org][7]。
在页面的左侧有一个主题类别的列表。当你找到一个你想要的主题,你需要下载它。我直接把 `.tar` 文件下载到我的家目录下的 `.themes` 目录(你可能需要先创建这个目录)。
```
`$ mkdir ~/.themes`
$ mkdir ~/.themes
```
如果你想让所有用户都能使用这个主题,请把它放在 `/usr/share/themes` 中。
```
`$ tar xvf theme_archive.tar.xz`
$ tar xvf theme_archive.tar.xz
```
下载后,解压压缩包。你可以删除 `.tar.xz` 文件以节省一些磁盘空间。
### 应用主题
要应用你的新主题,在 Tweaks 中进入 **Appearance**。在这里,你可以为你的桌面的每个方面选择不同的选项。
要应用你的新主题,在“优化”中进入“<ruby>外观<rt>Appearance</rt></ruby>。在这里,你可以为你的桌面的每个方面选择不同的选项。
![Apply a theme][8]
(Alan Formy-Duval, [CC BY-SA 4.0][5])
### 多样性是生活的调剂品
### 多样性是生活的调剂品。
自从第一个图形界面面市以来能够用不同的墙纸、颜色、字体等个性化电脑桌面一直是一个受欢迎的功能。GNOME Tweaks 和用户主题扩展使这种自定义功能能够在所有 GNU/Linux 操作系统上的 GNOME 桌面环境中实现。而且开源社区还在继续提供广泛的主题、图标、字体和壁纸,任何人都可以下载、尝试和定制。
自从第一个图形界面面市以来能够用不同的墙纸、颜色、字体等个性化电脑桌面一直是一个受欢迎的功能。GNOME “优化”和用户主题扩展可以在所有 GNU/Linux 操作系统上的 GNOME 桌面环境中实现这种自定义。而且开源社区还在持续提供广泛的主题、图标、字体和壁纸,任何人都可以下载、尝试和定制。
你最喜欢的 GNOME 主题是什么,你为什么喜欢它们?请在评论中分享。
@ -89,7 +81,7 @@ via: https://opensource.com/article/20/8/gnome-themes
作者:[Alan Formy-Duval][a]
选题:[lujun9972][b]
译者:[geekpi](https://github.com/geekpi)
校对:[校对者ID](https://github.com/校对者ID)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出

View File

@ -0,0 +1,85 @@
[#]: collector: (lujun9972)
[#]: translator: (geekpi)
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-12617-1.html)
[#]: subject: (Manage your software repositories with this open source tool)
[#]: via: (https://opensource.com/article/20/8/manage-repositories-pulp)
[#]: author: (Melanie Corr https://opensource.com/users/melanie-corr)
用这个开源工具管理你的软件仓库
======
> 这篇文章介绍 Pulp一个开源仓库管理解决方案它的使用范围和功能在不断增长。
![](https://img.linux.net.cn/data/attachment/album/202009/15/205353hlidoullmmj44vzq.jpg)
[Foreman][2] 是一个强大的管理和自动化产品,它为 Linux 环境的管理员提供了企业级的解决方案它适用于四个关键场景供应管理、配置管理、补丁管理和内容管理。Foreman 中内容管理功能的一个主要组成部分是由 Pulp 项目提供的。虽然 Pulp 是这个产品的一个组成部分,但它也是一个独立的、自由开源的项目,自身也在取得巨大的进步。
让我们来看看 Pulp 项目,特别是最新版本 Pulp 3 的功能。
### 什么是 Pulp
Pulp 是一个管理软件包仓库,并将其提供给大量的消费者的平台。你可以使用 Pulp 在不同环境中镜像、同步、上传和推广各种内容,如 RPM、Python 包、Ansible 集合、容器镜像等。如果你有几十个、几百个甚至上千个软件包并需要更好的方式来管理它们Pulp 可以帮助你。
最新的主要版本是 [Pulp 3][3],它于 2019 年 12 月发布。Pulp 3 是多年来收集用户需求的结晶,并对现有的 Pulp 架构进行了全面的技术改造,以提高可靠性和灵活性。另外,它还包含了大量的新功能。
### 谁在使用 Pulp
大多数情况下,在 Pulp 用户管理的企业软件环境中内容的稳定性和可靠性是最重要的。Pulp 用户希望有一个平台来开发内容而不用担心仓库可能会消失。他们希望以安全的方式在其生命周期环境的不同阶段推广内容优化磁盘空间并扩展环境以满足新的需求。他们还需要灵活处理各种内容类型。Pulp 3 提供了这些以及更多功能。
### 在一处管理各类内容
安装 Pulp 后,你可以为你计划管理的内容类型添加[内容插件][4],将内容镜像到本地,添加私人托管的内容,并根据你的需求混合内容。例如,如果你是 Ansible 用户,而你又不想在 Ansible Galaxy 上托管你的私有内容,你可以添加 Pulp Ansible 插件,镜像你所需要的公共 Ansible 内容,并将 Pulp 作为一个内部平台,在你的组织中管理和分发可扩展的公共和私有 Ansible 角色和集合的混合。你可以用任何内容类型执行此操作。有各种各样的内容插件可供选择,包括 RPM、Debian、Python、容器和 Ansible 等等。还有一个文件插件,你可以用它来管理 ISO 镜像等文件。
如果你没有找到你所需的内容类型插件Pulp 3 引入了新的插件 API 和插件模板,你可以轻松创建一个属于自己的 Pulp 插件。你可以根据[插件编写指南][5]自动生成一个最小可用的插件,然后从那里开始构建。
### 高可用性
在 Pulp 3 中,从 MongoDB 到 PostgreSQL 的转变促进了性能和数据完整性的重大改进。Pulp 用户现在有了一个完全开源的技术栈它可以提供高可用性HA和更好的扩展性。
### 仓库版本管理
使用 Pulp 3你可以毫无风险地进行试验。每次你添加或删除内容时Pulp 都会创建一个不可变的仓库版本,这样你就可以回滚到早期的版本,从而保证操作的安全性和稳定性。通过使用发布和分发,你可以公开一个仓库的多个版本,你可以将其作为回滚到早期版本的另一种方法。如要回滚,你可以简单地将你的分发指向一个旧的发布。
### 磁盘优化
任何软件开发环境的主要挑战之一是磁盘优化。如果你不断地下载包例如你今天需要但明天不再需要的仓库每日构建那么磁盘空间将很快成为一个问题。Pulp 3 的设计已经考虑到了磁盘优化。当默认下载并保存所有的软件包,你也可以启用“按需”或“流式”选项。“按需”选项只下载和保存客户要求的内容,从而节省了磁盘空间。使用“流式”选项,它也会根据客户的要求进行下载,但它不会将内容保存在 Pulp 中。这对于同步内容是非常理想的,例如,从一个每日仓库同步,并让你在后期免于执行磁盘清理。
### 多种存储选项
即使进行了最好的磁盘优化随着项目的发展你可能需要一种方法来扩展你的部署以满足需求。除了本地文件存储Pulp 还支持一系列的云存储选项,如 Amazon S3 和 Azure以确保你可以扩展满足你的部署需求。
### 保护你的内容
Pulp 3 可以选择添加 [Certguard][6] 插件,该插件提供了一个支持 X.509 的 ContentGuard它要求客户在收到 Pulp 的内容之前提交证明其对内容的权利的证书。
只要客户端的证书没有过期,且由证书颁发机构签署,并在创建时存储在 Certguard 上,任何客户端在请求时提供基于 X.509 或基于 Red Hat 订阅管理证书都将获得授权。客户端使用安全传输层TLS提供证书这证明客户端不仅有证书还有它的密钥。你可以放心地开发知道你的内容正在受到保护。
Pulp 团队也在积极为整个 Pulp 部署一个基于角色的访问控制系统,这样管理员就可以确保正确的用户可以访问正确的环境。
### 在容器中试用 Pulp
如果你有兴趣亲自评估 Pulp 3你可以使用 Docker 或 Podman 轻松[在容器中安装 Pulp 3][7]。Pulp 团队一直在努力简化安装过程。你也可以使用 [Ansible 剧本][8] 来自动完成 Pulp 3 的全部安装和配置。
--------------------------------------------------------------------------------
via: https://opensource.com/article/20/8/manage-repositories-pulp
作者:[Melanie Corr][a]
选题:[lujun9972][b]
译者:[geekpi](https://github.com/geekpi)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://opensource.com/users/melanie-corr
[b]: https://github.com/lujun9972
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/fruit-orange-pomegranate-pulp-unsplash.jpg?itok=4cvODZDJ (Oranges and pomegranates)
[2]: https://opensource.com/article/17/8/system-management-foreman
[3]: https://pulpproject.org/about-pulp-3/
[4]: https://pulpproject.org/content-plugins/
[5]: https://docs.pulpproject.org/plugins/plugin-writer/index.html
[6]: https://pulp-certguard.readthedocs.io/en/latest/
[7]: https://pulpproject.org/pulp-in-one-container/
[8]: https://pulp-installer.readthedocs.io/en/latest/

View File

@ -0,0 +1,135 @@
[#]: collector: (lujun9972)
[#]: translator: (wxy)
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-12602-1.html)
[#]: subject: (What is DNS and how does it work?)
[#]: via: (https://www.networkworld.com/article/3268449/what-is-dns-and-how-does-it-work.html)
[#]: author: (Keith Shaw, Josh Fruhlinger )
什么是 DNS它是如何工作的
======
> 域名系统解析互联网网站的名称及其底层 IP 地址,并在此过程中增加了效率和安全性。
![](https://images.techhive.com/images/article/2017/04/domain-name-systems-dns-100719737-large.jpg)
<ruby>域名系统<rt>Domain Name System</rt></ruby>DNS是互联网的基础之一然而大多数不懂网络的人可能并不知道他们每天都在使用它来工作、查看电子邮件或在智能手机上浪费时间。
就其本质而言DNS 是一个与数字匹配的名称目录。这些数字,在这里指的是 IP 地址,计算机用 IP 地址来相互通信。大多数对 DNS 的描述都是用电话簿来比喻,这对于 30 岁以上的人来说是没有问题的,因为他们知道电话簿是什么。
如果你还不到 30 岁,可以把 DNS 想象成你的智能手机的联系人名单,它将人们的名字与他们的电话号码及电子邮件地址进行匹配,然后这个联系人名单的就像地球上的人一样多。
### DNS 简史
当互联网还非常、非常小的时候,人们很容易将特定的 IP 地址与特定的计算机对应起来,但随着越来越多的设备和人加入到不断发展的网络中,这种简单的情况就没法持续多久了。现在仍然可以在浏览器中输入一个特定的 IP 地址来到达一个网站,但当时和现在一样,人们希望得到一个由容易记忆的单词组成的地址,也就是我们今天所认识的那种域名(比如 linux.cn。在 20 世纪 70 年代和 80 年代早期,这些名称和地址是由一个人指定的,她是[斯坦福大学的 Elizabeth Feinler][2],她在一个名为 [HOSTS.TXT][3] 的文本文件中维护着一个主列表,记录了每一台连接互联网的计算机。
随着互联网的发展,这种局面显然无法维持下去,尤其是因为 Feinler 只处理加州时间下午 6 点之前的请求而且圣诞节也要请假。1983 年,南加州大学的研究人员 Paul Mockapetris 受命在处理这个问题的多种建议中提出一个折中方案。但他基本上无视了所有提出的建议,而是开发了自己的系统,他将其称为 DNS。虽然从那时起现今的它显然发生了很大的变化但在基本层面上它的工作方式仍然与将近 40 年前相同。
### DNS 服务器是如何工作的
将名字与数字相匹配的 DNS 目录并不是整个藏在互联网的某个黑暗角落。截至 2017 年底,[它记录了超过 3.32 亿个域名][4],如果作为一个目录确实会非常庞大。就像互联网本身一样,该目录分布在世界各地,存储在域名服务器(一般简称为 DNS 服务器)上,这些服务器都会非常有规律地相互沟通,以提供更新和冗余。
### 权威 DNS 服务器与递归 DNS 服务器的比较
当你的计算机想要找到与域名相关联的 IP 地址时,它首先会向<ruby>递归<rt>recursive</rt></ruby> DNS 服务器(也称为递归解析器)提出请求。递归解析器是一个通常由 ISP 或其他第三方提供商运营的服务器,它知道需要向其他哪些 DNS 服务器请求解析一个网站的名称与其 IP 地址。实际拥有所需信息的服务器称为<ruby>权威<rt>authoritative</rt></ruby> DNS 服务器。
### DNS 服务器和 IP 地址
每个域名可以对应一个以上的 IP 地址。事实上,有些网站有数百个甚至更多的 IP 地址与一个域名相对应。例如,你的计算机访问 [www.google.com][5] 所到达的服务器,很可能与其他国家的人在浏览器中输入相同的网站名称所到达的服务器完全不同。
该目录的分布式性质的另一个原因是,如果这个目录只在一个位置,在数百万,可能是数十亿在同一时间寻找信息的人中共享,那么当你在寻找一个网站时,你需要花费多少时间才能得到响应 —— 这就像是排着长队使用电话簿一样。
### 什么是 DNS 缓存?
为了解决这个问题DNS 信息在许多服务器之间共享。但最近访问过的网站的信息也会在客户端计算机本地缓存。你有可能每天使用 google.com 好几次。你的计算机不是每次都向 DNS 名称服务器查询 google.com 的 IP 地址,而是将这些信息保存在你的计算机上,这样它就不必访问 DNS 服务器来解析这个名称的 IP 地址。额外的缓存也可能出现在用于将客户端连接到互联网的路由器上以及用户的互联网服务提供商ISP的服务器上。有了这么多的缓存实际上对 DNS 名称服务器的查询数量比看起来要少很多。
### 如何找到我的 DNS 服务器?
一般来说,当你连接到互联网时,你使用的 DNS 服务器将由你的网络提供商自动建立。如果你想看看哪些服务器是你的主要名称服务器(一般是递归解析器,如上所述),有一些网络实用程序可以提供关于你当前网络连接的信息。[Browserleaks.com][6] 是一个很好的工具,它提供了很多信息,包括你当前的 DNS 服务器。
### 我可以使用 8.8.8.8 的 DNS 吗?
但要记住,虽然你的 ISP 会设置一个默认的 DNS 服务器,但你没有义务使用它。有些用户可能有理由避开他们 ISP 的 DNS —— 例如,有些 ISP 使用他们的 DNS 服务器将不存在的地址的请求重定向到[带有广告的网页][7]。
如果你想要一个替代方案,你可以将你的计算机指向一个公共 DNS 服务器,以它作为一个递归解析器。最著名的公共 DNS 服务器之一是谷歌的,它的 IP 地址是 8.8.8.8 和 8.8.4.4。Google 的 DNS 服务往往是[快速的][8],虽然对 [Google 提供免费服务的别有用心的动机][9]有一定的质疑,但他们无法真正从你那里获得比他们从 Chrome 浏览器中获得的更多信息。Google 有一个页面,详细说明了如何[配置你的电脑或路由器][10]连接到 Google 的 DNS。
### DNS 如何提高效率
DNS 的组织结构有助于保持事情的快速和顺利运行。为了说明这一点,让我们假设你想访问 linux.cn。
如上所述,对 IP 地址的初始请求是向递归解析器提出的。递归解析器知道它需要请求哪些其他 DNS 服务器来解析一个网站linux.cn的名称与其 IP 地址。这种搜索会传递至根服务器,它知道所有顶级域名的信息,如 .com、.net、.org 以及所有国家域名,如 .cn中国和 .uk英国。根服务器位于世界各地所以系统通常会将你引导到地理上最近的一个服务器。
一旦请求到达正确的根服务器它就会进入一个顶级域名TLD名称服务器该服务器存储二级域名的信息即在你写在 .com、.org、.net 之前的单词例如linux.cn 的信息是 “linux”。然后请求进入域名服务器域名服务器掌握着网站的信息和 IP 地址。一旦 IP 地址被找到,它就会被发回给客户端,客户端现在可以用它来访问网站。所有这一切都只需要几毫秒的时间。
因为 DNS 在过去的 30 多年里一直在工作,所以大多数人都认为它是理所当然的。在构建系统的时候也没有考虑到安全问题,所以[黑客们充分利用了这一点][11],制造了各种各样的攻击。
### DNS 反射攻击
DNS 反射攻击可以用 DNS 解析器服务器的大量信息淹没受害者。攻击者使用伪装成受害者的 IP 地址来向他们能找到的所有开放的 DNS 解析器请求大量的 DNS 数据。当解析器响应时,受害者会收到大量未请求的 DNS 数据,使其不堪重负。
### DNS 缓存投毒
[DNS 缓存投毒][12]可将用户转移到恶意网站。攻击者设法在 DNS 中插入虚假的地址记录这样当潜在的受害者请求解析其中一个中毒网站的地址时DNS 就会以另一个由攻击者控制的网站的 IP 地址作出回应。一旦访问了这些假网站,受害者可能会被欺骗,泄露密码或下载了恶意软件。
### DNS 资源耗尽
[DNS 资源耗尽][13]攻击可以堵塞 ISP 的 DNS 基础设施,阻止 ISP 的客户访问互联网上的网站。攻击者注册一个域名,并通过将受害者的名称服务器作为域名的权威服务器来实现这种攻击。因此,如果递归解析器不能提供与网站名称相关的 IP 地址,就会询问受害者的名称服务器。攻击者会对自己注册的域名产生大量的请求,并查询不存在的子域名,这就会导致大量的解析请求发送到受害者的名称服务器,使其不堪重负。
### 什么是 DNSSec
DNS 安全扩展是为了使参与 DNS 查询的各级服务器之间的通信更加安全。它是由负责 DNS 系统的<ruby>互联网名称与数字地址分配机构<rt>Internet Corporation for Assigned Names and Numbers</rt></ruby>ICANN设计的。
ICANN 意识到 DNS 顶级、二级和三级目录服务器之间的通信存在弱点,可能会让攻击者劫持查询。这将允许攻击者用恶意网站的 IP 地址来响应合法网站的查询请求。这些网站可能会向用户上传恶意软件,或者进行网络钓鱼和网络欺骗攻击。
DNSSec 将通过让每一级 DNS 服务器对其请求进行数字签名来解决这个问题,这就保证了终端用户发送进来的请求不会被攻击者利用。这就建立了一个信任链,这样在查询的每一步,请求的完整性都会得到验证。
此外DNSSec 可以确定域名是否存在,如果不存在,它就不会让该欺诈性域名交付给寻求域名解析的无辜请求者。
随着越来越多的域名被创建,越来越多的设备继续通过物联网设备和其他“智能”系统加入网络,随着[更多的网站迁移到 IPv6][14],将需要维持一个健康的 DNS 生态系统。大数据和分析的增长也[带来了对 DNS 管理的更大需求][15]。
### SIGRed: 蠕虫病毒 DNS 漏洞再次出现
最近,随着 Windows DNS 服务器缺陷的发现,全世界都看到了 DNS 中的弱点可能造成的混乱。这个潜在的安全漏洞被称为 SIGRed[它需要一个复杂的攻击链][16],但利用未打补丁的 Windows DNS 服务器,有可能在客户端安装和执行任意恶意代码。而且该漏洞是“可蠕虫传播”的,这意味着它可以在没有人为干预的情况下从计算机传播到计算机。该漏洞被认为足够令人震惊,以至于美国联邦机构[被要求他们在几天时间内安装补丁][17]。
### DNS over HTTPS新的隐私格局
截至本报告撰写之时DNS 正处于其历史上最大的一次转变的边缘。谷歌和 Mozilla 共同控制着浏览器市场的大部分份额,他们正在鼓励向 [DNS over HTTPS][18]DoH的方向发展在这种情况下DNS 请求将被已经保护了大多数 Web 流量的 HTTPS 协议加密。在 Chrome 的实现中,浏览器会检查 DNS 服务器是否支持 DoH如果不支持则会将 DNS 请求重新路由到谷歌的 8.8.8.8。
这是一个并非没有争议的举动。早在上世纪 80 年代就在 DNS 协议上做了大量早期工作的 Paul Vixie 称此举对安全来说是“[灾难][19]”:例如,企业 IT 部门将更难监控或引导穿越其网络的 DoH 流量。不过Chrome 浏览器是无所不在的DoH 不久就会被默认打开,所以让我们拭目以待。
--------------------------------------------------------------------------------
via: https://www.networkworld.com/article/3268449/what-is-dns-and-how-does-it-work.html
作者:[Keith Shaw][a], [Josh Fruhlinger][c]
选题:[lujun9972][b]
译者:[wxy](https://github.com/wxy)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://www.networkworld.com/author/Keith-Shaw/
[c]: https://www.networkworld.com/author/Josh-Fruhlinger/
[b]: https://github.com/lujun9972
[1]: https://www.networkworld.com/newsletters/signup.html
[2]: https://www.internethalloffame.org/blog/2012/07/23/why-does-net-still-work-christmas-paul-mockapetris
[3]: https://tools.ietf.org/html/rfc608
[4]: http://www.verisign.com/en_US/domain-names/dnib/index.xhtml?section=cc-tlds
[5]: http://www.google.com
[6]: https://browserleaks.com/ip
[7]: https://www.networkworld.com/article/2246426/comcast-redirects-bad-urls-to-pages-with-advertising.html
[8]: https://www.networkworld.com/article/3194890/comparing-the-performance-of-popular-public-dns-providers.html
[9]: https://blog.dnsimple.com/2015/03/why-and-how-to-use-googles-public-dns/
[10]: https://developers.google.com/speed/public-dns/docs/using
[11]: https://www.networkworld.com/article/2838356/network-security/dns-is-ubiquitous-and-its-easily-abused-to-halt-service-or-steal-data.html
[12]: https://www.networkworld.com/article/2277316/tech-primers/tech-primers-how-dns-cache-poisoning-works.html
[13]: https://www.cloudmark.com/releases/docs/whitepapers/dns-resource-exhaustion-v01.pdf
[14]: https://www.networkworld.com/article/3254575/lan-wan/what-is-ipv6-and-why-aren-t-we-there-yet.html
[15]: http://social.dnsmadeeasy.com/blog/opinion/future-big-data-dns-analytics/
[16]: https://www.csoonline.com/article/3567188/wormable-dns-flaw-endangers-all-windows-servers.html
[17]: https://federalnewsnetwork.com/cybersecurity/2020/07/cisa-gives-agencies-a-day-to-remedy-windows-dns-server-vulnerability/
[18]: https://www.networkworld.com/article/3322023/dns-over-https-seeks-to-make-internet-use-more-private.html
[19]: https://www.theregister.com/2018/10/23/paul_vixie_slaps_doh_as_dns_privacy_feature_becomes_a_standard/
[20]: https://www.facebook.com/NetworkWorld/
[21]: https://www.linkedin.com/company/network-world

View File

@ -0,0 +1,60 @@
[#]: collector: (lujun9972)
[#]: translator: (wxy)
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-12592-1.html)
[#]: subject: (Information could be half the world's mass by 2245, says researcher)
[#]: via: (https://www.networkworld.com/article/3570438/information-could-be-half-the-worlds-mass-by-2245-says-researcher.html)
[#]: author: (Patrick Nelson https://www.networkworld.com/author/Patrick-Nelson/)
研究人员表示,到 2245 年信息量可能占世界质量的一半
======
> 根据一位理论物理学家的说法,由于创建和存储数字信息所使用的能源和资源数量,数据应该被视为物理的,而不仅仅是看不见的一和零。
![](https://images.idgesg.net/images/article/2019/07/global_connections_digital_world_map_planet_earth_particles_light_by_luza_studios_gettyimages-1022793086_2400x1600-100806717-large.jpg)
一位大学学者建议,数字内容应该与气体、液体、等离子体和固体一样,被视为第五种物质状态。
英国朴茨茅斯大学高级讲师、发表在《AIP Advances》杂志上的《[信息灾难][1]》一文的作者 Melvin Vopson 称,由于以物理和数字方式创建、存储和分发数据所使用的能量和资源,数据已经发生了演变,现在应该被视为质量。
Vopson 还声称,数字比特正在走向压倒地球的道路,最终将超过原子的数量。
给数字信息分配质量的想法建立在一些现有数据点的基础之上。Vopson 引用了 IBM 的一项估计,发现数据每天以 2.5 万亿字节的速度产生。他还将每英寸超过 1 <ruby>太比特<rt>terabit</rt></ruby>的数据存储密度考虑在内,将比特的大小与原子的大小进行比较。
假设数据生成量每年增长 50%,根据宣布 Vopson 研究的[媒体发布][2],“比特的数量将在大约 150 年内等于地球上的原子数量。”
新闻稿中写道:“大约 130 年后,维持数字信息创造所需的动力将等于地球上目前产生的所有动力,到 2245 年,地球上一半的质量将转化为数字信息质量。”
Vopson 补充说COVID-19 大流行正在提高数字数据创造的速度,并加速这一进程。
他警告说一个饱和点即将到来“即使假设未来的技术进步将比特大小降低到接近原子本身的大小这个数字信息量所占的比重将超过地球的大小从而导致我们所定义的信息灾难。”Vopson 在[论文][3]中写道。
“我们正在一点一点地改变这个星球这是一场看不见的危机”Vopson 说,他是希捷科技公司的前研发科学家。
Vopson 并不是一个人在探索,信息并不是简单的不可察觉的 1 和 0。根据发布的消息Vopson 借鉴了爱因斯坦广义相对论中的质能对比;将热力学定律应用于信息的 Rolf Landauer 的工作;以及数字比特的发明者 Claude Shannon 的工作。
“当一个人将信息内容带入现有的物理理论中时这几乎就像物理学中的一切都多了一个维度”Vopson 说。
他的论文总结道,随着增长速度似乎不可阻挡,数字信息生产“将消耗地球上大部分的电力能源,从而导致道德和环境问题。”他的论文总结道。
有趣的是除此以外Vopson 还提出,如果像他所预测的那样,未来地球的质量主要由信息位组成,并且有足够的动力创造出来(不确定),那么“可以设想未来的世界主要由计算机模拟,并由数字比特和计算机代码主导,”他写道。
--------------------------------------------------------------------------------
via: https://www.networkworld.com/article/3570438/information-could-be-half-the-worlds-mass-by-2245-says-researcher.html
作者:[Patrick Nelson][a]
选题:[lujun9972][b]
译者:[wxy](https://github.com/wxy)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://www.networkworld.com/author/Patrick-Nelson/
[b]: https://github.com/lujun9972
[1]: https://aip.scitation.org/doi/10.1063/5.0019941
[2]: https://publishing.aip.org/publications/latest-content/digital-content-on-track-to-equal-half-earths-mass-by-2245/
[3]: https://aip.scitation.org/doi/full/10.1063/5.0019941
[4]: https://www.facebook.com/NetworkWorld/
[5]: https://www.linkedin.com/company/network-world

View File

@ -1,18 +1,20 @@
[#]: collector: (lujun9972)
[#]: translator: (geekpi)
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-12588-1.html)
[#]: subject: (Use GraphQL as an API gateway to monitor microservices)
[#]: via: (https://opensource.com/article/20/8/microservices-graphql)
[#]: author: (Rigin Oommen https://opensource.com/users/riginoommen)
使用 GraphQL 作为 API 网关来监控微服务
======
在一个问题使一个关键的微服务瘫痪之前,使用 GraphQL 的监控功能,帮助你及早发现问题。
![Net catching 1s and 0s or data in the clouds][1]
[微服务][2]和 [GraphQL][3] 就像面包和黄油一样,是一个很好的组合。它们本身都很好,结合起来就更好了。了解你的微服务的健康状况是很重要的,因为它们运行着重要的服务。如果等到某个关键的服务崩溃了才诊断问题,那是很愚蠢的。让 GraphQL 帮助你及早发现问题并不需要花费太多精力。
> 在问题导致关键的微服务瘫痪之前,使用 GraphQL 的监控功能帮助你及早发现问题。
![](https://img.linux.net.cn/data/attachment/album/202009/06/205052ve8eebyamcace4v8.jpg)
[微服务][2]和 [GraphQL][3] 就像面包和黄油一样,是一个很好的组合。它们本身都很棒,结合起来就更棒了。了解你的微服务的健康状况是很重要的,因为它们运行着重要的服务。如果等到某个关键的服务崩溃了才诊断问题,那是很愚蠢的。让 GraphQL 帮助你及早发现问题并不需要花费太多精力。
![GraphQL in Microservices][4]
@ -20,15 +22,13 @@
以下是我在设计服务检查时考虑的因素:
**服务器健康检查的要求:**
服务器健康检查的要求:
1. 我需要了解我的微服务的可用性状态。
2. 我希望能够管理服务器的负载。
3. 我希望对我的微服务进行端到端e2e测试。
4. 我应该能够预测中断。
![Service health in microservices][5]
### 做服务器健康检查的方法
@ -39,22 +39,19 @@
2. **脚本化浏览器:**脚本化浏览器比较高级。像 [Selenium][6] 这样的浏览器自动化工具可以让你实现自定义的监控规则集。
3. **API 测试:**API 测试用于监控 API 端点。这是 ping 检查模型的高级版本,你可以根据 API 响应来定义监控计划。
### 使用 GraphQL 进行健康检查
在一个典型的基于 REST 的微服务中,你需要从头开始构建健康检查功能。这是一个时间密集型的过程,但使用 GraphQL 就不用担心了。
根据它的[网站][7]
根据它的[网站][7]
> “GraphQL 是一种用于 API 的查询语言也是一种用现有数据完成这些查询的运行时。GraphQL 为你的 API 中的数据提供了一个完整的、可理解的描述,让客户有能力精确地仅查询他们所需要的东西,让 API 更容易随着时间的推移而进化,并实现强大的开发者工具。”
> “GraphQL 是一种用于 API 的查询语言,也是一种用现有数据完成这些查询的运行时环境。GraphQL 为你的 API 中的数据提供了一个完整的、可理解的描述,让客户有能力精确地仅查询他们所需要的东西,让 API 更容易随着时间的推移而进化,并实现强大的开发者工具。”
当你启动一个 GraphQL 微服务时,你还可以获得监控微服务的运行状况的预置。这是一个隐藏的宝贝。
当你启动一个 GraphQL 微服务时,你还可以获得监控微服务的运行状况的供给。这是一个隐藏的宝贝。
正如我上面提到的,你可以用 GraphQL 端点执行 API 测试以及 ping 检查。
Apollo GraphQL Server 提供了一个默认的端点,它可以返回有关你的微服务和服务器健康的信息。它不是很复杂:如果服务器正在运行,它就会返回状态码 200。
Apollo GraphQL 服务器提供了一个默认的端点,它可以返回有关你的微服务和服务器健康的信息。它不是很复杂:如果服务器正在运行,它就会返回状态码 200。
默认端点是 `<server-host>/.well-known/apollo/server-health`
@ -66,27 +63,26 @@ Apollo GraphQL Server 提供了一个默认的端点,它可以返回有关你
Apollo GraphQL 在定义服务器的同时,通过声明一个 `onHealthCheck` 函数来有效地管理这种情况。
```
* Defining the Apollo Server */
const apollo = new ApolloServer({
  playground: process.env.NODE_ENV !== 'production',
  typeDefs: gqlSchema,
  resolvers: resolver,
  onHealthCheck: () =&gt; {
    return new Promise((resolve, reject) =&gt; {
      // Replace the `true` in this conditional with more specific checks!
      if (true) {
        resolve();
      } else {
        reject();
      }
    });
  }
playground: process.env.NODE_ENV !== 'production',
typeDefs: gqlSchema,
resolvers: resolver,
onHealthCheck: () => {
return new Promise((resolve, reject) => {
// Replace the `true` in this conditional with more specific checks!
if (true) {
resolve();
} else {
reject();
}
});
}
});
```
当你定义一个 `onHealthCheck` 方法时,它返回一个 promise如果服务器准备好了它就会返回 _resolve_,如果有错误,它就会返回 _reject_
当你定义一个 `onHealthCheck` 方法时,它返回一个 promise如果服务器准备好了它就会返回 `resolve`,如果有错误,它就会返回 `reject`
GraphQL 让监控 API 变得更容易。此外,在你的服务器基础架构中使用它可以使代码变得可扩展。如果你想尝试采用 GraphQL 作为你的新基础设施定义,请参见我的 GitHub 仓库中的[示例代码和配置][9]。
@ -97,7 +93,7 @@ via: https://opensource.com/article/20/8/microservices-graphql
作者:[Rigin Oommen][a]
选题:[lujun9972][b]
译者:[geekpi](https://github.com/geekpi)
校对:[校对者ID](https://github.com/校对者ID)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出

View File

@ -0,0 +1,188 @@
[#]: collector: (lujun9972)
[#]: translator: (wxy)
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-12624-1.html)
[#]: subject: (Best Free Online Markdown Editors That Are Also Open Source)
[#]: via: (https://itsfoss.com/online-markdown-editors/)
[#]: author: (Ankush Das https://itsfoss.com/author/ankush/)
免费开源的在线 Markdown 编辑器
======
[Markdown][1] 是一种有用的轻量级[标记语言][2],很多人喜欢用它来编写文档或做网页发布。很多人都使用 Markdown 来写文章。
有[几个适用于 Linux 的 Markdown 编辑器][3],你可以安装并使用。
但是,如果你不想在你的系统上安装另一个程序怎么办?也许你暂时使用的系统无法安装一个应用程序?也许你只是想要一个能让你实时协作的 Markdown 编辑器?
无论你的需求是什么,在线 Markdown 编辑器通过提供协作功能、发布集成、笔记同步和一些在线功能,让很多事情变得简单。
因此,我整理了一份在线 Markdown 编辑器列表。
### 免费的在线 Markdown 编辑器
我尽量把重点放在代码开源的在线 Markdown 编辑器上。你可以使用它们的官方网站或将其部署到你的服务器上。
注:本列表没有特定排名顺序。
#### 1、StackEdit
![][4]
[StackEdit][5] 是目前最流行的开源在线 Markdown 编辑器之一。
它提供了一个很好的用户界面,并有一堆有用的功能。协作能力、同步能力,以及能够将你的文件发布/保存到 Blogger、WordPress、GitHub 和其他一些服务是 StackEdit 的一些关键功能。
不要忘了,你还可以使用一些 Markdown 扩展来支持 LaTeX 数学表达式、UML 图等。它的界面是一个所见即所得的编辑器,可以让你轻松使用 Markdown。它还可以离线工作如果你需要的话它还提供了一个 chrome 应用程序和扩展。
在 StackEdit 上导入/导出文件也很容易。如果你需要在你的服务器上托管它,你可以看看它在 [GitHub][6] 上的源代码,了解更多细节。
- [StackEdit][7]
#### 2、Dillinger
![][8]
Dillinger 也是一个有趣的开源在线 Markdown 编辑器。与 StackEdit 类似,你也可以与 Dropbox、GitHub、Medium、Google Drive、Bitbucket 和 OneDrive 链接并保存文件。
你也可以选择在需要时简单地导入/导出文件。Dillinger 的用户界面比你在 StackEdit 上看到的更简单,但它也可以工作。与 StackEdit 不同的是,你没有 LaTeX 表达式或图表的 Markdown 扩展支持,如果你只是需要一个简单的在线 Markdown 编辑器,这是一个不错的选择。
如果你需要,你可以选择将它部署在服务器上的 Docker 容器中。关于它的更多技术细节,你不妨看看它的 [GitHub 页面][9]。
- [Dillinger][10]
#### 3、Write.as
![][11]
Write.as 基于该团队开发的自由开源软件 [WriteFreely][12],所以如果你愿意的话,你可以简单地把它托管在自己的服务器上免费使用它。
你也可以使用 Write.as 服务作为一个具有基本功能的免费在线 Markdown 编辑器。为了使它发挥最大的作用,你可能想选购一份付费订阅。付费的功能包括自定义主题、新闻通讯、照片托管和多个博客等等。
它支持 Markdown可以让 [Mastodon][13]、[ActivityPub][14] 和 [Pleroma][15] 上的任何人轻松关注和分享你的博客文章。
你可以在它的 [GitHub 页面][16]上探索更多关于 WriteFreely 的信息,或者使用 Write.as 开始。
- [Write.as][17]
#### 4、Editor.md
![][18]
这是一个有趣的开源 Markdown 编辑器,还可以嵌入到自己的网页上。
它支持实时预览、GitHub 风格的 Markdown它有一个所见即所得的编辑器以及一堆有用的功能。除了基本的 Markdown 支持外它还支持表情符、LaTeX 表达式、流程图等。
你也可以选择自己托管,更多信息请看它的 [GitHub 页面][19]。
- [Editor.md][20]
#### 5、CodiMD
![][21]
CodiMD 从一开始就不是一个成熟的在线服务。但是,它是一个开源项目,通过托管在服务器上,你可以实时协作文档或笔记。
它基于 [HackMD][22] 的源代码,并提供了一个[演示实例][23]来提供测试。我个人很喜欢它还提供了一个黑暗模式,而且很容易使用。
对于它未来的发布版本(在写这篇文章的时候),它将改名为 “HedgeDoc”。
你可以在它的 [GitHub 页面][24]上找到所有关于通过 Docker/Kubernetes 在服务器上部署它的相关信息以及其他手动配置选项。
- [CodiMD][25]
#### 6、Wri.pe
![][26]
Wri.pe 是一款简单的开源在线 Markdown 编辑器,虽然已经不再维护,但它仍然活着而且可用。
它的特点是实时预览和可以导出或保存你的笔记到 Dropbox/Evernote。考虑到它没有积极维护你可能不会依赖它但当我测试它时它和预期一样可以工作。
你可以看看它的 [GitHub 页面][27]或官方网站来了解更多关于它的信息。
- [Wri.pe][28]
### 附带提名
下面是一些提供 Markdown 访问的工具。
#### Markdown Web Dingus
![][29]
这是由 Markdown 语言的创造者提供的一个简单而免费的在线 Markdown 编辑器。它并不是一个成熟的在线编辑器,也不支持导入/导出,
但是,如果你只是想要一个在线编辑器来预览你的 Markdown 代码,这可能是一个不错的选择。不仅仅局限于编辑器,你还可以在网站的侧边栏得到一个语法速查表。所以,你也可以在这里尝试和学习。
- [Markdown Web Dingus][30]
#### Markdown Journal
![][31]
[Markdown Journal][32] 是 [GitHub][33] 上的一个有趣的开源项目,但已经停止开发了。你可以通过它的在线编辑器使用 Markdown 语言创建日记,并直接保存在你的 Dropbox 账户上。当我试图创建日志时,我注意到发生了内部服务器错误,但你可以了解一下它。
#### Etherpad
![][34]
[Etherpad][35] 是另一个令人印象深刻的开源在线编辑器,但它并没有开箱即用的 Markdown 支持。你可能会注意到通过一些插件可以在你的服务器上启用 Markdown 编辑,但还不够完美。所以,你可能要注意一点。它有一个[公共实例][36]的列表,也可以尝试一下。
### 总结
考虑到很多在线编辑器、CMS 和记事本服务都支持 Markdown如果你想把它发布到网站上像 [WordPress][37] 这样的服务/应用也是一个不错的选择。
你更喜欢用哪个 Markdown 编辑器?我是否错过了你最喜欢的东西?请在下面的评论中告诉我。
--------------------------------------------------------------------------------
via: https://itsfoss.com/online-markdown-editors/
作者:[Ankush Das][a]
选题:[lujun9972][b]
译者:[wxy](https://github.com/wxy)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://itsfoss.com/author/ankush/
[b]: https://github.com/lujun9972
[1]: https://en.wikipedia.org/wiki/Markdown
[2]: https://en.wikipedia.org/wiki/Markup_language
[3]: https://itsfoss.com/best-markdown-editors-linux/
[4]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/08/stackedit-screenshot.png?resize=800%2C396&ssl=1
[5]: https://itsfoss.com/stackedit-markdown-editor/
[6]: https://github.com/benweet/stackedit
[7]: https://stackedit.io/
[8]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/08/dillinger-screenshot.jpg?resize=800%2C390&ssl=1
[9]: https://github.com/joemccann/dillinger
[10]: https://dillinger.io/
[11]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/08/write-as-screenshot.jpg?resize=800%2C505&ssl=1
[12]: https://writefreely.org/
[13]: https://itsfoss.com/mastodon-open-source-alternative-twitter/
[14]: https://en.wikipedia.org/wiki/ActivityPub
[15]: https://pleroma.social/
[16]: https://github.com/writeas/writefreely
[17]: https://write.as/
[18]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/08/editor-md-screenshot.jpg?resize=800%2C436&ssl=1
[19]: https://github.com/pandao/editor.md
[20]: http://editor.md.ipandao.com/en.html
[21]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/08/codiMD.png?resize=800%2C525&ssl=1
[22]: https://hackmd.io/
[23]: https://demo.codimd.org/
[24]: https://github.com/codimd/server
[25]: https://demo.codimd.org
[26]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/08/wri-pe-screenshot.jpg?resize=800%2C558&ssl=1
[27]: https://github.com/masuidrive/open-wripe
[28]: https://wri.pe/
[29]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/08/markdown-web-dingus.jpg?resize=800%2C616&ssl=1
[30]: https://daringfireball.net/projects/markdown/dingus
[31]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/08/markdown-journal.jpg?resize=800%2C656&ssl=1
[32]: https://markdownjournal.com/
[33]: https://github.com/maciakl/MarkdownJournal
[34]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/08/etherpad-public-instance.png?resize=800%2C556&ssl=1
[35]: https://etherpad.org/
[36]: https://github.com/ether/etherpad-lite/wiki/Sites-that-run-Etherpad-Lite
[37]: https://wordpress.com/

View File

@ -1,8 +1,8 @@
[#]: collector: (lujun9972)
[#]: translator: (wxy)
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-12589-1.html)
[#]: subject: (Linux Jargon Buster: What is a Display Server in Linux? What is it Used for?)
[#]: via: (https://itsfoss.com/display-server/)
[#]: author: (Dimitrios Savvopoulos https://itsfoss.com/author/dimitrios/)
@ -18,13 +18,13 @@ Linux 黑话解释:什么是显示服务器,用来做什么?
### 什么是显示服务器?
显示服务器是一个程序,它负责协调其客户端与操作系统的其他部分之间以及硬件和操作系统之间的输入和输出。基本上多亏了显示服务器你才能以图形化的方式使用你的计算机GUI。如果没有显示服务器你只能局限于命令行界面TTY
显示服务器是一个程序它负责协调其客户端与操作系统的其他部分之间以及硬件和操作系统之间的输入和输出。基本上多亏了显示服务器你才能以图形化的方式使用你的计算机GUI。如果没有显示服务器你只能局限于命令行界面TTY
显示服务器提供了一个图形环境的框架,使你可以使用鼠标和键盘与应用程序进行交互。
显示服务器通过[显示服务器协议][1](如 X11与客户端进行通信。显示服务器是图形用户界面 —— 特别是窗口系统 —— 中的一个关键组件。
不要把显示服务器和[桌面环境][2]混淆。桌面环境下面使用的是显示服务器。
不要把显示服务器和[桌面环境][2]混淆。桌面环境的下层使用的是显示服务器。
听起来很熟悉,但又不完全清楚?让我来解释一下。
@ -38,7 +38,7 @@ X11也称 X是已经存在多年的传统显示服务器。它是 Linux
![X 架构][4]
X11 通信协议,使用 [X.org 服务器][5]显示服务器。它接收来自[设备驱动程序][6]的输入事件,并将它们提供给它的一个客户端。
X11 通信协议,使用显示服务器 [X.org 服务器][5]。它接收来自[设备驱动程序][6]的输入事件,并将它们提供给它的一个客户端。
显示服务器也从客户端接收数据,它处理数据并进行合成,在 Linux 上,它将数据传递给三个内核组件之一:[DRM][7]、[gem][8] 或 [KMS 驱动][9]。
@ -48,13 +48,13 @@ X.Org 服务器是一个显示服务器,它依靠第二个程序:[合成窗
按照其网站的说法Wayland “旨在作为 X 的更简单的替代品,更容易开发和维护”。
而事实上 [Wayland][13] 就是现代显示服务器,它应该取代传统的 X 显示服务器。
而事实上 [Wayland][13] 就是现代显示服务器,它应该取代传统的 X 显示服务器。
它的采用还在进行中。Ubuntu 曾试图在 17.10 版本中改用 Wayland 作为默认的显示服务器,但这个实验遭到了负面反馈。
对它的采用还在普及中。Ubuntu 曾试图在 17.10 版本中改用 Wayland 作为默认的显示服务器,但这个尝试遭到了负面反馈。
很多 GUI 应用程序及其框架都依赖于 X 服务器。这些应用程序在 Wayland 上无法正常工作。
这迫使 Ubuntu 继续使用 X 作为默认显示服务器。它仍然提供了使用 Wayland 的选项,但不再是默认的了。
这迫使 Ubuntu 继续使用 X 作为默认显示服务器。它仍然提供了使用 Wayland 的选项,但不再是默认的了。
即使在今天,绝大多数的发行版都默认使用 X 显示服务器。
@ -76,7 +76,7 @@ Wayland 作为比较新的产品,相比 Xorg 来说,还不是很稳定。作
因此,很多程序在使用 Wayland 时可能无法运行。Ubuntu 默认切换到 Wayland 的实验证实了这一点。
#### 结束语
### 结束语
我希望你对 Linux 中的显示服务器概念有了更好的理解。我已经尽量不谈太多的技术细节,但我无法完全避免。
@ -89,7 +89,7 @@ via: https://itsfoss.com/display-server/
作者:[Dimitrios Savvopoulos][a]
选题:[lujun9972][b]
译者:[wxy](https://github.com/wxy)
校对:[校对者ID](https://github.com/校对者ID)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出

View File

@ -0,0 +1,59 @@
[#]: collector: (lujun9972)
[#]: translator: (silentdawn-zz)
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-12611-1.html)
[#]: subject: (Military looks to ultraviolet networks for secure battlefield communication)
[#]: via: (https://www.networkworld.com/article/3572372/military-looks-to-ultraviolet-networks-for-secure-battlefield-communication.html)
[#]: author: (Patrick Nelson https://www.networkworld.com/author/Patrick-Nelson/)
美国军方正探索战场保密通信用紫外网络
======
> 美国军方想以开放空间传输的紫外线为载体,为士兵开发新的更安全的通讯网络。
![](https://images.idgesg.net/images/article/2018/02/security_safety_guarding_mobile_laptop_endpoint_protection_thinkstock_906578404-100750806-large.jpg)
美国军方研究者之所以探索战场环境下的紫外光通信的应用,是因为这种技术可能实现敌对方无法侦测的通信。
研究者关注的一个方面是衰减效应,即信号强度随传播距离的增加而减弱的自然现象。他们想知道是否存在一个合适的距离范围,在该范围内,信号强度足够弱,以至于敌对方几乎无法侦测,但又足够强,使得友方可以侦测并建立通信。他们说他们观察到了这种情况,但关于他们相关工作的 [研究论文][1] 并没有讲这个距离范围究竟是多少。
一份军方出版物提到,“紫外通信具有独特的传输特性,不但可以实现非视距连接,而且让敌对方难以侦测。”
这个研究由美军作战能力发展司令部 [军队研究实验室][2] 主导,其重点是开发一个基础架构,为未来研究提供可量化环境,在该环境下,己方既可以使用紫外通信,也能够避免敌对方的侦测。研究过程中他们还有另外两个发现:
* 最差情况,即敌对方探测器与己方发射器在视线范围内,但友方接收器不在视线范围内,问题不像想象中严重。
* 转换紫外线发射器的发射方向不是降低敌对方探测到通信信号可能性的有效方式。
研究者计划分析下面四种场景,场景中涵盖了己方紫外发射器、友方接收器、敌对方探测器相对位置关系:
* 友方接收器、敌对方探测器都在发射器的视线范围内。
* 友方接收器在发射器视线范围内,但敌对方探测器不在视线范围内(最佳条件)。
* 敌对方探测器在发射器的视线范围内,但友方接收器不在视线范围内(最差条件)。
* 友方接收器、敌对方探测器均不在视线范围内。
假定敌对方试图通过时域上的光子计数来发现相干通信信号,进而判定正在进行通信。
科学家们承认这么一个事实,即越靠近发射器,信号越容易被侦测。所以紫外通信中发射器的有效使用依赖于对敌对方探测器位置的准确感知。
“我们提供了一个基础框架,使得对紫外通信系统实际可探测性与期望性能间差距的根本限制因素的研究得以进行。” 研究者之一Robert Drost 博士如是说。
“我们的研究确保了团队对紫外波段用于通信的潜力及有限性有了根本上的理解。我坚信这种理解将影响到未来军队网络通信能力的发展。”
--------------------------------------------------------------------------------
via: https://www.networkworld.com/article/3572372/military-looks-to-ultraviolet-networks-for-secure-battlefield-communication.html
作者:[Patrick Nelson][a]
选题:[lujun9972][b]
译者:[silentdawn-zz](https://github.com/silentdawn-zz)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://www.networkworld.com/author/Patrick-Nelson/
[b]: https://github.com/lujun9972
[1]: https://www.osapublishing.org/DirectPDFAccess/4516B0FD-2152-4663-9A9899BF00560B7C_433781/oe-28-16-23640.pdf?da=1&id=433781&seq=0&mobile=no
[2]: https://www.arl.army.mil
[3]: https://www.facebook.com/NetworkWorld/
[4]: https://www.linkedin.com/company/network-world

View File

@ -0,0 +1,110 @@
[#]: collector: (lujun9972)
[#]: translator: (geekpi)
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-12620-1.html)
[#]: subject: (Design a book cover with an open source alternative to InDesign)
[#]: via: (https://opensource.com/article/20/9/open-source-publishing-scribus)
[#]: author: (Jim Hall https://opensource.com/users/jim-hall)
用 InDesign 的开源替代方案 Scribus 设计书籍封面
======
> 使用开源的出版软件 Scribus 来制作你的下一本自出版书籍的封面。
![](https://img.linux.net.cn/data/attachment/album/202009/16/213714ppvfzm6idv9nnynp.jpg)
我最近写完了一本关于 [C 语言编程][2]的书,我通过 [Lulu.com][3] 自行出版。我已经用 Lulu 做了好几个图书项目它是一个很棒的平台。今年早些时候Lulu 做了一些改变让作者在创作图书封面时有了更大的控制权。以前你只需上传一对大尺寸图片作为书的封面和封底。现在Lulu 允许作者上传完全按照你的书的尺寸定制的 PDF。
你可以使用 [Scribus][4] 这个开源页面布局程序来创建封面。下面是我的做法。
### 下载一个模板
当你在 Lulu 上输入图书的信息时,最终会进入<ruby>设计<rt>Design</rt></ruby>栏。在该页面的<ruby>设计封面<rt>Design Your Cover</rt></ruby>部分,你会发现一个方便的<ruby>下载模板<rt>Download Template</rt></ruby>按钮,它为你的图书封面提供了一个 PDF 模板。
![Lulu Design your Cover page][5]
下载此模板,它为你提供了在 Scribus 中创建自己的书籍封面所需的信息。
![Lulu's cover template][7]
最重要的细节是:
* <ruby>文件总尺寸(含出血)<rt>Total Document Size (with bleed)</rt></ruby>
* <ruby>出血区(从裁切边缘)<rt>Bleed area (from trim edge)</rt></ruby>
* <ruby>书脊区<rt>Spine area</rt></ruby>
<ruby>出血<rt>Bleed</rt></ruby>是一个印刷术语,在准备“印刷就绪”文件时,这个术语很重要。它与普通文件中的页边距不同。打印文件时,你会为顶部、底部和侧面设置一个页边距。在大多数文档中,页边距通常为一英寸左右。
但在印刷就绪的文件中,文档的尺寸需要比成品书大一些,因为书籍的封面通常包括颜色或图片,一直到封面的边缘。为了创建这种设计,你要使颜色或图片超出你的边距,印刷厂就会把多余的部分裁切掉,使封面缩小到准确的尺寸。因此,“裁切”就是印刷厂将封面精确地裁剪成相应尺寸。而“出血区”就是印刷厂裁掉的多余部分。
如果你没有出血区,印刷厂就很难完全按照尺寸印刷封面。如果打印机只偏离了一点点,你的封面最终会在边缘留下一个微小的、白色的、没有印刷的边缘。使用出血和修剪意味着你的封面每次都能看起来正确。
### 在 Scribus 中设置书籍的封面文档
要在 Scribus 中创建新文档,请从定义文档尺寸的<ruby>新文档<rt>New Document</rt></ruby>对话框开始。单击<ruby>出血<rt>Bleeds</rt></ruby>选项卡,并输入 PDF 模板所说的出血尺寸。Lulu 图书通常在所有边缘使用 0.125 英寸的出血量。
对于 Scribus 中的文档总尺寸,你不能只使用 PDF 模板上的文档总尺寸。如果这样做,你的 Scribus 文档的尺寸会出现错误。相反,你需要做一些数学计算来获取正确的尺寸。
看下 PDF 模板中的<ruby>文件总尺寸(含出血)<rt>Total Document Size (with bleed)</rt></ruby>。这是将要发送给打印机的 PDF 的总尺寸,它包括封底、书脊和封面(包含出血)。要在 Scribus 中输入正确的尺寸,你必须从所有边缘中减去出血。例如,我最新的书的尺寸是<ruby>四开本<rt>Crown Quarto</rt></ruby>,装订后尺寸为 7.44" x 9.68",书脊宽度为 0.411"。加上 0.125" 的出血量,文件总尺寸(含出血)是 15.541" × 9.93"。因此,我在 Scribus 中的文档尺寸是:
* 宽15.541-(2 x 0.125)=15.291"
* 高9.93-(2 x 0.125)=9.68"
![Scribus document setup][8]
这将设置一个新的适合我的书的封面尺寸的 Scribus 文档。新的 Scribus 文档尺寸应与 PDF 模板上列出的“文件总尺寸(含出血)”完全匹配。
### 从书脊开始
在 Scribus 中创建新的书籍封面时,我喜欢从书脊区域开始。这可以帮助我验证我是否在 Scribus 中正确定义了文档。
使用<ruby>矩形<rt>Rectangle</rt></ruby>工具在文档上绘制一个彩色方框,书脊需要出现在那里。你不必完全按照正确的尺寸和位置来绘制,只要大小差不多并使用<ruby>属性<rt>Properties</rt></ruby>来设置正确的值即可。在形状的属性中,选择左上角基点,然后输入书脊需要放在的 x、y 位置和尺寸。同样,你需要做一些数学计算,并使用 PDF 模板上的尺寸作为参考。
![Empty Scribus document][9]
例如,我的书的修边尺寸是 7.44"×9.68",这是印刷厂修边后的封面和封底的尺寸。我的书的书脊大小是 0.411",出血量是 0.125"。也就是说,书脊的左上角 X、Y 的正确位置是:
* X 位置(出血量+裁剪宽度0.411+7.44=7.8510"
* Y 位置(减去出血量):-0.125"
矩形的尺寸是我的书封面的全高(包括出血)和 PDF 模板中标明的书脊宽度。
* 宽度0.411"
* 高度9.93"
将矩形的<ruby>填充<rt>Fill</rt></ruby>设置为你喜欢的颜色,将<ruby>笔触<rt>Stroke</rt></ruby>设置为<ruby><rt>None</rt></ruby>以隐藏边界。如果你正确地定义了 Scribus 文档,你应该最终得到一个矩形,它可以延伸到位于文档中心的图书封面的顶部和底部边缘。
![Book spine in Scribus][10]
如果矩形与文档不完全匹配,可能是你在创建 Scribus 文档时设置了错误的尺寸。由于你还没有在书的封面上花太多精力,所以可能最容易的做法是重新开始,而不是尝试修复你的错误。
### 剩下的就看你自己了
接下来,你可以创建你的书的封面的其余部分。始终使用 PDF 模板作为指导。封底在左边,封面在右边
我可以做一个简单的书籍封面,但我缺乏艺术能力,无法创造出真正醒目的设计。在自己设计了几个书的封面后,我对那些能设计出好封面的人产生了敬意。但如果你只是需要制作一个简单的封面,你可以通过开源软件自己动手。
--------------------------------------------------------------------------------
via: https://opensource.com/article/20/9/open-source-publishing-scribus
作者:[Jim Hall][a]
选题:[lujun9972][b]
译者:[geekpi](https://github.com/geekpi)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://opensource.com/users/jim-hall
[b]: https://github.com/lujun9972
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/books_read_list_stack_study.png?itok=GZxb9OAv (Stack of books for reading)
[2]: https://opensource.com/article/20/8/c-programming-cheat-sheet
[3]: https://www.lulu.com/
[4]: https://www.scribus.net/
[5]: https://opensource.com/sites/default/files/uploads/lulu-download-template.jpg (Lulu Design your Cover page)
[6]: https://creativecommons.org/licenses/by-sa/4.0/
[7]: https://opensource.com/sites/default/files/uploads/lulu-pdf-template.jpg (Lulu's cover template)
[8]: https://opensource.com/sites/default/files/uploads/scribus-new-document.jpg (Scribus document setup)
[9]: https://opensource.com/sites/default/files/uploads/scribus-empty-document.jpg (Empty Scribus document)
[10]: https://opensource.com/sites/default/files/uploads/scribus-spine-rectangle.jpg (Book spine in Scribus)

View File

@ -0,0 +1,134 @@
[#]: collector: (lujun9972)
[#]: translator: (geekpi)
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-12605-1.html)
[#]: subject: (Rclone Browser Enables You to Sync Data With Cloud Services in Linux Graphically)
[#]: via: (https://itsfoss.com/rclone-browser/)
[#]: author: (Ankush Das https://itsfoss.com/author/ankush/)
Rclone Browser 让你在 Linux 中以图形化的方式与云服务同步数据
======
> Rclone Browser 是一款高效的 GUI 程序,它可以让你轻松地使用 Rclone 管理和同步云存储上的数据。在这里,我们来看看它提供的功能和工作方式。
如果你想原生地在 Linux 上毫不费力地使用 One Drive 或 [Google Drive][1],你可以选择像 [Insync][2] 这样的高级 GUI 工具。
如果你能在终端上下功夫,你可以使用 [rclone][4] 与许多 [Linux 上的云存储服务][5]进行同步。我们有一份详细的[在 Linux 中使用 Rclone 与 OneDrive 同步的指南][6]。
[rclone][4] 是一个相当流行且有用的命令行工具。rclone 提供的功能是很多有经验的用户需要的。
然而,即使它足够有用,也不是每个人都能从终端使用它。
因此,在本文中,我将介绍一个令人印象深刻的 GUI “Rclone Browser”它可以让你轻松地使用 Rclone 管理和同步云存储上的数据。
值得注意的是rclone 确实提供了一个实验性的基于 Web 的 GUI。但我们将在这里专注于 [Rclone Browser][7]。
![][8]
### Rclone BrowserRclone 的开源 GUI
Rclone Browser 是一款可以让你浏览、修改、上传/下载、列出文件,并在想充分利用远程存储位置的情况下,做更多你想做的事情的 GUI。
它提供了一个简单的用户界面,并且工作良好(根据我的快速测试)。让我们详细看看它提供的功能以及如何开始使用它。
### Rclone Browser 的功能
![][9]
它提供了很多选项和控制来管理远程存储位置。根据你的使用情况,你可能会发现它的功能丰富或不知所措。以下是它的功能:
* 浏览和修改 rclone 远程存储位置
* 支持加密云存储
* 支持自定义位置和配置加密
* 不需要额外的配置。它将使用相同的 rclone 配置文件(如果你有的话)
* 在不同的标签页中同时导航多个位置
* 按层次列出文件(按文件名、大小和修改日期)
* rclone 命令的执行是异步的,不会使 GUI 冻结
* 你可以上传、下载、创建新文件夹、重命名、删除文件和文件夹
* 上传文件时支持拖放
* 在 VLC 等播放器中播放流媒体文件
* 挂载和卸载文件夹/云端驱动器
* 能够计算文件夹的大小、导出文件列表,并将 rclone 命令复制到剪贴板
* 支持便携模式
* 支持共享驱动器(如果你使用 Google Drive
* 针对支持共享链接的远程存储服务,支持获取共享链接
* 能够创建任务,你可以很容易地保存,以便以后再次运行或编辑。
* 黑暗模式
* 跨平台支持Windows、macOS 和 Linux
### 在 Linux 上安装 Rclone Browser
在使用 Rclone Browser 之前,你需要在你的 Linux 发行版上安装 rclone。请按照[官方安装说明][10]来安装。
你可以在 [GitHub 页面][7]的[发布页][11]找到 Rclone Browser 的 AppImage 文件。所以,你在任何 Linux 发行版上运行它都不会有问题。
如果你不知道 AppImage我会推荐你阅读我们的[在 Linux 上使用 AppImage][12] 指南。
你也可以选择构建它。操作说明在 GitHub 页面上。
- [下载 Rclone Browser][7]
### 开始使用 Rclone Browser
在这里,我只分享一下使用 Rclone Browser 应该知道的几件事。
![][13]
如果你在终端中使用 rclone 时有任何现有的远程位置,它将自动显示在 GUI 中。你也可以点击 “Refresh” 按钮来获取最新的新增内容。
如上图所示,当你点击 “Config” 按钮时它会启动终端让你轻松地添加一个新的远程或按你的要求配置它。当终端弹出的时候不用担心Rclone browser 会执行命令来完成所有必要的任务,你只需要在需要的时候设置或编辑一些东西。你不需要执行任何 rclone 命令。
如果你有一些现有的远程位置,你可以使用 “Open” 按钮打开它们,并在不同的标签页中访问云存储,如下所示。
![][14]
你可以轻松地挂载云驱动器,上传/下载文件,获取详细信息,共享文件夹的公共链接(如果支持),以及直接播放流媒体文件。
如果你想复制、移动或与远程存储位置同步数据,你可以简单地创建一个任务来完成。只需确保设置正确,你可以模拟执行或者直接运行任务。
你可以在 “Jobs” 页面找到所有正在运行的任务,如果需要,你可以取消/停止它们。
![][15]
除了上面提到的所有基本功能外,你可以前往 “File->Preferences” 更改 rclone 位置、挂载选项、下载文件夹、带宽设置以及代理。
![][16]
要了解更多关于它的用法和功能,你可能需要前往 [GitHub 页面][7]了解所有的技术信息。
### 总结
Rclone Browser 对于每一位想要使用 rclone 强大功能的 Linux 用户来说,绝对是得心应手。
你是否已经尝试过了呢?你更喜欢通过 GUI 还是终端来使用 rclone请在下面的评论中告诉我你的想法
--------------------------------------------------------------------------------
via: https://itsfoss.com/rclone-browser/
作者:[Ankush Das][a]
选题:[lujun9972][b]
译者:[geekpi](https://github.com/geekpi)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://itsfoss.com/author/ankush/
[b]: https://github.com/lujun9972
[1]: https://itsfoss.com/use-google-drive-linux/
[2]: https://itsfoss.com/recommends/insync/
[3]: https://itsfoss.com/affiliate-policy/
[4]: https://rclone.org/
[5]: https://itsfoss.com/cloud-services-linux/
[6]: https://itsfoss.com/use-onedrive-linux-rclone/
[7]: https://github.com/kapitainsky/RcloneBrowser
[8]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/09/Cloud-sync.gif?resize=800%2C450&ssl=1
[9]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/08/rclone-browser-screenshot.jpg?resize=800%2C618&ssl=1
[10]: https://rclone.org/install/
[11]: https://github.com/kapitainsky/RcloneBrowser/releases/tag/1.8.0
[12]: https://itsfoss.com/use-appimage-linux/
[13]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/09/rclone-browser-howto.png?resize=800%2C412&ssl=1
[14]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/09/rclone-browser-drive.png?resize=800%2C505&ssl=1
[15]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/09/rclone-browser-task.jpg?resize=800%2C493&ssl=1
[16]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/09/rclone-browser-preferences.jpg?resize=800%2C590&ssl=1

View File

@ -0,0 +1,102 @@
[#]: collector: (lujun9972)
[#]: translator: (geekpi)
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-12606-1.html)
[#]: subject: (Build a remote management console using Python and Jupyter Notebooks)
[#]: via: (https://opensource.com/article/20/9/remote-management-jupyter)
[#]: author: (Moshe Zadka https://opensource.com/users/moshez)
使用 Jupyter Notebooks 构建一个远程管理控制台
======
> 把 Jupyter 变成一个远程管理控制台。
![](https://img.linux.net.cn/data/attachment/album/202009/12/115114jct1g15e9ucsr6ua.jpg)
SSH 是一个强大的远程管理工具,但有些细节还不够好。编写一个成熟的远程管理控制台听起来好像是一件很费劲的事情。当然,开源社区中肯定有人已经写了一些东西吧?
是的,他们已经写出来了,它的名字是 [Jupyter][2]。你可能会认为 Jupyter 是那些数据科学家用来分析一周内的广告点击趋势之类的工具。这并没有错,它确实是的,而且它是一个很好的工具。但这仅仅刻画是它的表面。
### 关于 SSH 端口转发
有时,你可以通过 22 端口进入一台服务器。一般你也连接不到其他端口。也许你是通过另一个有更多访问权限的“堡垒机”,或者限制主机或端口的网络防火墙访问 SSH。当然限制访问的 IP 范围是有充分理由的。SSH 是远程管理的安全协议,但允许任何人连接到任何端口是相当不必要的。
这里有一个替代方案:运行一个简单的 SSH 端口转发命令,将本地端口转发到一个“远程”本地连接上。当你运行像 `-L 8111:127.0.0.1:8888` 这样的 SSH 端口转发命令时,你是在告诉 SSH 将你的*本地*端口 `8111` 转发到它认为的“远程”主机 `127.0.0.1:8888`。远程主机认为 `127.0.0.1` 就是它本身。
就像在《芝麻街》节目一样,“这里”是一个微妙的词。
地址 `127.0.0.1` 就是你告诉网络的“这里”。
### 实际动手学习
这可能听起来很混乱,但运行比解释它更简单。
```
$ ssh -L 8111:127.0.0.1:8888 moshez@172.17.0.3
Linux 6ad096502e48 5.4.0-40-generic #44-Ubuntu SMP Tue Jun 23 00:01:04 UTC 2020 x86_64
The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Wed Aug 5 22:03:25 2020 from 172.17.0.1
$ jupyter/bin/jupyter lab --ip=127.0.0.1
[I 22:04:29.771 LabApp] JupyterLab application directory is /home/moshez/jupyter/share/jupyter/lab
[I 22:04:29.773 LabApp] Serving notebooks from local directory: /home/moshez
[I 22:04:29.773 LabApp] Jupyter Notebook 6.1.1 is running at:
[I 22:04:29.773 LabApp] http://127.0.0.1:8888/?token=df91012a36dd26a10b4724d618b2e78cb99013b36bb6a0d1
<删节>
```
端口转发 `8111``127.0.0.1`,并在远程主机上启动 Jupyter它在 `127.0.0.1:8888` 上监听。
现在你要明白Jupyter 在撒谎。它认为你需要连接到 `8888` 端口,但你把它转发到 `8111` 端口。所以,当你把 URL 复制到浏览器后,但在点击回车之前,把端口从 `8888` 修改为 `8111`
![Jupyter remote management console][3]
这就是你的远程管理控制台。如你所见,底部有一个“终端”图标。点击它可以启动一个终端。
![Terminal in Jupyter remote console][5]
你可以运行一条命令。创建一个文件会在旁边的文件浏览器中显示出来。你可以点击该文件,在本地的编辑器中打开它。
![Opening a file][6]
你还可以下载、重命名或删除文件:
![File options in Jupyter remote console][7]
点击**上箭头**就可以上传文件了。那就上传上面的截图吧。
![Uploading a screenshot][8]
最后说个小功能Jupyter 可以让你直接通过双击远程图像查看。
哦,对了,如果你想用 Python 做系统自动化,还可以用 Jupyter 打开笔记本。
所以,下次你需要远程管理防火墙环境的时候,为什么不使用 Jupyter 呢?
--------------------------------------------------------------------------------
via: https://opensource.com/article/20/9/remote-management-jupyter
作者:[Moshe Zadka][a]
选题:[lujun9972][b]
译者:[geekpi](https://github.com/geekpi)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://opensource.com/users/moshez
[b]: https://github.com/lujun9972
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/computer_space_graphic_cosmic.png?itok=wu493YbB (Computer laptop in space)
[2]: https://jupyter.org/
[3]: https://opensource.com/sites/default/files/uploads/output_1_0.png (Jupyter remote management console)
[4]: https://creativecommons.org/licenses/by-sa/4.0/
[5]: https://opensource.com/sites/default/files/uploads/output_3_0.png (Terminal in Jupyter remote console)
[6]: https://opensource.com/sites/default/files/uploads/output_5_0.png (Opening a file)
[7]: https://opensource.com/sites/default/files/uploads/output_7_0.png (File options in Jupyter remote console)
[8]: https://opensource.com/sites/default/files/uploads/output_9_0.png (Uploading a screenshot)

View File

@ -0,0 +1,90 @@
[#]: collector: (lujun9972)
[#]: translator: (wxy)
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-12609-1.html)
[#]: subject: (Linux Jargon Buster: What is a Linux Distribution? Why is it Called a Distribution?)
[#]: via: (https://itsfoss.com/what-is-linux-distribution/)
[#]: author: (Abhishek Prakash https://itsfoss.com/author/abhishek/)
Linux 黑话解释:什么是 Linux 发行版?为什么它被称为“发行版”?
======
> 在这一章的 Linux 黑话解释中,我们来讨论一些基本的东西。
![][8]
让我们来讨论一下什么是 Linux 发行版,为什么它被称为<ruby>发行版<rt>distribution</rt></ruby>(或简称 distro以及它与 Linux 内核有什么不同。你还会了解到为什么有些人坚称 Linux 为 GNU/Linux。
### 什么是 Linux 发行版?
Linux 发行版是一个由 Linux 内核、[GNU 工具][1]、附加软件和软件包管理器组成的操作系统,它也可能包括[显示服务器][9]和[桌面环境][2],以用作常规的桌面操作系统。
这个术语之所以是 “Linux 发行版”,是因为像 Debian、Ubuntu 这样的机构“发行”了 Linux 内核以及所有必要的软件及实用程序(如网络管理器、软件包管理器、桌面环境等),使其可以作为一个操作系统使用。
你的发行版还负责提供更新来维护其内核和其他实用程序。
所以“Linux” 是内核,而 “Linux 发行版”是操作系统。这就是为什么它们有时也被称为基于 Linux 的操作系统的原因。
如果不是很理解以上所有的内容,不要担心。下面我将详细解释一下。
### “Linux 只是一个内核,不是一个操作系统。”这是什么意思?
你可能看到到过这句话,这说的没错。内核是一个操作系统的核心,它接近于具体硬件。你使用应用程序和 shell 与它交互。
![Linux 内核结构][3]
为了理解这一点,我就用我在《[什么是 Linux 的详细指南][4]》中曾用过的那个比喻。把操作系统看成车辆,把内核看成引擎。你不能直接驱动引擎。同样,你也不能直接使用内核。
![操作系统类比][5]
一个 Linux 发行版可以看作是一个汽车制造商(比如丰田或福特)为你提供的现成的汽车,就像 Ubuntu 或 Fedora 发行版的发行商为你提供的一个基于 Linux 的现成操作系统一样。
### 什么是 GNU/Linux
让我们再来看看这张图片。1991 年的时候,[Linus Torvalds][6] 创造的只是其中的最内圈,即 Linux 内核。
![Linux 内核结构][3]
要使用 Linux即使是以最原始的形式甚至没有 GUI你也需要一个 shell。最常见的是 Bash shell。
然后,你需要在 shell 中运行一些命令来完成一些工作。你能记起一些基本的 Linux 命令吗?比如 `cat`、`cp`、`mv`、`grep`、`find`、`diff`、`gzip` 等等。
严格来说这些所谓的“Linux 命令”并不是只属于 Linux。它们中的很多都来源于 UNIX 操作系统。
在 Linux 诞生之前Richard Stallman 就已经在 1983 年创建了<ruby>自由软件项目<rt>free software project</rt></ruby>中的第一个项目GNUGNU 是“GNU is Not Unix” 的递归缩写)。[GNU 项目][7]实现了许多流行的 Unix 实用程序,如 `cat`、`grep`、`awk`、shell`bash`同时还开发了自己的编译器GCC和编辑器Emacs
在 80 年代UNIX 是专有软件,而且超级昂贵。这就是为什么 Linus Torvalds 开发了一个类似 UNIX 的新内核的原因。为了与 Linux 内核进行交互Linus Torvalds 使用了 GNU 工具,这些工具在其 GPL 开源许可证下是免费的。
有了这些 GNU 工具,它的行为也像 UNIX 一样。这就是为什么 Linux 也被称为类 UNIX 操作系统的原因。
你无法想象没有 shell 和所有这些命令的 Linux。由于 Linux 与 GNU 工具集成得很深,几乎是完全依赖于 GNU 工具,所以纯粹主义者要求 GNU 应该得到应有的认可,这就是为什么他们坚称它为 GNU Linux写成 GNU/Linux
### 总结
那么该用哪个术语Linux、GNU/Linux、Linux 发行版,基于 Linux 的操作系统还是类 UNIX 操作系统?这取决于你的上下文。我已经为你提供了足够的细节,让你对这些相关的术语有更好的理解。
我希望你喜欢这个 Linux 黑话解释系列,并能学习到新的东西。欢迎你的反馈和建议。
--------------------------------------------------------------------------------
via: https://itsfoss.com/what-is-linux-distribution/
作者:[Abhishek Prakash][a]
选题:[lujun9972][b]
译者:[wxy](https://github.com/wxy)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://itsfoss.com/author/abhishek/
[b]: https://github.com/lujun9972
[1]: https://www.gnu.org/manual/blurbs.html
[2]: https://itsfoss.com/what-is-desktop-environment/
[3]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/03/Linux_Kernel_structure.png?resize=800%2C350&ssl=1
[4]: https://itsfoss.com/what-is-linux/
[5]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/03/operating_system_analogy.png?resize=800%2C350&ssl=1
[6]: https://itsfoss.com/linus-torvalds-facts/
[7]: https://www.gnu.org/gnu/thegnuproject.en.html
[8]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/09/what-is-linux-distribution.png?resize=800%2C450&ssl=1
[9]: https://linux.cn/article-12589-1.html

View File

@ -0,0 +1,217 @@
[#]: collector: (lujun9972)
[#]: translator: (wxy)
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-12667-1.html)
[#]: subject: (Program hardware from the Linux command line)
[#]: via: (https://opensource.com/article/20/9/hardware-command-line)
[#]: author: (Alan Smithee https://opensource.com/users/alansmithee)
使用 RT-Thread 的 FinSH 对硬件进行编程
======
> 由于物联网IoT的兴起对硬件进行编程变得越来越普遍。RT-Thread 可以让你可以用 FinSH 从 Linux 命令行与设备进行沟通、
![](https://img.linux.net.cn/data/attachment/album/202009/29/233059w523g55qzvo53h6i.jpg)
RT-Thread 是一个开源的[实时操作系统][2]用于对物联网IoT设备进行编程。FinSH 是 [RT-Thread][3] 的命令行组件,它提供了一套操作界面,使用户可以从命令行与设备进行沟通。它主要用于调试或查看系统信息。
通常情况下,开发调试使用硬件调试器和 `printf` 日志来显示。但在某些情况下,这两种方法并不是很有用,因为它是从运行的内容中抽象出来的,而且它们可能很难解析。不过 RT-Thread 是一个多线程系统,当你想知道一个正在运行的线程的状态,或者手动控制系统的当前状态时,这很有帮助。因为它是多线程的,所以你能够拥有一个交互式的 shell你可以直接在设备上输入命令、调用函数来获取你需要的信息或者控制程序的行为。如果你只习惯于 Linux 或 BSD 等现代操作系统,这在你看来可能很普通,但对于硬件黑客来说,这是极其奢侈的,远超将串行电缆直接连线到电路板上以获取一丝错误的做法。
FinSH 有两种模式。
* C 语言解释器模式,称为 c-style。
* 传统的命令行模式,称为 msh模块 shell
在 C 语言解释器模式下FinSH 可以解析执行大部分 C 语言的表达式,并使用函数调用访问系统上的函数和全局变量。它还可以从命令行创建变量。
在 msh 模式下FinSH 的操作与 Bash 等传统 shell 类似。
### GNU 命令标准
当我们在开发 FinSH 时,我们了解到,在编写命令行应用程序之前,你需要熟悉 GNU 命令行标准。这个标准实践的框架有助于给界面带入熟悉感,这有助于开发人员在使用时感到舒适和高效。
一个完整的 GNU 命令主要由四个部分组成。
1. 命令名(可执行文件):命令行程序的名称;
2. 子命令:命令程序的子函数名称。
3. 选项:子命令函数的配置选项。
4. 参数:子命令函数配置选项的相应参数。
你可以在任何命令中看到这一点。以 Git 为例:
```
git reset --hard HEAD~1
```
这一点可以分解为:
![GNU command line standards][4]
可执行的命令是 `git`,子命令是 `reset`,使用的选项是 `--head`,参数是 `HEAD~1`
再举个例子:
```
systemctl enable --now firewalld
```
可执行的命令是 `systemctl`,子命令是 `enable`,选项是 `--now`,参数是 `firewalld`
想象一下,你想用 RT-Thread 编写一个符合 GNU 标准的命令行程序。FinSH 拥有你所需要的一切,并且会按照预期运行你的代码。更棒的是,你可以依靠这种合规性,让你可以自信地移植你最喜欢的 Linux 程序。
### 编写一个优雅的命令行程序
下面是一个 RT-Thread 运行命令的例子RT-Thread 开发人员每天都在使用这个命令:
```
usage: env.py package [-h] [--force-update] [--update] [--list] [--wizard]
                      [--upgrade] [--printenv]
optional arguments:
  -h, --help      show this help message and exit
  --force-update  force update and clean packages, install or remove the
                  packages by your settings in menuconfig
  --update        update packages, install or remove the packages by your
                  settings in menuconfig
  --list          list target packages
  --wizard        create a new package with wizard
  --upgrade       upgrade local packages list and ENV scripts from git repo
  --printenv      print environmental variables to check
```
正如你所看到的那样,它看起来很熟悉,行为就像你可能已经在 Linux 或 BSD 上运行的大多数 POSIX 应用程序一样。当使用不正确或不充分的语法时,它会提供帮助,它支持长选项和短选项。这种通用的用户界面对于任何使用过 Unix 终端的人来说都是熟悉的。
### 选项种类
选项的种类很多,按长短可分为两大类。
1. 短选项:由一个连字符加一个字母组成,如 `pkgs -h` 中的 `-h` 选项。
2. 长选项:由两个连字符加上单词或字母组成,例如,`scons- --target-mdk5` 中的 `--target` 选项。
你可以把这些选项分为三类,由它们是否有参数来决定。
1. 没有参数:该选项后面不能有参数。
2. 参数必选:选项后面必须有参数。
3. 参数可选:选项后可以有参数,但不是必需的。
正如你对大多数 Linux 命令的期望FinSH 的选项解析非常灵活。它可以根据空格或等号作为定界符来区分一个选项和一个参数,或者仅仅通过提取选项本身并假设后面的内容是参数(换句话说,完全没有定界符)。
* `wavplay -v 50`
* `wavplay -v50`
* `wavplay --vol=50`
### 使用 optparse
如果你曾经写过命令行程序,你可能会知道,一般来说,你所选择的语言有一个叫做 optparse 的库或模块。它是提供给程序员的,所以作为命令的一部分输入的选项(比如 `-v``--verbose`)可以与命令的其他部分进行*解析*。这可以帮助你的代码从一个子命令或参数中获取一个选项。
当为 FinSH 编写一个命令时,`optparse` 包希望使用这种格式:
```
MSH_CMD_EXPORT_ALIAS(pkgs, pkgs, this is test cmd.);
```
你可以使用长形式或短形式,或者同时使用两种形式来实现选项。例如:
```
static struct optparse_long long_opts[] =
{
    {"help"        , 'h', OPTPARSE_NONE}, // Long command: help, corresponding to short command h, without arguments.
    {"force-update",  0 , OPTPARSE_NONE}, // Long comman: force-update, without arguments
    {"update"      ,  0 , OPTPARSE_NONE},
    {"list"        ,  0 , OPTPARSE_NONE},
    {"wizard"      ,  0 , OPTPARSE_NONE},
    {"upgrade"     ,  0 , OPTPARSE_NONE},
    {"printenv"    ,  0 , OPTPARSE_NONE},
    { NULL         ,  0 , OPTPARSE_NONE}
};
```
创建完选项后,写出每个选项及其参数的命令和说明:
```
static void usage(void)
{
    rt_kprintf("usage: env.py package [-h] [--force-update] [--update] [--list] [--wizard]\n");
    rt_kprintf("                      [--upgrade] [--printenv]\n\n");
    rt_kprintf("optional arguments:\n");
    rt_kprintf("  -h, --help      show this help message and exit\n");
    rt_kprintf("  --force-update  force update and clean packages, install or remove the\n");
    rt_kprintf("                  packages by your settings in menuconfig\n");
    rt_kprintf("  --update        update packages, install or remove the packages by your\n");
    rt_kprintf("                  settings in menuconfig\n");
    rt_kprintf("  --list          list target packages\n");
    rt_kprintf("  --wizard        create a new package with wizard\n");
    rt_kprintf("  --upgrade       upgrade local packages list and ENV scripts from git repo\n");
    rt_kprintf("  --printenv      print environmental variables to check\n");
}
```
下一步是解析。虽然你还没有实现它的功能,但解析后的代码框架是一样的:
```
int pkgs(int argc, char **argv)
{
int ch;
int option_index;
struct optparse options;
if(argc == 1)
{
usage();
return RT_EOK;
}
optparse_init(&options, argv);
while((ch = optparse_long(&options, long_opts, &option_index)) != -1)
{
ch = ch;
rt_kprintf("\n");
rt_kprintf("optopt = %c\n", options.optopt);
rt_kprintf("optarg = %s\n", options.optarg);
rt_kprintf("optind = %d\n", options.optind);
rt_kprintf("option_index = %d\n", option_index);
}
rt_kprintf("\n");
return RT_EOK;
}
```
这里是函数头文件:
```
#include "optparse.h"
#include "finsh.h"
```
然后,编译并下载到设备上。
![Output][6]
### 硬件黑客
对硬件进行编程似乎很吓人,但随着物联网的发展,它变得越来越普遍。并不是所有的东西都可以或者应该在树莓派上运行,但在 RT-ThreadFinSH 可以让你保持熟悉的 Linux 感觉。
如果你对在裸机上编码感到好奇,不妨试试 RT-Thread。
--------------------------------------------------------------------------------
via: https://opensource.com/article/20/9/hardware-command-line
作者:[Alan Smithee][a]
选题:[lujun9972][b]
译者:[wxy](https://github.com/wxy)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://opensource.com/users/alansmithee
[b]: https://github.com/lujun9972
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/command_line_prompt.png?itok=wbGiJ_yg (Command line prompt)
[2]: https://opensource.com/article/20/6/open-source-rtos
[3]: https://github.com/RT-Thread/rt-thread
[4]: https://opensource.com/sites/default/files/uploads/command-line-apps_2.png (GNU command line standards)
[5]: https://creativecommons.org/licenses/by-sa/4.0/
[6]: https://opensource.com/sites/default/files/uploads/command-line-apps_3.png (Output)

View File

@ -0,0 +1,199 @@
[#]: collector: (lujun9972)
[#]: translator: (geekpi)
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-12629-1.html)
[#]: subject: (How to Connect to WiFi from the Terminal in Ubuntu Linux)
[#]: via: (https://itsfoss.com/connect-wifi-terminal-ubuntu/)
[#]: author: (Abhishek Prakash https://itsfoss.com/author/abhishek/)
如何在 Linux 终端中连接 WiFi
======
> 在本教程中,你将学习如何在 Ubuntu 中从终端连接到无线网络。如果你在使用 Ubuntu 服务器时,无法访问常规的[桌面环境][1],这将对你非常有帮助。
我的家用电脑主要使用桌面 Linux。我也有多台 Linux 服务器用于托管网站以及开源软件,如 [Nextcloud][2]、[Discourse][3]、Ghost、Rocket Chat 等。
我可以使用 [Linode][4] 在云端几分钟内快速部署 Linux 服务器。但最近,我在我的树莓派上安装了 [Ubuntu 服务器][5]。这是我第一次在物理设备上安装服务器,我不得不做一些额外的事情来通过命令行将 Ubuntu 服务器连接到 WiFi。
在本教程中,我将展示在 Ubuntu Linux 中使用终端连接到 WiFi 的步骤。你应该:
* 不要害怕使用终端编辑文件。
* 知道 wifi 接入点名称 SSID 和密码。
### 在 Ubuntu 中从终端连接到 WiFi
![][6]
当你使用 Ubuntu 桌面时,连接到 WiFi 是很容易的,因为你有图形用户界面,可以很容易地做到这一点。但当你使用 Ubuntu 服务器时就不一样了,因为你只能使用命令行。
Ubuntu 使用 [Netplan][7] 工具来轻松配置网络。在 Netplan 中,你可以创建一个包含网络接口描述的 YAML 文件,然后在 `netplan` 命令行工具的帮助下,生成所有需要的配置。
让我们看看如何使用 Netplan 从终端连接到无线网络。
#### 步骤 1确定你的无线网络接口名称
有几种方法可以识别你的网络接口名称。你可以使用 `ip` 命令、过时的 `ipconfig` 命令或查看这个文件:
```
ls /sys/class/net
```
这应该会展示所有可用的网络接口以太网、WiFi 和环回)。无线网络接口名称以 `w` 开头,通常命名类似 `wlanX`、`wlpxyz`。
```
[email protected]:~$ ls /sys/class/net
eth0 lo wlan0
```
记下这个接口名。你将在下一步使用它。
#### 步骤 2编辑 Netplan 配置文件中的 wifi 接口详细信息
Netplan 配置文件在 `/etc/netplan` 目录下。如果你查看这个目录的内容,你应该看到类似 `01-network-manager-all.yml``50-cloud-init.yaml` 等文件。
如果是 Ubuntu 服务器,你应该有 `50-cloud-init.yaml` 文件。如果是桌面计算机,应该是 `01-network-manager-all.yml` 文件。
Linux 桌面计算机的 Network Manager 允许你选择一个无线网络。你可以在它的配置中硬编码写入 WiFi 接入点。这可以在自动掉线的情况下(比如挂起)时帮助到你。
不管是哪个文件,都可以打开编辑。我希望你对 Nano 编辑器有一点[熟悉][8],因为 Ubuntu 预装了它。
```
sudo nano /etc/netplan/50-cloud-init.yaml
```
YAML 文件对空格、缩进和对齐方式非常敏感。不要使用制表符,在看到缩进的地方使用 4 个空格(或 2 个,以 YAML 文件中已经使用的为准)代替。
基本上你需要添加以下几行引号中是接入点名称SSID 和密码(通常):
```
wifis:
wlan0:
dhcp4: true
optional: true
access-points:
"SSID_name":
password: "WiFi_password"
```
再说一次,保持我所展示的对齐方式,否则 YAML 文件不能被解析,它会抛出一个错误。
你的完整配置文件可能是这样的:
```
# This file is generated from information provided by the datasource. Changes
# to it will not persist across an instance reboot. To disable cloud-init's
# network configuration capabilities, write a file
# /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg with the following:
# network: {config: disabled}
network:
ethernets:
eth0:
dhcp4: true
optional: true
version: 2
wifis:
wlan0:
dhcp4: true
optional: true
access-points:
"SSID_name":
password: "WiFi_password"
```
我觉得很奇怪,尽管有消息说更改不会在实例重启后保留,但它仍然可以工作。
不管怎样,用这个命令生成配置:
```
sudo netplan generate
```
现在应用它:
```
sudo netplan apply
```
如果你幸运的话,你应该连上网络。尝试 `ping` 一个网站或运行 `apt` 更新命令。
然而,事情可能不会那么顺利,你可能会看到一些错误。如果是这种情况,请尝试一些额外的步骤。
#### 可能的故障排除
当你使用 `netplan apply` 命令时,你有可能在输出中看到类似这样的错误。
```
Failed to start netplan-wpa-wlan0.service: Unit netplan-wpa-wlan0.service not found.
Traceback (most recent call last):
File "/usr/sbin/netplan", line 23, in <module>
netplan.main()
File "/usr/share/netplan/netplan/cli/core.py", line 50, in main
self.run_command()
File "/usr/share/netplan/netplan/cli/utils.py", line 179, in run_command
self.func()
File "/usr/share/netplan/netplan/cli/commands/apply.py", line 46, in run
self.run_command()
File "/usr/share/netplan/netplan/cli/utils.py", line 179, in run_command
self.func()
File "/usr/share/netplan/netplan/cli/commands/apply.py", line 173, in command_apply
utils.systemctl_networkd('start', sync=sync, extra_services=netplan_wpa)
File "/usr/share/netplan/netplan/cli/utils.py", line 86, in systemctl_networkd
subprocess.check_call(command)
File "/usr/lib/python3.8/subprocess.py", line 364, in check_call
raise CalledProcessError(retcode, cmd)
subprocess.CalledProcessError: Command '['systemctl', 'start', '--no-block', 'systemd-networkd.service', 'netplan-wpa-wlan0.service']' returned non-zero exit status 5.
```
可能是 `wpa_supplicant` 服务没有运行。运行这个命令:
```
sudo systemctl start wpa_supplicant
```
再次运行 `netplan apply`。如果它能解决这个问题,那就太好了。否则,使用下面的命令[关闭 Ubuntu 系统][9]
```
shutdown now
```
重新启动 Ubuntu 系统,登录并再次生成和运行 `netplan apply`
```
sudo netplan generate
sudo netplan apply
```
现在可能会显示警告(而不是错误)。这是警告而不是错误。我检查了[正在运行的 systemd 服务][10],发现 `netplan-wpa-wlan0.service` 已经在运行了。可能是因为它已经在运行了,而且 `netplan apply` 更新了配置文件(即使没有任何改变),所以显示了警告。
```
Warning: The unit file, source configuration file or drop-ins of netplan-wpa-wlan0.service changed on disk. Run 'systemctl daemon-reload' to reload units.
```
这并不重要,你可以通过运行 `apt update` 来检查网络是否已经正常工作。
我希望你能够在本教程的帮助下,在 Ubuntu 中使用命令行连接到 WiFi。如果你仍然遇到困难请在评论区告诉我。
--------------------------------------------------------------------------------
via: https://itsfoss.com/connect-wifi-terminal-ubuntu/
作者:[Abhishek Prakash][a]
选题:[lujun9972][b]
译者:[geekpi](https://github.com/geekpi)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://itsfoss.com/author/abhishek/
[b]: https://github.com/lujun9972
[1]: https://itsfoss.com/what-is-desktop-environment/
[2]: https://itsfoss.com/nextcloud/
[3]: https://www.discourse.org/
[4]: https://itsfoss.com/recommends/linode/
[5]: https://itsfoss.com/install-ubuntu-server-raspberry-pi/
[6]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/09/connect-to-wifi-from-terminal-ubuntu.png?resize=800%2C450&ssl=1
[7]: https://netplan.io/
[8]: https://itsfoss.com/nano-editor-guide/
[9]: https://itsfoss.com/schedule-shutdown-ubuntu/
[10]: https://linuxhandbook.com/systemd-list-services/

View File

@ -0,0 +1,122 @@
[#]: collector: "lujun9972"
[#]: translator: "hom"
[#]: reviewer: "wxy"
[#]: publisher: "wxy"
[#]: url: "https://linux.cn/article-12632-1.html"
[#]: subject: "Manage your SSH connections with this open source tool"
[#]: via: "https://opensource.com/article/20/9/ssh-connection-manager"
[#]: author: "Kenneth Aaron https://opensource.com/users/flyingrhino"
使用开源工具 nccm 管理 SSH 连接
======
> 使用 nccm 让你的终端连接 SSH 会话更快、更稳、更轻松。
![](https://img.linux.net.cn/data/attachment/album/202009/19/233942j6ne6wllnlbnjd36.jpg)
OpenSSH 很常用,但没有一个知名的连接管理器,因此我开发了 ncurses SSH 连接管理器(`nccm`)来填补这个重要的空白。 `nccm` 是一个简单的 SSH 连接管理器,具有非常便于移植的终端界面(就如项目名称所示,使用 ncurses 编写)。最重要的是,它使用起来非常简单。有了 `nccm`,你可以花费最少的精力和最少的按键连接到你选择的 SSH 会话。
### 安装 nccm
最快的方式是从它的 [Git 仓库][2]克隆该项目:
```
$ git clone https://github.com/flyingrhinonz/nccm nccm.git
```
`nccm.git/nccm` 的文件夹中有两个文件:`nccm` 自身和 `nccm.yml` 配置文件。
首先将 `nccm` 脚本复制到系统目录 `/usr/local/bin/` 中并添加执行权限,也可以通过使用`install` 命令来完成操作:
```
$ sudo install -m755 nccm target-directory /usr/local/bin
```
文件 `nccm.yml` 可以拷贝到以下任意一个位置,默认从找到的第一个位置获取配置:
* `~/.config/nccm/nccm.yml`
* `~/.nccm.yml`
* `~/nccm.yml`
* `/etc/nccm.yml`
`nccm` 需要在 Python 3 的环境中运行,这在大部分的 Linux 环境是没问题的。大多数 Python 库的依赖包已经作为 Python 3 的一部分存在,但是,有一些 YAML 的依赖包和实用程序是你必须安装的。
如果你没有安装 `pip`,你可以使用包管理器来安装它。在安装的同时,也请安装 `yamllint` 应用程序来帮助你验证 `nccm.yml` 文件。
在 Debian 或类似系统使用 `apt` 命令:
```
$ sudo apt install python3-pip yamllint
```
在 Fedora 或者类似系统使用 `dnf` 命令:
```
$ sudo dnf install python3-pip yamllint
```
`PyYAML` 也是必须安装的,可以通过使用 `pip` 来安装:
```
$ pip3 install --user PyYAML
```
### 使用 nccm
开始之前,需要修改 `nccm.yml` 文件来添加 SSH 连接配置,可以参照示例文件格式化 YAML 文件。仿照示例文件在开头添加连接名称,配置项使用两个空格缩进。不要忘了冒号(`:`),这是 YAML 的语言的格式。
不要担心你的 SSH 会话信息以何顺序排列,因为 `nccm` 在程序内提供了排序的方式。
如果修改完成,可以使用 `yamllint` 来校验配置:
```
$ yamllint ~/.config/nccm/nccm.yml
```
如果没有错误信息返回,说明文件的内容格式是正确的,可以进行下面的步骤。
如果 `nccm` 可以[从你的路径][3]中找到并且可以执行,那么输入 `nccm` 就可以启动 TUI文本用户界面了。如果你看到 Python 3 抛出的异常,请检查依赖包是否正确安装,任何异常都应该提到缺少的依赖包。
只要你没有在 YAML 配置文件中更改 `ncm_config_control` 模式,那么你可以使用以下的键盘按键来控制:
* `Up`/`Down` 方向键 - 移动光标
* `Home`/`End` - 跳转到文件开始和结尾
* `PgUp`/`PgDn` - 以页为单位查看
* `Left`/`Right` 方向键 - 水平滚动
* `TAB` - 在文本框之间移动
* 回车 - 连接选中的 SSH 会话
* `Ctrl-h` - 显示帮助菜单
* `Ctrl-q`/`Ctrl-c` - 退出
* `F1`-`F5` 或 `!` `@` `#` `$` `%` - 按 1-5 列排序
使用 `F1``F5` 来按 1-5 列排序,如果你的设备占用了这些 `F1` - `F5` 键,你可以使用`!` `@` `#` `$` `%` 来替代。默认界面显示 4 列内容,但我们将用户名和服务器地址作为单独的列来排序,这样我们就有了 5 个排序方式。你也可以通过再次按下排序的按键来逆转排序。在选中的行上按回车可以建立会话。
![nccm screenshot terminal view][4]
`Filter` 文本框中输入过滤内容,会用输入的内容以“与”的关系来过滤输出内容。这是不区分大小写的,而条目间用空白分隔。在 `Conn` 部分也是如此,但在这里按回车键可以连接到那个特定的条目编号。
这个工具还有许多功能需要你去发掘,比如专注模式,这些部分留下等待你去探索,也可以查看项目主页或者内置的帮助文档查看更多细节内容。
项目的 YAML 配置文件的文档是完善的,所以你可以查阅修改使 `nccm` 使用起来更加顺手。`nccm` 项目是非常希望得到你的反馈的,所以你可以复刻该项目然后添加更多新功能,欢迎大家提出拉取请求。
### 使用 nccm 来放松连接 SSH 的压力
像我一样,我希望这个工具可以对你有用,感谢能够为开源工作增加自己的贡献,请接受 `nccm` 作为我对开源项目自由、高效工作所做的贡献。
--------------------------------------------------------------------------------
via: https://opensource.com/article/20/9/ssh-connection-manager
作者:[Kenneth Aaron][a]
选题:[lujun9972][b]
译者:[hom](https://github.com/hom)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://opensource.com/users/flyingrhino
[b]: https://github.com/lujun9972
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/linux-penguins.png?itok=yKOpaJM_ "Penguins"
[2]: https://github.com/flyingrhinonz/nccm
[3]: https://opensource.com/article/17/6/set-path-linux
[4]: https://opensource.com/sites/default/files/uploads/nccm_screenshot.png "nccm screenshot terminal view"

View File

@ -0,0 +1,131 @@
[#]: collector: (lujun9972)
[#]: translator: (geekpi)
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-12637-1.html)
[#]: subject: (Using the Linux stat command to create flexible file listings)
[#]: via: (https://www.networkworld.com/article/3573802/using-the-linux-stat-command-to-create-flexible-file-listings.html)
[#]: author: (Sandra Henry-Stocker https://www.networkworld.com/author/Sandra-Henry_Stocker/)
使用 Linux stat 命令创建灵活的文件列表
======
![](https://img.linux.net.cn/data/attachment/album/202009/21/223030wi3xfx2eprij13z2.jpg)
`stat` 命令提供了很多关于文件的详细信息。
它不仅提供了文件最近变化的日期/时间,还显示了最近访问文件的时间和权限变化。它可以同时告诉你文件的字节大小和块的数量。它可以显示文件使用的 inode 以及文件类型。它包括了文件所有者和相关用户组的名称和 UID/GID。它以 “rwx”被称为 “人类可读” 格式)和数字方式显示文件权限。在某些系统中,它甚至可能包括文件创建的日期和时间(称为“出生”)。
除了提供所有这些信息外,`stat` 命令还可以用来创建文件列表。这些列表非常灵活,你可以选择包含上述任何或全部信息。
要生成一个自定义列表,你只需要使用 `stat` 命令的 `-c`(或 `--format`)选项,并指定你想要包含的字段。例如,要创建一个以两种格式显示文件权限的列表,使用这个命令:
```
$ stat -c '%n %a %A' my*
my.banner 664 -rw-rw-r--
mydir 775 drwxrwxr-x
myfile 664 -rw-rw-r--
myjunk 777 lrwxrwxrwx
mykey 664 -rw-rw-r--
mylog 664 -rw-rw-r--
myscript 755 -rwxr-xr-x
mytext 664 -rw-rw-r--
mytext.bak 664 -rw-rw-r--
mytwin 50 -rw-r-----
mywords 664 -rw-rw-r--
```
如上例所示,`%n` 代表文件名,`%a` 代表八进制的权限,`%A` 代表 `rwx` 形式的权限。完整的列表如后面所示。
要为这个命令创建一个别名,输入这个命令,或在 `.bashrc` 文件中添加这个定义。
```
$ alias ls_perms="stat -c '%n %a %A'"
```
要创建一个非常接近 `ls -l` 提供的长列表,可以这样做:
```
$ stat -c '%A %h %U %G %s %y %n' my*
-rw-rw-r-- 1 shs shs 255 2020-04-01 16:20:00.899374215 -0400 my.banner
drwxrwxr-x 2 shs shs 4096 2020-09-07 12:50:20.224470760 -0400 mydir
-rw-rw-r-- 1 shs shs 6 2020-05-16 11:12:00.460355387 -0400 myfile
lrwxrwxrwx 1 shs shs 11 2020-05-28 18:49:21.666792608 -0400 myjunk
-rw-rw-r-- 1 shs shs 655 2020-01-14 15:56:08.540540488 -0500 mykey
-rw-rw-r-- 1 shs shs 8 2020-03-04 17:13:21.406874246 -0500 mylog
-rwxr-xr-x 1 shs shs 201 2020-09-07 12:50:41.316745867 -0400 myscript
-rw-rw-r-- 1 shs shs 40 2019-06-06 08:54:09.538663323 -0400 mytext
-rw-rw-r-- 1 shs shs 24 2019-06-06 08:48:59.652712578 -0400 mytext.bak
-rw-r----- 2 shs shs 228 2019-04-12 19:37:12.790284604 -0400 mytwin
-rw-rw-r-- 1 shs shs 1983 2020-08-10 14:39:57.164842370 -0400 mywords
```
不同之处包括: 1、不试图将字段排成可辨认的一列2、日期是 `yy-mm-dd` 格式3、时间字段更精确4、增加了时区-0400 是 EDT
如果你想根据最后一次访问的日期来列出文件(例如,用 `cat` 命令来显示),使用这样的命令:
```
$ stat -c '%n %x' my* | sort -k2
mytwin 2019-04-22 11:25:20.656828964 -0400
mykey 2020-08-20 16:10:34.479324431 -0400
mylog 2020-08-20 16:10:34.527325066 -0400
myfile 2020-08-20 16:10:57.815632794 -0400
mytext.bak 2020-08-20 16:10:57.935634379 -0400
mytext 2020-08-20 16:15:42.323391985 -0400
mywords 2020-08-20 16:15:43.479407259 -0400
myjunk 2020-09-07 10:04:26.543980300 -0400
myscript 2020-09-07 12:50:41.312745815 -0400
my.banner 2020-09-07 13:22:38.105826116 -0400
mydir 2020-09-07 14:53:10.171867194 -0400
```
`stat` 列出文件细节时,可用的选项包括:
* `%a` - 八进制的访问权限(注意 `#``0` 的 printf 标志)
* `%A` 人类可读的访问权限
* `%b` 分配的块数(见 `%B`
* `%B` `%b` 报告的每个块的字节数
* `%C` SELinux 安全上下文字符串
* `%d` 十进制的设备编号
* `%D` 十六进制的设备编号
* `%f` 十六进制的原始模式
* `%F` 文件类型
* `%g` 所有者的组 ID
* `%G` 所有者的组名
* `%h` 硬链接的数量
* `%i` inode 编号
* `%m` 挂载点
* `%n` 文件名
* `%N` 如果是符号链接,会解引用为指向的文件名
* `%o` 最佳 I/O 传输大小提示
* `%s` 以字节为单位的总大小
* `%t` 十六进制的主要设备类型,用于字符/块设备特殊文件
* `%T` 十六进制的次要设备类型,用于字符/块设备特殊文件
* `%u` 所有者的用户 ID
* `%U` 所有者的用户名
* `%w` 文件创建时间,以人类可读形式; 如果未知,则为 `-`
* `%W` 文件创建时间,以 UNIX 纪元以来的秒数形式;如果未知,则为 `0`
* `%x` 上次访问时间,以人类可读形式
* `%X` 上次访问时间,以 UNIX 纪元以来的秒数形式
* `%y` 上次数据修改时间,以人类可读形式
* `%Y` 上次数据修改时间,以 UNIX 纪元以来的秒数形式
* `%z` 上次状态改变的时间,以人类可读形式
* `%Z` 上次状态改变的时间,以 UNIX 纪元以来的秒数形式
这些字段的选择都列在手册页中,你可以选择任何一个,不过用你喜欢的选项创建一些别名应该可以省去很多麻烦。有些选项,如 SELinux 安全上下文字符串,除非在系统中有使用,它将不可用。文件创建时间只有在你的系统保留该信息的情况下才可用。
--------------------------------------------------------------------------------
via: https://www.networkworld.com/article/3573802/using-the-linux-stat-command-to-create-flexible-file-listings.html
作者:[Sandra Henry-Stocker][a]
选题:[lujun9972][b]
译者:[geekpi](https://github.com/geekpi)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://www.networkworld.com/author/Sandra-Henry_Stocker/
[b]: https://github.com/lujun9972
[2]: https://www.facebook.com/NetworkWorld/
[3]: https://www.linkedin.com/company/network-world

View File

@ -0,0 +1,79 @@
[#]: collector: (lujun9972)
[#]: translator: (geekpi)
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-12630-1.html)
[#]: subject: (The New YubiKey 5C NFC Security Key Lets You Use NFC to Easily Authenticate Your Secure Devices)
[#]: via: (https://itsfoss.com/yubikey-5c-nfc/)
[#]: author: (Ankush Das https://itsfoss.com/author/ankush/)
全新的 YubiKey 5C NFC 安全密钥让你可以使用 NFC 轻松认证你的安全设备
======
如果你格外谨慎,会使用最好的认证方法来保护你的在线帐户的安全,你可能知道 [Yubico][1]。他们制作的硬件认证安全密钥可以取代[双因素认证][2],并摆脱在线账户的密码认证系统。
基本上,你只需将安全密钥插在电脑上,或者使用智能手机上的 NFC 来解锁访问账户。这样一来,你的认证方式就会完全保持离线状态。
![](https://img.linux.net.cn/data/attachment/album/202009/18/174323ior6v6xp1y1or1ov.jpg)
当然,你可以随时使用 [Linux 中好用的密码管理器][4]。但如果你拥有一家公司,或为公司工作,或者只是对自己的隐私和安全格外谨慎,想增加一层额外的安全保护,这些硬件安全密钥可能值得一试。这些设备最近得到的进一步普及。
Yubico 的最新产品 [YubiKey 5C NFC][5] 可能令人印象深刻,因为它既可以作为 Type-C 的 USB 密钥使用,也可以作为 NFC 使用(只要用密钥碰触你的设备)。
下面,让我们来看看这款安全密钥的概况。
LCTT 译注:请注意本文中的购买连接是原文作者的受益链接,如果你对此担心,请阅读其[受益政策][6]。)
### Yubico 5C NFC概述
![][7]
YubiKey 5C NFC 是最新的产品,它同时使用 USB-C 和 NFC。因此你可以轻松地将它插入 Windows、macOS 和 Linux 电脑。除了电脑,你还可以将其与 Android 或 iOS 智能手机或平板电脑配合使用。
不仅仅局限于 USB-C 和 NFC 的支持(这是件好事),它也恰好是世界上第一个支持智能卡的多协议安全密钥。
对于普通消费者来说,硬件安全密钥并不那么常见,因为它的成本很高。但在疫情流行的过程中,随着远程办公的兴起,一个更安全的认证系统肯定会派上用场。
以下是 Yubico 在其新闻稿中提到的内容:
> Yubico 首席产品官 Guido Appenzeller 表示:“如今人们工作和上网的方式与几年前大不相同,尤其是在过去几个月内。用户不再仅仅被一种设备或服务所束缚,也不再希望受限于此。这就是为什么 YubiKey 5C NFC 是我们最受欢迎的安全密钥之一。它与大多数现代电脑和手机兼容,并可以在一系列传统和现代应用中良好运行。归根结底,我们的客户渴望的是无论如何都能“正常工作”的安全性。”
YubiKey 5C NFC 支持的协议有 FIDO2、WebAuthn、FIDO U2F、PIV智能卡、OATH-HOTP 和 OATH-TOTP (基于哈希和时间的一次性密码)、[OpenPGP][8]、YubiOTP 和挑战应答认证。
考虑到所有这些协议,你可以轻松地保护任何支持硬件认证的在线帐户,同时还可以访问身份访问管理 IAM 解决方案。因此,这对个人用户和企业来说都是一个很好的选择。
### 定价和渠道
YubiKey 5C NFC 的价格为 55 美元。你可以直接从他们的[在线商店][5]订购或者从你所在国家的任何授权经销商处购买。花费可能也会根据运输费用的不同而有所不同但对于那些想要为他们的在线账户提供最佳安全级别的用户而言55 美元似乎是个不错的价格。
值得注意的是,如果你订购两个以上的 YubiKeys你可以获得批量折扣。
- [订购 YubiKey 5C NFC][5]
### 总结
无论你是想保护你的云存储帐户还是其他在线帐户的安全如果你不介意花点钱来保护你的数据安全Yubico 的最新产品是值得一试的。
你是否使用过 YubiKey 或其他安全密钥,如 LibremKey 等?你对它的体验如何?你认为这些设备值得花钱吗?
--------------------------------------------------------------------------------
via: https://itsfoss.com/yubikey-5c-nfc/
作者:[Ankush Das][a]
选题:[lujun9972][b]
译者:[geekpi](https://github.com/geekpi)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://itsfoss.com/author/ankush/
[b]: https://github.com/lujun9972
[1]: https://itsfoss.com/recommends/yubikey/
[2]: https://ssd.eff.org/en/glossary/two-factor-authentication
[3]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/09/yubikey-5c-nfc-desktop.jpg?resize=800%2C671&ssl=1
[4]: https://itsfoss.com/password-managers-linux/
[5]: https://itsfoss.com/recommends/yubico-5c-nfc/
[6]: https://itsfoss.com/affiliate-policy/
[7]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/09/yubico-5c-nfc.jpg?resize=800%2C671&ssl=1
[8]: https://www.openpgp.org/

View File

@ -0,0 +1,135 @@
[#]: collector: (lujun9972)
[#]: translator: (geekpi)
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-12635-1.html)
[#]: subject: (Shutdown Taking Too Long? Heres How to Investigate and Fix Long Shutdown Time in Linux)
[#]: via: (https://itsfoss.com/long-shutdown-linux/)
[#]: author: (Abhishek Prakash https://itsfoss.com/author/abhishek/)
关机时间太长的调查和解决的方法
======
![](https://img.linux.net.cn/data/attachment/album/202009/20/233812o1kd114jzq11lq1l.jpg)
> 你的 Linux 系统关机时间太长么?以下是你可以采取的步骤,来找出导致延迟关机的原因并解决这个问题。
我希望你对 [sigterm 和 sigkill][1] 的概念有一点熟悉。
当你[关闭 Linux 系统][2]时它会发送终止信号sigterm并礼貌地要求正在运行的进程停止。有些进程不符合该行为它们会忽略终止信号并继续运行。
这可能会导致关机过程的延迟,因为你的系统会在一个预定义的时间段内等待运行的进程停止。在这个时间段之后,它会发送 `kill` 信号来强制停止所有剩余的运行进程并关闭系统。
事实上,在某些情况下,你会在黑屏上看到一个类似 “a stop job is running” 的信息。
如果你的系统关闭时间太长,你可以做以下工作:
* 检查哪个进程/服务耗时过长,以及你是否能删除或重新配置它,使其正常运行。
* 更改系统强制停止运行进程前的默认等待时间。(快速而不优雅的方式)
我的操作系统是使用 systemd 的 Ubuntu。这里的命令和步骤适用于任何使用 systemd 的 Linux 发行版(大多数发行版都是这样)。
![][3]
### 检查哪些进程会导致 Linux 的长时间关机
如果你想找出问题所在你应该检查上次关机时发生了什么。使用这个命令来获得“我知道你上个会话做了什么”I Know What You Did Last Summer 的双关语)的力量。
```
journalctl -rb -1
```
[journalctl 命令][4]能让你读取系统日志。使用选项 `-b -1` 可以过滤最后一次启动会话的日志。使用选项 `-r` 时,日志将按时间倒序显示。
换句话说,`journalctl -rb -1` 命令将显示最后一次关闭 Linux 系统之前的系统日志。这里就是你需要分析 Linux 系统长时间关机问题的地方。
#### 没有 journal 日志?下面是你应该做的。
如果没有 journal 日志,请确认你的发行版是否使用 systemd。
即使在一些使用 systemd 的 Linux 发行版上journal 日志也没有被默认激活。
请确认 `/var/log/journal` 是否存在。如果不存在,请创建它:
```
sudo mkdir /var/log/journal
```
你还应该检查 `/etc/systemd/journald.conf` 文件的内容,并确保 `Storage` 的值被设置为自动(`auto`)或持久(`persistent`)。
你是否在日志中发现可疑的东西?是否有一个进程/服务拒绝停止?如果是,调查一下是否可以在没有副作用的情况下删除它,或者是否可以重新配置它。请不要在这里盲目地去删除东西。你应该对这个进程有所了解。
### 通过减少默认停止超时来加快 Linux 中的关机速度(快速修复)
关机的默认等待时间通常设置为 90 秒。在这个时间之后,你的系统会尝试强制停止服务。
如果你想让你的 Linux 系统快速关闭,你可以改变这个等待时间。
你可以在位于 `/etc/systemd/system.conf` 的配置文件中找到所有的 systemd 设置。这个文件中应该有很多以 `#` 开头的行。它们代表了文件中各条目的默认值。
在开始之前,最好先复制一份原始文件。
```
sudo cp /etc/systemd/system.conf /etc/systemd/system.conf.orig
```
在这里寻找 `DefaultTimeoutStopSec`。它可能被设置为 90 秒。
```
#DefaultTimeoutStopSec=90s
```
你得把这个值改成更方便的,比如 5 秒或 10 秒。
```
DefaultTimeoutStopSec=5s
```
如果你不知道如何在终端中编辑配置文件,可以使用这个命令在系统默认的文本编辑器(如 Gedit中打开文件进行编辑
```
sudo xdg-open /etc/systemd/system.conf
```
![Change Shutdown Time Settings Ubuntu][5]
不要忘记**删除 DefaultTimeoutStopSec 前的 `#` 号**。保存文件并重启系统。
这将帮助你减少 Linux 系统的关机延迟。
#### 看门狗问题!
Linux 有一个名为看门狗的模块,用于监控某些服务是否在运行。它可以被配置为在系统因软件错误而挂起时自动重启系统。
在桌面系统上使用看门狗是不常见的,因为你可以手动关闭或重启系统。它经常被用于远程服务器上。
首先检查看门狗是否在运行:
```
ps -af | grep watch*
```
如果你的系统正在运行看门狗,你可以在 systemd 配置文件 `/etc/systemd/system.conf` 中将 `ShutdownWatchdogSec` 的值从 10 分钟改为更低的值。
### 你能解决关机时间过长的问题吗?
希望本教程能帮助你解决系统长时间关机的问题。如果你成功解决了这个问题,请在评论中告诉我。
--------------------------------------------------------------------------------
via: https://itsfoss.com/long-shutdown-linux/
作者:[Abhishek Prakash][a]
选题:[lujun9972][b]
译者:[geekpi](https://github.com/geekpi)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://itsfoss.com/author/abhishek/
[b]: https://github.com/lujun9972
[1]: https://linuxhandbook.com/sigterm-vs-sigkill/
[2]: https://itsfoss.com/schedule-shutdown-ubuntu/
[3]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/09/troubleshoot-long-shutdown-linux.gif?resize=800%2C450&ssl=1
[4]: https://linuxhandbook.com/journalctl-command/
[5]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/09/change-shutdown-time-settings-ubuntu.png?resize=797%2C322&ssl=1

View File

@ -0,0 +1,120 @@
[#]: collector: (lujun9972)
[#]: translator: (geekpi)
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-12656-1.html)
[#]: subject: (How Nextcloud simplified the signup process for decentralization)
[#]: via: (https://opensource.com/article/20/9/decentralization-signup)
[#]: author: (Jan C. Borchardt https://opensource.com/users/jancborchardt)
Nextcloud 如何简化去中心化的注册流程?
======
> Nextcloud 是开源软件,我们不提供托管服务,但我们却能从根本上简化注册体验。
![](https://img.linux.net.cn/data/attachment/album/202009/27/100351eqd88qub0b3ww0tu.jpg)
我们一直有个列表,上面有几十个 Nextcloud 提供商,然而我听到的最常见的问题,即使是我的技术方面的朋友,也是:
> ”嗨Jan你推荐哪个 Nextcloud 提供商?”
当然,这也是可以理解的。如果你有一长串的供应商,你怎么选择?托管商在附近?名字可爱?标志最大?
每一个使用服务器的去中心化开源解决方案都在努力解决这些:
* Mastodon 有 [joinmastodon.org][2] 来选择社区,但很明显主实例是 mastodon.social。
* Diaspora 有[joindiaspora.com][3],它也是主实例。
* Matrix 有 [matrix.to][4],还有一个在 [Element.io][5] 的应用(多平台)。
* WordPress 有 [wordpress.com][6]。我不确定是否有提供商能接近它的知名度。
* PeerTube 有一堆实例,都有不同的技术细节。
* Pixelfed 在[beta.joinpixelfed.org][7] 有一个早期版本的实例选择器,以及在 [pixelfed.social][8] 有一个大型实例。
* 还有更多的去中心化开源应用的例子,这里列出了如何通过终端访问它、设置 Rust 实现、或使其在网络打印机上运行。
这就导致了一些问题:
* 🔮 人们不知道该选哪个,有<ruby>错失恐惧症<rt>Fear Of Missing Out</rt></ruby>FOMO然后根本不选。这就是选择的悖论
* 🕸 网络并不是真正的去中心化,因为大多数人都在少数服务器上,或者主要是只有一台服务器。
Nextcloud 不存在这些问题。
### 我们的解决方案:简单注册
这是它是如何工作的:
当你下载我们的手机或桌面应用时,你首先看到的是“登录”或“使用供应商注册”的选择。这是任何专有应用都会做的事情:
![Android client][9]
选择“注册”可打开应用中的[简易注册页面][10]。
![Web client][11]
你输入你的电子邮件地址,然后点击“注册”。
输入密码,就可以了! 🎉
> ”等一下,这怎么这么简单?“
我知道,对吧?✨
事实上,它甚至比很多集中式的应用更简单,在那里你需要输入你的全名和电话号码,然后点击谷歌的验证码。
这基本上可以归结为:
### 我们为你选择
而不是面对一个无法判断什么适合你供应商的名单,我们只向你展示一个选择。就好像我是你的朋友一样,我回答了那个关于我推荐哪家供应商的问题。
很好!😊
澄清一下:你可以修改供应商,但默认的应该很适合你。目前,它只是地理位置上离你最近的提供商。
除此之外,我们对通过简单注册列出的提供商有一些要求,以确保无论你选择哪一个提供商都能获得良好的用户体验:
* 🎁 2 GB 的免费存储空间,而且不仅仅是试用期。
* 🍱 一套核心应用。文件、日历、联系人、邮件、通话、任务、笔记。有些供应商甚至提供更多。
* 🛡 最新版本,让你始终保持最新的功能、修复和安全更新。
除此之外,我们还提出了一个尊重隐私的流程。当你点击“注册”时,你的邮件不会发送给我们,而是直接发送给你选择的供应商,这将无缝过渡到他们的设置步骤,在那里你选择一个密码。这意味着在 Nextcloud 不会有任何数据泄露给我们,我们甚至不知道你选择的是哪家提供商!
因此,虽然我们提供这项服务,而且它超级容易使用,但我们只做绝对最低限度的数据处理,以连接你与你的理想供应商。
### 去中心化项目需要简单的注册方式
很多开源软件项目可以从简单注册这样的体验中受益。我们[在最初发布的时候写过有关它的文章][12],我们希望这篇文章能澄清使它成功的设计决策,以便它能被更多项目采用。
去中心化是赋能,但只有当人们即使不知道服务器是什么也能简单注册时,才是真正的革命。
当然,现在也还不完美。比如,如果你已经在 Nextcloud 实例上有了账户,任何一个应用的登录过程都会要求你输入一个服务器地址,而很多人根本不知道那是什么。比如在很多邮件应用中,在这一步会有一个最受欢迎的供应商列表,底部有一个“自定义服务器”的条目。这也可能是一种可能性,但同样带来了系统过于集中的风险,或者让人们对选择什么感到困惑。
所以,我们不断尝试为所有 Nextcloud 桌面和移动应用改进这一点,比如 Nextcloud Talk 或者所有优秀的社区开发的应用。在 Android 上,我们与 DAVx5Android 上的日历和联系人同步)紧密集成,而且,对于其他 Android 应用,还有一个[单点登录库][13]。不幸的是,在 iOS 上,就没有那么容易了,因为应用必须来自同一个开发者才能共享凭证。
如果你想合作解决类似这些有趣的挑战,[来加入我们的 Nextcloud 设计团队吧][14]
--------------------------------------------------------------------------------
via: https://opensource.com/article/20/9/decentralization-signup
作者:[Jan C. Borchardt][a]
选题:[lujun9972][b]
译者:[geekpi](https://github.com/geekpi)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://opensource.com/users/jancborchardt
[b]: https://github.com/lujun9972
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/rh_003601_05_mech_osyearbook2016_cloud_cc.png?itok=XSV7yR9e (clouds in the sky with blue pattern)
[2]: https://joinmastodon.org/
[3]: https://joindiaspora.com
[4]: https://matrix.to
[5]: http://Element.io
[6]: https://wordpress.com
[7]: http://beta.joinpixelfed.org
[8]: http://pixelfed.social
[9]: https://opensource.com/sites/default/files/nextcloud-android-small.png (Android client)
[10]: https://nextcloud.com/signup
[11]: https://opensource.com/sites/default/files/nextcloud-web-small.png (Web client)
[12]: https://nextcloud.com/blog/introducing-simple-signup-you-can-now-get-started-with-nextcloud-in-2-steps/
[13]: https://github.com/nextcloud/Android-SingleSignOn
[14]: https://nextcloud.com/design

View File

@ -0,0 +1,102 @@
[#]: collector: (lujun9972)
[#]: translator: (geekpi)
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-12653-1.html)
[#]: subject: (Incremental backups with Btrfs snapshots)
[#]: via: (https://fedoramagazine.org/btrfs-snapshots-backup-incremental/)
[#]: author: (Alessio https://fedoramagazine.org/author/alciregi/)
使用 Btrfs 快照进行增量备份
======
![](https://img.linux.net.cn/data/attachment/album/202009/26/112524cppfppjpvplyjzyx.jpg)
<ruby>快照<rt>snapshot</rt></ruby>是 Btrfs 的一个有趣的功能。快照是一个子卷的副本。生成快照是立即的。然而,生成快照与执行 `rsync``cp` 不同,快照并不是一创建就会占用空间。
> 编者注:来自 [BTRFS Wiki][2]:快照简单的来说就是一个子卷,它使用 Btrfs 的 COW 功能与其他子卷共享其数据(和元数据)。
占用的空间将随着原始子卷或快照本身(如果它是可写的)的数据变化而增加。子卷中已添加/修改的文件和已删除的文件仍然存在于快照中。这是一种方便的备份方式。
### 使用快照进行备份
快照驻留在子卷所在的同一磁盘上。你可以像浏览普通目录一样浏览它,并按照生成快照时的状态恢复文件的副本。顺便说一下,在快照子卷的同一磁盘上生成快照并不是一个理想的备份策略:如果硬盘坏了,快照也会丢失。快照的一个有趣的功能是可以将快照发送到另一个位置。快照可以被发送到外部硬盘或通过 SSH 发送到远程系统(目标文件系统也需要格式化为 Btrfs。要实现这个需要使用命令 `btrfs send``btrfs receive`
### 生成快照
要使用 `btrfs send``btrfs receive` 命令,重要的是要将快照创建为只读,而快照默认是可写的。
下面的命令将对 `/home` 子卷进行快照。请注意 `-r` 标志代表只读。
```
sudo btrfs subvolume snapshot -r /home /.snapshots/home-day1
```
快照的名称可以是当前日期,而不是 `day1`,比如 `home-$(date +%Y%m%d)`。快照看起来像普通的子目录。你可以把它们放在任何你喜欢的地方。目录 `/.snapshots` 可能是一个不错的选择,以保持它们的整洁和避免混淆。
> 编者注:快照不会对自己进行递归快照。如果你创建了一个子卷的快照,子卷所包含的每一个子卷或快照都会被映射到快照里面的一个同名的空目录。
### 使用 btrfs send 进行备份
在本例中U 盘中的目标 Btrfs 卷被挂载为 `/run/media/user/mydisk/bk`。发送快照到目标卷的命令是:
```
sudo btrfs send /.snapshots/home-day1 | sudo btrfs receive /run/media/user/mydisk/bk
```
这被称为初始启动,它相当于一个完整的备份。这个任务需要一些时间,取决于 `/home` 目录的大小。显然,后续的增量发送只需要更短的时间。
### 增量备份
快照的另一个有用的功能是能够以增量的方式执行发送任务。让我们再来生成一个快照。
```
sudo btrfs subvolume snapshot -r /home /.snapshots/home-day2
```
为了执行增量发送任务,需要指定上一个快照作为基础,并且这个快照必须存在于源文件和目标文件中。请注意 `-p` 选项。
```
sudo btrfs send -p /.snapshot/home-day1 /.snapshot/home-day2 | sudo btrfs receive /run/media/user/mydisk/bk
```
再来一次(一天之后):
```
sudo btrfs subvolume snapshot -r /home /.snapshots/home-day3
sudo btrfs send -p /.snapshot/home-day2 /.snapshot/home-day3 | sudo btrfs receive /run/media/user/mydisk/bk
```
### 清理
操作完成后,你可以保留快照。但如果你每天都执行这些操作,你可能最终会有很多快照。这可能会导致混乱,并可能会在你的磁盘上使用大量的空间。因此,如果你认为你不再需要一些快照,删除它们是一个很好的建议。
请记住,为了执行增量发送,你至少需要最后一个快照。这个快照必须存在于源文件和目标文件中。
```
sudo btrfs subvolume delete /.snapshot/home-day1
sudo btrfs subvolume delete /.snapshot/home-day2
sudo btrfs subvolume delete /run/media/user/mydisk/bk/home-day1
sudo btrfs subvolume delete /run/media/user/mydisk/bk/home-day2
```
注意:第 3 天的快照被保存在源文件和目标文件中。这样,明天(第 4 天),你就可以执行新的增量 `btrfs send`
最后的建议是,如果 U 盘的空间很大,可以考虑在目标盘中保留多个快照,而在源盘中只保留最后一个快照。
--------------------------------------------------------------------------------
via: https://fedoramagazine.org/btrfs-snapshots-backup-incremental/
作者:[Alessio][a]
选题:[lujun9972][b]
译者:[geekpi](https://github.com/geekpi)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://fedoramagazine.org/author/alciregi/
[b]: https://github.com/lujun9972
[1]: https://fedoramagazine.org/wp-content/uploads/2020/08/butterfs-816x346.png
[2]: https://btrfs.wiki.kernel.org/index.php/SysadminGuide#Snapshots

View File

@ -0,0 +1,100 @@
[#]: collector: (lujun9972)
[#]: translator: (wxy)
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-12618-1.html)
[#]: subject: (Linux Jargon Buster: What is a Long Term Support \(LTS\) Release? What is Ubuntu LTS?)
[#]: via: (https://itsfoss.com/long-term-support-lts/)
[#]: author: (Ankush Das https://itsfoss.com/author/ankush/)
Linux 黑话解释什么是长期支持LTS版本什么是 Ubuntu LTS
======
在 Linux 的世界里,特别是谈到 [Ubuntu][1] 的时候,你会遇到 LTS<ruby>长期支持<rt>Long Term Support</rt></ruby>)这个词。
如果你是一个经验丰富的 Linux 用户,你可能知道 Linux 发行版的各个方面,比如 LTS 版本。但是,新用户或不太懂技术的用户可能不知道。
在这一章 Linux 黑话解释中,你将了解什么是 Linux 发行版的 LTS 版本。
### 什么是长期支持LTS版本
长期支持LTS版本通常与应用程序或操作系统有关你会在较长的时间内获得安全、维护和有时有功能的更新。
LTS 版本被认为是最稳定的版本,它经历了广泛的测试,并且大多包含了多年积累的改进。
需要注意的是LTS 版本的软件不一定涉及功能更新,除非有一个更新的 LTS 版本。但是,你会在 LTS 版本的更新中得到必要的错误修复和安全修复。
LTS 版本被推荐给生产级的消费者、企业和商家,因为你可以获得多年的软件支持,而且软件更新不会破坏系统。
如果你注意到任何软件的非 LTS 版本,它通常是具有新功能和较短支持时间跨度(例如 6-9 个月)的前沿版本,而 LTS 版本的支持时间为 3-5 年。
![][2]
为了让大家更清楚的了解 LTS 和非 LTS 版本的区别,我们来看看选择 LTS 版本的一些优缺点。
#### LTS 版本的优点
* 软件更新与安全和维护修复的时间很长Ubuntu 有 5 年支持)
* 广泛的测试
* 软件更新不会带来破坏系统的变化
* 你有足够的时间为下一个 LTS 版本准备系统
#### LTS 版本的缺点
* 不提供最新和最强的功能
* 你可能会错过最新的硬件支持
* 你也可能会错过最新的应用程序升级
现在,你知道了什么是 LTS 版本及其优缺点,是时候了解一下 Ubuntu 的 LTS 版本了。Ubuntu 是最流行的 Linux 发行版之一,也是少数同时拥有 LTS 和非 LTS 版本的发行版之一。
这就是为什么我决定用一整个章节来介绍它。
### 什么是 Ubuntu LTS
自 2006 年以来Ubuntu 每六个月发布一个非 LTS 版本,每两年发布一个 LTS 版本,这一点一直如此。
最新的 LTS 版本是 [Ubuntu 20.04][3],它将被支持到 2025 年 4 月。换句话说Ubuntu 20.04 在那之前都会收到软件更新。非 LTS 版本只支持九个月。
你会发现 Ubuntu LTS 版本总是被标为 “LTS”。至少在 [Ubuntu 官方网站][4]上浏览最新的 Ubuntu 版本时是这样的。
为了让你更清楚,如果你见过 Ubuntu 16.04 LTS那就意味着**它早在 2016 年 4 月就已经发布,并且支持到 2021 年**(想想**5 年的软件更新**)。
同样,你也可以通过计算每个 Ubuntu LTS 版本发布日期接下来的**5 年**软件支持期来估计其更新支持情况。
### Ubuntu LTS 软件更新包括什么?
![][5]
Ubuntu LTS 版本在其发布的生命周期内都会收到安全和维护更新。除非该版本达到[生命末期EOL][6],否则你将获得所有必要的安全和错误修复。
在 LTS 版本中你不会注意到任何功能升级。所以,如果你想尝试最新的实验性技术,你可能需要将你的 Ubuntu 版本升级到一个非 LTS 版本。
我建议你参考我们最新的 [Ubuntu 升级指南][7]来了解更多关于升级 Ubuntu 的信息。
我也建议你阅读我们的文章[安装哪个 Ubuntu 版本][8],以消除你对不同 Ubuntu 版本的困惑,比如 [Xubuntu][9] 或 [Kubuntu][10],它们有什么不同。
我希望你现在对 LTS 这个术语有了更好的理解,尤其是在 Ubuntu LTS 方面。敬请关注未来更多的 Linux 黑话解释。
--------------------------------------------------------------------------------
via: https://itsfoss.com/long-term-support-lts/
作者:[Ankush Das][a]
选题:[lujun9972][b]
译者:[wxy](https://github.com/wxy)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://itsfoss.com/author/ankush/
[b]: https://github.com/lujun9972
[1]: https://ubuntu.com/
[2]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/09/display-server-linux.png?resize=800%2C450&ssl=1
[3]: https://itsfoss.com/download-ubuntu-20-04/
[4]: https://ubuntu.com
[5]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/09/ubuntu-lts-release.png?resize=800%2C397&ssl=1
[6]: https://itsfoss.com/end-of-life-ubuntu/
[7]: https://itsfoss.com/upgrade-ubuntu-version/
[8]: https://itsfoss.com/which-ubuntu-install/
[9]: https://xubuntu.org/
[10]: https://kubuntu.org/

View File

@ -0,0 +1,107 @@
[#]: collector: (lujun9972)
[#]: translator: (geekpi)
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-12642-1.html)
[#]: subject: (KeePassXC is An Amazing Community Driven Open Source Password Manager [Not Cloud Based])
[#]: via: (https://itsfoss.com/keepassxc/)
[#]: author: (Ankush Das https://itsfoss.com/author/ankush/)
KeePassXC社区驱动的开源密码管理器不基于云服务
======
![](https://img.linux.net.cn/data/attachment/album/202009/23/054245jxx9pyzk8p3kbxhw.jpg)
> KeePassXC 是一款有用的开源跨平台密码管理器,即使它不是云端工具,在功能上也毫不逊色。下面,我们就来快速了解一下它。
### KeePassXC一个跨平台的开源密码管理器
![][1]
KeePassXC 是 [KeePassX][2] 的社区复刻版本,旨在成为 [KeePass Password Safe][3](适用于 Windows的跨平台移植。它是完全免费使用和跨平台的Windows、Linux 和 macOS
事实上,它是目前 [Linux 最佳密码管理器][4]之一。它的功能选项既适合新手,也适合那些想要进一步控制以保护系统上的密码数据库的高级用户。
是的,与我[最喜欢的 Bitwarden 密码管理器][5]不同KeePassXC 不是基于云端的,密码永远不会离开系统。有些用户确实喜欢不把密码和秘密保存在云服务器中。
当你开始使用密码管理器时,你应该能在它上找到你所需要的所有基本功能。但是,在这里,为了让你初步了解,我会强调提到一些它提供的功能。
### KeePassXC 的功能
![][6]
值得注意的是,对于一个新手来说,这些功能可能会让人有点不知所措。但是,考虑到你想充分使用它,我想你应该真正了解它所提供的功能:
* 密码生成器
* 能够从 1Password、KeePass 1 和任何 CSV 文件导入密码。
* 通过导出和同步 SSL 证书支持,轻松共享数据库。
* 支持数据库加密 256 位 AES
* 浏览器集成(可选)
* 能够搜索你的凭证
* 在应用中自动输入密码
* 数据库报告,以检查密码的健康状况和其他统计数字
* 支持导出为 CSV 和 HTML
* 支持双因素认证令牌
* 支持将文件附加到密码中
* 支持 YubiKey
* 支持命令行
* 支持集成 SSH 代理
* 必要时改变加密算法
* 能够使用 DuckDuckGO 下载网站图标
* 数据库超时自动锁定
* 清除剪贴板和搜索查询的能力
* 自动保存文件
* 支持文件夹/嵌套文件夹
* 设置密码的有效期
* 提供黑暗主题
* 跨平台支持
正如你所看到的,它的确是一款功能丰富的密码管理器。所以,我建议你如果想使用提供的每一个功能,就好好探索它。
![][7]
### 在 Linux 上安装 KeePassXC
你应该能在你安装的发行版的软件中心找到它。
你也可以从官方网站上获得 AppImage 文件。如果你还不知道的话,我建议你去看看我们的[在 Linux 中使用 AppImage 文件][8]的指南。
另外,你还会发现有一个 snap 包可以用。除此之外,你还可以得到 Ubuntu PPA、Debian 包、Fedora 包和 Arch 包。
如果你好奇,你可以直接探索[官方下载页面][9]的可用包,并查看他们的 [GitHub 页面][10]的源代码。
- [下载 KeePassXC][11]
### 总结
如果你不是 [Bitwarden][5] 等云端开源密码管理器的粉丝KeePassXC 应该是你的绝佳选择。
在这里你得到的功能数量可以让你可以在多个平台上保证密码的安全和易于维护。即使没有开发团队的“官方”移动应用,你也可以尝试他们的一些[推荐应用][12],它们与其数据库兼容,并提供相同的功能。
你尝试过 KeePassXC 吗?你更喜欢使用什么作为你的密码管理器?请在下面的评论中告诉我你的想法。
--------------------------------------------------------------------------------
via: https://itsfoss.com/keepassxc/
作者:[Ankush Das][a]
选题:[lujun9972][b]
译者:[geekpi](https://github.com/geekpi)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://itsfoss.com/author/ankush/
[b]: https://github.com/lujun9972
[1]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/09/keepassxc-screenshot.jpg?resize=800%2C580&ssl=1
[2]: https://www.keepassx.org/
[3]: https://keepass.info
[4]: https://itsfoss.com/password-managers-linux/
[5]: https://itsfoss.com/bitwarden/
[6]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/09/keepassxc-screenshot-1.jpg?resize=800%2C579&ssl=1
[7]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/09/keepassxc-settings.png?resize=800%2C587&ssl=1
[8]: https://itsfoss.com/use-appimage-linux/
[9]: https://keepassxc.org/download/
[10]: https://github.com/keepassxreboot/keepassxc
[11]: https://keepassxc.org
[12]: https://keepassxc.org/docs/#faq-platform-mobile

View File

@ -0,0 +1,69 @@
[#]: collector: (lujun9972)
[#]: translator: (geekpi)
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-12659-1.html)
[#]: subject: (Huawei ban could complicate 5G deployment)
[#]: via: (https://www.networkworld.com/article/3575408/huawei-ban-could-complicate-5g-deployment.html)
[#]: author: (Jon Gold https://www.networkworld.com/author/Jon-Gold/)
对华为的禁令可能使 5G 部署复杂化
======
> 对华为、中兴的禁令意味着无线运营商建设 5G 服务的选择减少了。
![](https://images.idgesg.net/images/article/2019/02/5g_wireless_technology_network_connections_by_credit-vertigo3d_gettyimages-1043302218_3x2-100787550-large.jpg)
随着运营商竞相建设他们的 5G 网络,由于美国联邦政府的压力,在美国购买所需设备的选择比其他国家少,这可能会减缓部署。
在 2018 年的《国防授权法案》中,总部位于中国的华为和中兴通讯都被禁止向美国政府提供设备,此后不久又全面禁止进口。这极大地改变了竞争格局,并引发了美国 5G 的形态可能因此而改变的问题。
Gartner 的分析师 Michael Porowski 表示,虽然还不完全清楚,但运营商可以在哪里购买 5G 设备的限制有可能会减缓部署速度。
他说:”供应商数量仍然很多:爱立信、诺基亚、三星。中兴和华为都是更经济的选择。如果它们可用,你可能会看到更快的采用速度。”
451 Research 的研究总监 Christian Renaud 表示,业界普遍认为,华为设备既成熟又价格低廉,而在没有华为的情况下,运营商也没有明确的替代方案。
他说:“目前,会有采用诺基亚或爱立信标准的运营商。(而且)现在判断谁最成熟还为时过早,因为部署是如此有限。”
这种争论在运营商本身的覆盖地图上可以得到证实。虽然他们很快就大肆宣传 5G 服务在美国的许多市场上已经有了,但实际的地理覆盖范围大多局限于大城市核心区的公共场所。简而言之,大部分地区的 5G 部署还没有到来。
部署缓慢是有充分理由的。5G 接入点的部署密度要远高于上一代的无线技术,这使得该过程更加复杂且耗时。还有一个问题是,目前可用的 5G 用户设备数量还很少。
Renaud 说:“这就好比说,在有人发明汽车之前,说‘我已经有了这条八车道的高速公路’。”
设备供应商目前的部分目标是通过私有部署来展示 5G 的潜力,这些部署将该技术用做<ruby>信号隧道<rt>backhaul</rt></ruby>,用于支持[物联网][8]和其他针对单个企业的链接场景。
Renaud 说:“(设备供应商)都在大力推动私有部署这一块,然后他们可以利用这一点说:你看,我可以用在布鲁克林造船厂或某个私有部署的 5G 网络中,所以,如果可以的话……,它可以用于支持人们观看 YouTube。”
对中国的禁令的一个不幸结果可能是供应商为满足 5G 要求而遵循的规范的分裂。Renaud 称,如果非中国供应商必须为允许华为和中兴的市场制作一个版本,而为不允许华为和中兴的地方制作不同的版本,这可能会给他们带来新的麻烦。
他说:“这将把成本负担转移到设备制造商身上,来试图支持不同的运营商实施。我们会造成非技术性的壁垒。”而这些,反过来又会导致客户体验受到影响。
但是5G 已经通过[开放无线接入网技术][9]拥抱了更高的互操作性的趋势,它将 5G 栈各层之间的软件接口标准化。运营商和设备商都接受了这一推动,使得互操作性更有可能,这可能会在未来吸引更多的参与者。
当然,即便是普遍的互操作性,设备制造商仍然会试图建立客户依赖性。他说“在试图锁定客户的供应商和试图保持供应商中立的客户之间,总是会有一场拉锯战。这不会有很大的改变。(但是)我们显然已经看到了试图更加开放的动向。”
--------------------------------------------------------------------------------
via: https://www.networkworld.com/article/3575408/huawei-ban-could-complicate-5g-deployment.html
作者:[Jon Gold][a]
选题:[lujun9972][b]
译者:[geekpi](https://github.com/geekpi)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://www.networkworld.com/author/Jon-Gold/
[b]: https://github.com/lujun9972
[1]: https://www.networkworld.com/article/3203489/what-is-5g-fast-wireless-technology-for-enterprises-and-phones.html
[2]: https://www.networkworld.com/article/3568253/how-5g-frequency-affects-range-and-speed.html
[3]: https://www.networkworld.com/article/3568614/private-5g-can-solve-some-enterprise-problems-that-wi-fi-can-t.html
[4]: https://www.networkworld.com/article/3488799/private-5g-keeps-whirlpool-driverless-vehicles-rolling.html
[5]: https://www.networkworld.com/article/3570724/5g-can-make-for-cost-effective-private-backhaul.html
[6]: https://www.networkworld.com/article/3529291/cbrs-wireless-can-bring-private-5g-to-enterprises.html
[8]: https://www.networkworld.com/article/3207535/what-is-iot-the-internet-of-things-explained.html
[9]: https://www.networkworld.com/article/3574977/carriers-vendors-work-to-promote-5g-network-flexibility-with-open-standards.html
[10]: https://www.facebook.com/NetworkWorld/
[11]: https://www.linkedin.com/company/network-world

View File

@ -0,0 +1,322 @@
[#]: collector: (lujun9972)
[#]: translator: (wxy)
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-12646-1.html)
[#]: subject: (Teach Python with Jupyter Notebooks)
[#]: via: (https://opensource.com/article/20/9/teach-python-jupyter)
[#]: author: (Moshe Zadka https://opensource.com/users/moshez)
用 Jupyter Notebook 教 Python
======
> 有了 Jupyter、PyHamcrest用一点测试的代码把它们连在一起你就可以教任何适用于单元测试的 Python 内容。
![](https://img.linux.net.cn/data/attachment/album/202009/24/045721mubdfdx1tb11fibi.jpg)
关于 Ruby 社区的一些事情一直让我印象深刻,其中两个例子是对测试的承诺和对易于上手的强调。这两方面最好的例子是 [Ruby Koans][2],在这里你可以通过修复测试来学习 Ruby。
要是我们能把这些神奇的工具也用于 Python我们应该可以做得更好。是的使用 [Jupyter Notebook][3]、[PyHamcrest][4],再加上一点类似于胶带的粘合代码,我们可以做出一个包括教学、可工作的代码和需要修复的代码的教程。
首先,需要一些“胶布”。通常,你会使用一些漂亮的命令行测试器来做测试,比如 [pytest][5] 或 [virtue][6]。通常,你甚至不会直接运行它。你使用像 [tox][7] 或 [nox][8] 这样的工具来运行它。然而,对于 Jupyter 来说,你需要写一小段粘合代码,可以直接在其中运行测试。
幸运的是,这个代码又短又简单:
```
import unittest
def run_test(klass):
    suite = unittest.TestLoader().loadTestsFromTestCase(klass)
    unittest.TextTestRunner(verbosity=2).run(suite)
    return klass
```
现在,装备已经就绪,可以进行第一次练习了。
在教学中,从一个简单的练习开始,建立信心总是一个好主意。
那么,让我们来修复一个非常简单的测试:
```
@run_test
class TestNumbers(unittest.TestCase):
def test_equality(self):
expected_value = 3 # 只改这一行
self.assertEqual(1+1, expected_value)
```
```
test_equality (__main__.TestNumbers) ... FAIL
======================================================================
FAIL: test_equality (__main__.TestNumbers)
----------------------------------------------------------------------
Traceback (most recent call last):
File "<ipython-input-7-5ebe25bc00f3>", line 6, in test_equality
self.assertEqual(1+1, expected_value)
AssertionError: 2 != 3
----------------------------------------------------------------------
Ran 1 test in 0.002s
FAILED (failures=1)
```
“只改这一行” 对学生来说是一个有用的标记。它准确地表明了需要修改的内容。否则,学生可以通过将第一行改为 `return` 来修复测试。
在这种情况下,修复很容易:
```
@run_test
class TestNumbers(unittest.TestCase):
def test_equality(self):
expected_value = 2 # 修复后的代码行
self.assertEqual(1+1, expected_value)
```
```
test_equality (__main__.TestNumbers) ... ok
----------------------------------------------------------------------
Ran 1 test in 0.002s
OK
```
然而,很快,`unittest` 库的原生断言将被证明是不够的。在 `pytest` 中,通过重写 `assert` 中的字节码来解决这个问题,使其具有神奇的属性和各种启发式方法。但这在 Jupyter notebook 中就不容易实现了。是时候挖出一个好的断言库了PyHamcrest。
```
from hamcrest import *
@run_test
class TestList(unittest.TestCase):
def test_equality(self):
things = [1,
5, # 只改这一行
3]
assert_that(things, has_items(1, 2, 3))
```
```
test_equality (__main__.TestList) ... FAIL
======================================================================
FAIL: test_equality (__main__.TestList)
----------------------------------------------------------------------
Traceback (most recent call last):
File "<ipython-input-11-96c91225ee7d>", line 8, in test_equality
assert_that(things, has_items(1, 2, 3))
AssertionError:
Expected: (a sequence containing <1> and a sequence containing <2> and a sequence containing <3>)
but: a sequence containing <2> was <[1, 5, 3]>
----------------------------------------------------------------------
Ran 1 test in 0.004s
FAILED (failures=1)
```
PyHamcrest 不仅擅长灵活的断言,它还擅长清晰的错误信息。正因为如此,问题就显而易见了。`[1, 5, 3]` 不包含 `2`,而且看起来很丑:
```
@run_test
class TestList(unittest.TestCase):
def test_equality(self):
things = [1,
2, # 改完的行
3]
assert_that(things, has_items(1, 2, 3))
```
```
test_equality (__main__.TestList) ... ok
----------------------------------------------------------------------
Ran 1 test in 0.001s
OK
```
使用 Jupyter、PyHamcrest 和一点测试的粘合代码,你可以教授任何适用于单元测试的 Python 主题。
例如,下面可以帮助展示 Python 从字符串中去掉空白的不同方法之间的差异。
```
source_string = " hello world "
@run_test
class TestList(unittest.TestCase):
# 这是个赠品:它可以工作!
def test_complete_strip(self):
result = source_string.strip()
assert_that(result,
all_of(starts_with("hello"), ends_with("world")))
def test_start_strip(self):
result = source_string # 只改这一行
assert_that(result,
all_of(starts_with("hello"), ends_with("world ")))
def test_end_strip(self):
result = source_string # 只改这一行
assert_that(result,
all_of(starts_with(" hello"), ends_with("world")))
```
```
test_complete_strip (__main__.TestList) ... ok
test_end_strip (__main__.TestList) ... FAIL
test_start_strip (__main__.TestList) ... FAIL
======================================================================
FAIL: test_end_strip (__main__.TestList)
----------------------------------------------------------------------
Traceback (most recent call last):
File "<ipython-input-16-3db7465bd5bf>", line 19, in test_end_strip
assert_that(result,
AssertionError:
Expected: (a string starting with ' hello' and a string ending with 'world')
but: a string ending with 'world' was ' hello world '
======================================================================
FAIL: test_start_strip (__main__.TestList)
----------------------------------------------------------------------
Traceback (most recent call last):
File "<ipython-input-16-3db7465bd5bf>", line 14, in test_start_strip
assert_that(result,
AssertionError:
Expected: (a string starting with 'hello' and a string ending with 'world ')
but: a string starting with 'hello' was ' hello world '
----------------------------------------------------------------------
Ran 3 tests in 0.006s
FAILED (failures=2)
```
理想情况下,学生们会意识到 `.lstrip()``.rstrip()` 这两个方法可以满足他们的需要。但如果他们不这样做,而是试图到处使用 `.strip()` 的话:
```
source_string = " hello world "
@run_test
class TestList(unittest.TestCase):
# 这是个赠品:它可以工作!
def test_complete_strip(self):
result = source_string.strip()
assert_that(result,
all_of(starts_with("hello"), ends_with("world")))
def test_start_strip(self):
result = source_string.strip() # 改完的行
assert_that(result,
all_of(starts_with("hello"), ends_with("world ")))
def test_end_strip(self):
result = source_string.strip() # 改完的行
assert_that(result,
all_of(starts_with(" hello"), ends_with("world")))
```
```
test_complete_strip (__main__.TestList) ... ok
test_end_strip (__main__.TestList) ... FAIL
test_start_strip (__main__.TestList) ... FAIL
======================================================================
FAIL: test_end_strip (__main__.TestList)
----------------------------------------------------------------------
Traceback (most recent call last):
File "<ipython-input-17-6f9cfa1a997f>", line 19, in test_end_strip
assert_that(result,
AssertionError:
Expected: (a string starting with ' hello' and a string ending with 'world')
but: a string starting with ' hello' was 'hello world'
======================================================================
FAIL: test_start_strip (__main__.TestList)
----------------------------------------------------------------------
Traceback (most recent call last):
File "<ipython-input-17-6f9cfa1a997f>", line 14, in test_start_strip
assert_that(result,
AssertionError:
Expected: (a string starting with 'hello' and a string ending with 'world ')
but: a string ending with 'world ' was 'hello world'
----------------------------------------------------------------------
Ran 3 tests in 0.007s
FAILED (failures=2)
```
他们会得到一个不同的错误信息,显示去除了过多的空白:
```
source_string = " hello world "
@run_test
class TestList(unittest.TestCase):
# 这是个赠品:它可以工作!
def test_complete_strip(self):
result = source_string.strip()
assert_that(result,
all_of(starts_with("hello"), ends_with("world")))
def test_start_strip(self):
result = source_string.lstrip() # Fixed this line
assert_that(result,
all_of(starts_with("hello"), ends_with("world ")))
def test_end_strip(self):
result = source_string.rstrip() # Fixed this line
assert_that(result,
all_of(starts_with(" hello"), ends_with("world")))
```
```
test_complete_strip (__main__.TestList) ... ok
test_end_strip (__main__.TestList) ... ok
test_start_strip (__main__.TestList) ... ok
----------------------------------------------------------------------
Ran 3 tests in 0.005s
OK
```
在一个比较真实的教程中,会有更多的例子和更多的解释。这种使用 Jupyter Notebook 的技巧,有的例子可以用,有的例子需要修正,可以用于实时教学,可以用于视频课,甚至,可以用更多的其它零散用途,让学生自己完成一个教程。
现在就去分享你的知识吧!
--------------------------------------------------------------------------------
via: https://opensource.com/article/20/9/teach-python-jupyter
作者:[Moshe Zadka][a]
选题:[lujun9972][b]
译者:[wxy](https://github.com/wxy)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://opensource.com/users/moshez
[b]: https://github.com/lujun9972
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/read_book_guide_tutorial_teacher_student_apaper.png?itok=_GOufk6N (Person reading a book and digital copy)
[2]: https://github.com/edgecase/ruby_koans
[3]: https://jupyter.org/
[4]: https://github.com/hamcrest/PyHamcrest
[5]: https://docs.pytest.org/en/stable/
[6]: https://github.com/Julian/Virtue
[7]: https://tox.readthedocs.io/en/latest/
[8]: https://nox.thea.codes/en/stable/

View File

@ -0,0 +1,120 @@
[#]: collector: (lujun9972)
[#]: translator: (geekpi)
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-12663-1.html)
[#]: subject: (What's new with rdiff-backup?)
[#]: via: (https://opensource.com/article/20/9/rdiff-backup-linux)
[#]: author: (Patrik Dufresne https://opensource.com/users/patrik-dufresne)
11 年后重新打造的 rdiff-backup 2.0 有什么新功能?
======
> 这个老牌 Linux 备份方案迁移到了 Python 3 提供了添加许多新功能的机会。
![](https://img.linux.net.cn/data/attachment/album/202009/29/094858pb9pa3sppsq9x5z1.jpg)
2020 年 3 月,[rdiff-backup][2] 升级到了 2.0 版,这距离上一个主要版本已经过去了 11 年。2020 年初 Python 2 的废弃是这次更新的动力,但它为开发团队提供了整合其他功能和优势的机会。
大约二十年来,`rdiff-backup` 帮助 Linux 用户在本地或远程维护他们的数据的完整备份,而无需无谓地消耗资源。这是因为这个开源解决方案可以进行反向增量备份,只备份从上一次备份中改变的文件。
这次改版(或者说,重生)得益于一个新的、自组织的开发团队(由来自 [IKUS Software][3] 的 Eric Zolf 和 Patrik Dufresne以及来自 [Seravo][4] 的 Otto Kekäläinen 共同领导)的努力,为了所有 `rdiff-backup` 用户的利益,他们齐心协力。
### rdiff-backup 的新功能
在 Eric 的带领下,随着向 Python 3 的迁移,项目被迁移到了一个新的、不受企业限制的[仓库][5],以欢迎贡献。团队还整合了多年来提交的所有补丁,包括对稀疏文件的支持和对硬链接的修复。
#### 用 Travis CI 实现自动化
另一个巨大的改进是增加了一个使用开源 [Travis CI][6] 的持续集成/持续交付CI/CD管道。这允许在各种环境下测试 `rdiff-backup`从而确保变化不会影响方案的稳定性。CI/CD 管道包括集成所有主要平台的构建和二进制发布。
#### 使用 yum 和 apt 轻松安装
新的 `rdiff-backup` 解决方案可以运行在所有主流的 Linux 发行版上,包括 Fedora、Red Hat、Elementary、Debian 等。Frank 和 Otto 付出了艰辛的努力,提供了开放的仓库以方便访问和安装。你可以使用你的软件包管理器安装 `rdiff-backup`,或者按照 GitHub 项目页面上的[分步说明][7]进行安装。
#### 新的主页
团队将网站从 Savannah 迁移到了 GitHub Pages并对 [rdiff-backup.net][2] 官网进行了改版,加入了新的内容,让外观和感觉更加到位。
### 如何使用 rdiff-backup
如果你是 `rdiff-backup` 的新手,你可能会对它的易用性感到惊讶。备份方案应该让你对备份和恢复过程感到舒适,而不是吓人。
#### 开始备份
要开始备份到本地驱动器,例如通过 USB 连接的驱动器,输入 `rdiff-backup` 命令,然后输入要备份的驱动器和要存储文件的目标目录。
例如,要备份到名为 `my_backup_drive` 的本地驱动器,请输入:
```
$ rdiff-backup /home/tux/ /run/media/tux/my_backup_drive/
```
要将数据备份到异地存储,请使用远程服务器的位置,并在 `::` 后面指向备份驱动器的挂载点:
```
$ rdiff-backup /home/tux/ tux@example.com::/my_backup_drive/
```
你可能需要[设置 SSH 密钥][8]来使这个过程更轻松。
#### 还原文件
做备份的原因是有时文件会丢失。为了使恢复尽可能简单,你甚至不需要 `rdiff-backup` 来恢复文件(虽然使用 `rdiff-backup` 命令提供了一些方便)。
如果你需要从备份驱动器中获取一个文件,你可以使用 `cp` 将其从备份驱动器复制到本地系统,或者对于远程驱动器使用 `scp` 命令。
对于本地驱动器,使用:
```
$ cp _run_media/tux/my_backup_drive/Documents/example.txt ~/Documents
```
或者用于远程驱动器:
```
$ scp tux@example.com::/my_backup_drive/Documents/example.txt ~/Documents
```
然而,使用 `rdiff-backup` 命令提供了其他选项,包括 `--restore-as-of`。这允许你指定你要恢复的文件的哪个版本。
例如,假设你想恢复一个文件在四天前的版本:
```
$ rdiff-backup --restore-as-of 4D /run/media/tux/foo.txt ~/foo_4D.txt
```
你也可以用 `rdiff-backup` 来获取最新版本:
```
$ rdiff-backup --restore-as-of now /run/media/tux/foo.txt ~/foo_4D.txt`
```
就是这么简单。另外,`rdiff-backup` 还有很多其他选项,例如,你可以从列表中排除文件,从一个远程备份到另一个远程等等,这些你可以在[文档][9]中了解。
### 总结
我们的开发团队希望用户能够喜欢这个改版后的开源 `rdiff-backup` 方案,这是我们不断努力的结晶。我们也感谢我们的贡献者,他们真正展示了开源的力量。
--------------------------------------------------------------------------------
via: https://opensource.com/article/20/9/rdiff-backup-linux
作者:[Patrik Dufresne][a]
选题:[lujun9972][b]
译者:[geekpi](https://github.com/geekpi)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://opensource.com/users/patrik-dufresne
[b]: https://github.com/lujun9972
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/yearbook-haff-rx-linux-file-lead_0.png?itok=-i0NNfDC (Hand putting a Linux file folder into a drawer)
[2]: https://rdiff-backup.net/
[3]: https://www.ikus-soft.com/en/
[4]: https://seravo.fi/english
[5]: https://github.com/rdiff-backup/rdiff-backup
[6]: https://en.wikipedia.org/wiki/Travis_CI
[7]: https://github.com/rdiff-backup/rdiff-backup#installation
[8]: https://opensource.com/article/20/8/how-ssh
[9]: https://rdiff-backup.net/docs/examples.html

View File

@ -0,0 +1,99 @@
[#]: collector: (lujun9972)
[#]: translator: (geekpi)
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-12666-1.html)
[#]: subject: (How to Fix “Repository is not valid yet” Error in Ubuntu Linux)
[#]: via: (https://itsfoss.com/fix-repository-not-valid-yet-error-ubuntu/)
[#]: author: (Abhishek Prakash https://itsfoss.com/author/abhishek/)
如何修复 Ubuntu Linux 中的 “Release file is not valid yet” 错误
======
我最近[在我的树莓派上安装了 Ubuntu 服务器][1]。我[在 Ubuntu 终端连接上了 Wi-Fi][2],然后做了我在安装任何 Linux 系统后都会做的事情,那就是更新系统。
当我使用 `sudo apt update` 命令时,它给了一个对我而言特别的错误。它报出仓库的发布文件在某个时间段内无效。
> E: Release file for <http://ports.ubuntu.com/ubuntu-ports/dists/focal-security/InRelease> is not valid yet (invalid for another 159d 15h 20min 52s). Updates for this repository will not be applied.**
下面是完整输出:
```
ubuntu@ubuntu:~$ sudo apt update
Hit:1 http://ports.ubuntu.com/ubuntu-ports focal InRelease
Get:2 http://ports.ubuntu.com/ubuntu-ports focal-updates InRelease [111 kB]
Get:3 http://ports.ubuntu.com/ubuntu-ports focal-backports InRelease [98.3 kB]
Get:4 http://ports.ubuntu.com/ubuntu-ports focal-security InRelease [107 kB]
Reading package lists... Done
E: Release file for http://ports.ubuntu.com/ubuntu-ports/dists/focal/InRelease is not valid yet (invalid for another 21d 23h 17min 25s). Updates for this repository will not be applied.
E: Release file for http://ports.ubuntu.com/ubuntu-ports/dists/focal-updates/InRelease is not valid yet (invalid for another 159d 15h 21min 2s). Updates for this repository will not be applied.
E: Release file for http://ports.ubuntu.com/ubuntu-ports/dists/focal-backports/InRelease is not valid yet (invalid for another 159d 15h 21min 32s). Updates for this repository will not be applied.
E: Release file for http://ports.ubuntu.com/ubuntu-ports/dists/focal-security/InRelease is not valid yet (invalid for another 159d 15h 20min 52s). Updates for this repository will not be applied.
```
### 修复 Ubuntu 和其他 Linux 发行版中 “Release file is not valid yet” 的错误。
![][3]
错误的原因是系统上的时间和现实世界的时间不同。
你看,每个仓库文件都是在某个日期签名的,你可以通过查看发布文件信息了解:
```
sudo head /var/lib/apt/lists/ports.ubuntu.com_ubuntu_dists_focal_InRelease
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512
Origin: Ubuntu
Label: Ubuntu
Suite: focal
Version: 20.04
Codename: focal
Date: Thu, 23 Apr 2020 17:33:17 UTC
Architectures: amd64 arm64 armhf i386 ppc64el riscv64 s390x
```
现在,由于某些原因,我的 Ubuntu 服务器上的时间是过去时间,这也是为什么 Ubuntu 报出发布文件已经无效 X 天的原因。
如果你连接到了互联网,你可以**等待几分钟让系统同步时间**。
如果不行,你可以强制系统使用本地时间作为实时时钟(硬件时钟):
```
sudo timedatectl set-local-rtc 1
```
`timedatectl` 命令可以让你在 Linux 上配置时间、日期和[更改时区][4]。
你应该不需要重新启动。它可以立即工作,你可以通过[更新你的 Ubuntu 系统][5]再次验证它。
如果问题解决了,你可以将[实时时钟][6]设置为使用 UTCUbuntu 推荐的)。
```
sudo timedatectl set-local-rtc 0
```
**是否为你解决了这个问题?**
我希望这个提示能帮助你解决这个错误。如果你仍然遇到这个问题,请在评论栏告诉我,我会尽力帮助你。
--------------------------------------------------------------------------------
via: https://itsfoss.com/fix-repository-not-valid-yet-error-ubuntu/
作者:[Abhishek Prakash][a]
选题:[lujun9972][b]
译者:[geekpi](https://github.com/geekpi)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://itsfoss.com/author/abhishek/
[b]: https://github.com/lujun9972
[1]: https://itsfoss.com/install-ubuntu-server-raspberry-pi/
[2]: https://itsfoss.com/connect-wifi-terminal-ubuntu/
[3]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/09/Repository-not-valid-yet-error-ubuntu.png?resize=800%2C450&ssl=1
[4]: https://itsfoss.com/change-timezone-ubuntu/
[5]: https://itsfoss.com/update-ubuntu/
[6]: https://www.computerhope.com/jargon/r/rtc.htm

View File

@ -0,0 +1,108 @@
[#]: collector: (lujun9972)
[#]: translator: (wxy)
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-12639-1.html)
[#]: subject: (Linux Jargon Buster: What is a Rolling Release Distribution?)
[#]: via: (https://itsfoss.com/rolling-release/)
[#]: author: (Abhishek Prakash https://itsfoss.com/author/abhishek/)
Linux 黑话解释:什么是滚动发行版?
======
在了解了[什么是 Linux][1]、[什么是 Linux 发行版][2]之后,当你开始使用 Linux 时,你可能会在 Linux 论坛的讨论中遇到“<ruby>滚动发布<rt>rolling release</rt></ruby>”这个名词。
在这篇 Linux 黑话解释文章中,你将了解到 Linux 发行版的滚动发布模式。
### 什么是滚动发布?
在软件开发中,滚动发布是一种模式,在这种模式下,软件的更新是连续推出的,而不是分批的版本。这样软件就能始终保持更新。<ruby>滚动发行版<rt>rolling release distribution</rt></ruby>遵循同样的模式,它提供最新的 Linux 内核和软件版本,在它们一发布就提供。
[Arch Linux][3] 是滚动发行版中最流行的例子,然而 [Gentoo][4] 是最古老的滚动发行版,目前仍在开发中。
当你使用一个滚动发行版时,你会得到小而频繁的更新。这里没有像 Ubuntu 那样的重大 XYZ 版本发布。你会定期[更新 Arch][5]或其他滚动发行版,你将永远拥有最新版本的发行版。
滚动发布也是以测试为代价的。当最新的更新开始给你的系统带来问题时,你也许会受到“惊吓”。
### 对比滚动式发布与点版本式发布的发行版
![][6]
许多 Linux 发行版,如 Debian、Ubuntu、Linux Mint、Fedora 等都遵循<ruby>点版本<rt>point release</rt></ruby>模式。他们每隔几个月/年就会发布一个主要的 XYZ 版本。
点版本由 Linux 内核、桌面环境和其他软件的新版本组成。
当一个新的点版本发行版的主要版本发布时,你必须[专门来升级你的系统][7]。
相反,在滚动发行版中,当它从开发者那里发布时,你会不断地获得新的功能更新。这样,你不需要在几个月或几年后进行版本升级。你总是拥有最新的东西。
**哦,但我的 Ubuntu 也会定期更新,几乎每周一次。这是否意味着 Ubuntu 也在滚动发布?**
![][8]
Ubuntu 不是滚动发布。你看,你通常从 Ubuntu 得到的更新是安全和维护更新(除了一些软件,比如 Mozilla Firefox而不是新功能的发布。
例如GNOME 3.38 已经发布了,但 Ubuntu LTS 20.04 版不会给你 GNOME 3.38。它将坚持使用 3.36 版本。如果 GNOME 3.36 有安全或维护更新,你会在 Ubuntu 的更新中得到它。
LibreOffice 版本也是如此。Ubuntu 20.04 LTS 坚持使用 LibreOffice 6.x 系列,而 LibreOffice 7 已经发布了。请记住,我说的是官方软件库中的软件版本。你可以自由地从他们的官方网站上下载一个更新版本的 LibreOffice或者使用 PPA。但你不会从 Ubuntu 的软件库中得到它。
当 Ubuntu 发布下一个版本 Ubuntu 20.10 时,你会得到 LibreOffice 7 和 GNOME 3.38。
**为什么一些滚动发行版有“版本号”和发行版名称?**
![][9]
这是一个合理的问题。Arch Linux 是滚动发布的,它总是让你的系统保持更新,然而你会看到像 Arch Linux 2020.9.01 这样的版本号。
现在想象一下,你在 2018 年安装了 Arch Linux。你定期更新你的 Arch Linux 系统,所以你在 2020 年 9 月拥有所有最新的内核和软件。
但是,如果你决定在 2020 年 9 月在一个新系统上安装 Arch Linux 会发生什么?如果你使用 2018 年使用的相同的安装介质,你将不得不安装过去两年或更长时间内发布的所有系统更新。这很不方便,不是吗?
这就是为什么 Arch Linux和其他滚动发行版每个月或每隔几个月都会提供一个新的 ISO操作系统安装程序镜像文件其中包含所有最新的软件。**这就是所谓的 ISO 刷新**。这样一来,新用户就会得到一个更新的 Linux 发行版。
如果你已经在使用滚动发行版,你就不用担心新的 ISO 刷新了。你的系统已经和它对等了。ISO 刷新对那些要在新系统上安装它的人是有帮助的。
### 滚动式发布的利与弊
滚动发布模式的好处是,你可以得到小而频繁的更新。你总是可以从你的发行版的仓库中获得最新的内核和最新的软件版本。
然而,这也可能带来新软件不可预见的问题。点版本发行版通常会对系统中集成的基本组件进行测试,以避免带来令人不便的错误。而在滚动发行版中,情况就不一样了,在滚动发行版中,软件一经开发者发布就会被推出。
### 你应该使用滚动发行版还是点版本发行版?
![][10]
这取决于你。如果你是一个新的 Linux 用户,或者如果你不习惯于排除你的 Linux 系统的故障,请坚持使用你选择的点版本发行版。这也建议用于你的生产和关键任务的机器,在这里你会想要一个稳定的系统。
如果你想要最新的和最棒的 Linux 内核和软件,并且你不害怕花费一些时间在故障排除上(时常发生),你可以选择滚动发行版。
在这一点上,我还想提到 Manjaro Linux 的混合滚动发布模式。Manjaro 确实遵循滚动发布模式你不必将系统升级到较新的版本。不过Manjaro 也会对基本的软件组件进行测试,而不是盲目的向用户推出。这也是[为什么这么多人使用 Manjrao Linux][11] 的原因之一。
### 我讲清楚了吗?
希望你现在对“滚动发行版”这个词有了稍微的了解。如果你对它仍有一些疑问,请留言,我会尽力回答。我可能会更新文章以涵盖你的问题。祝你愉快 :)
--------------------------------------------------------------------------------
via: https://itsfoss.com/rolling-release/
作者:[Abhishek Prakash][a]
选题:[lujun9972][b]
译者:[wxy](https://github.com/wxy)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://itsfoss.com/author/abhishek/
[b]: https://github.com/lujun9972
[1]: https://itsfoss.com/what-is-linux/
[2]: https://linux.cn/article-12609-1.html
[3]: https://www.archlinux.org/
[4]: https://www.gentoo.org/
[5]: https://itsfoss.com/update-arch-linux/
[6]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/09/what-is-rolling-release-distribution.png?resize=800%2C450&ssl=1
[7]: https://itsfoss.com/upgrade-ubuntu-version/
[8]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/04/updates-available-ubuntu.png?resize=800%2C433&ssl=1
[9]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/09/arch-linux-iso-refresh.png?resize=799%2C388&ssl=1
[10]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/09/rolling-vs-point-release-distribution.png?resize=800%2C350&ssl=1
[11]: https://itsfoss.com/why-use-manjaro-linux/

View File

@ -0,0 +1,138 @@
[#]: collector: (lujun9972)
[#]: translator: (geekpi)
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-12654-1.html)
[#]: subject: (Teach Python with the Mu editor)
[#]: via: (https://opensource.com/article/20/9/teach-python-mu)
[#]: author: (Don Watkins https://opensource.com/users/don-watkins)
使用 Mu 编辑器教授 Python
======
> Mu 让你轻松学会如何编写 Python 代码。
![](https://img.linux.net.cn/data/attachment/album/202009/26/115018dkf3lvfyekifliec.jpg)
在学校里,教孩子们编程是非常流行的。很多年前,在 Apple II 和 [Logo][2] 编程的年代,我学会了创建<ruby>乌龟<rt>turtle</rt></ruby>绘图。我很喜欢学习如何对虚拟乌龟进行编程,后来也帮助学生进行编程。
大约五年前,我了解了 [Python 的 turtle 模块][3],这是我 Python 之旅的转折点。很快,我开始使用 `turtle` 模块来教学生 Python 编程基础,包括使用它来创建有趣的图形。
### 开始使用 Python 的 turtle 模块
在 Linux 或 macOS 电脑上,你只需打开一个终端,输入 `python`,你就会看到 Python shell。
如果你使用的是 Windows 电脑,则需要先安装 Python到 Python 网站上[下载][4]最新的稳定版。
接下来,用 `import turtle ``import turtle as t``turtle` 模块导入 Python 中。然后你就可以开始享受创建乌龟绘图的乐趣了。
### 认识一下 Mu
在我的 Python 冒险的早期,我使用了 [IDLE][5],它是 Python 的集成开发环境。它比在 Python shell 中输入命令要容易得多,而且我可以编写和保存程序供以后使用。我参加了一些在线课程,阅读了许多关于 Python 编程的优秀书籍。我教老师和学生如何使用 IDLE 创建乌龟绘图。
IDLE 是一个很大的改进,但在克利夫兰的 PyConUS 2019 上,我看到了 [Nicholas Tollervey][6]的演讲,这改变了我学习和教授 Python 的方式。Nick 是一位教育家,他创建了 [Mu][7],一个专门为年轻程序员(甚至像我这样的老程序员)设计的 Python 编辑器。Mu 可以安装在 Linux、macOS 和 Windows 上。它很容易使用,并且附带了优秀的[文档][8]和[教程][9]。
在 Linux 上,你可以通过命令行安装 Mu。
在 Ubuntu 或 Debian 上:
```
$ sudo apt install mu-editor
```
在 Fedora 或类似的地方:
```
$ sudo dnf install mu
```
或者,你可以使用 Python 来进行安装。首先,确保你已经安装了 Python 3
```
$ python --version
```
如果失败了,就试试:
```
$ python3 --version
```
假设你有 Python 3 或更高版本,使用 Python 包管理器 `pip` 安装 Mu。
```
$ python -m pip install mu-editor --user
```
然后你可以从命令行运行 Mu或者创建一个快捷方式
```
$ python -m pip install shortcut mu-editor --user
```
[树莓派][10]上默认安装了 Mu这是一个很大的优点。在过去的几年里我已经向学生介绍了使用树莓派和 Mu 编辑器的 Python 编程。
### 如何用 Mu 教授 Python
Mu 是向学生展示 Python 入门的好方法。下面是我如何教学生开始使用它。
1. 打开 Mu 编辑器。
![Mu editor][11]
2. 输入 `import turtle` 导入 `turtle` 模块,就可以让乌龟动起来了。我的第一课是用 Python 代码画一个简单的正方形。
![Mu editor][13]
3. 保存这个程序,确保文件名以 .py 结尾。
![Saving program in Mu][14]
4. 运行程序。哪怕是运行这样一个简单的程序都会让人兴奋,看到你写的程序的图形输出是很有趣的。
![Running Python program in Mu][15]
### 超越基础知识
在上完这节简单的课后,我讲解了有一些方法可以简化和扩展学生所学的基础知识。一是创建一个更简单的 `turtle` 对象,`import turtle as t`。然后我介绍了一个 `for` 循环,用另外一种 `turtle` 方法画一个正方形。
![for loops in Python with Mu][16]
接下来,我将展示如何创建一个 `my_square` 函数,作为另一种绘制正方形的方法。
![my_square function][17]
后来,我通过介绍其他 `turtle` 模块方法,包括 `penup`、`pendown` 和 `pencolor` 来扩展这个概念。很快,我的学生们就开始开发更复杂的程序,并对其进行迭代。
![Mu editor][18]
我一直渴望学习,我很想知道你在学校或家里是如何教授 Python 的。请在评论中分享你的经验。
--------------------------------------------------------------------------------
via: https://opensource.com/article/20/9/teach-python-mu
作者:[Don Watkins][a]
选题:[lujun9972][b]
译者:[geekpi](https://github.com/geekpi)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://opensource.com/users/don-watkins
[b]: https://github.com/lujun9972
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/python-programming-code-keyboard.png?itok=fxiSpmnd (Hands on a keyboard with a Python book )
[2]: https://en.wikipedia.org/wiki/Logo_(programming_language)
[3]: https://docs.python.org/3/library/turtle.html
[4]: https://www.python.org/downloads/windows/
[5]: https://docs.python.org/3/library/idle.html
[6]: https://ntoll.org/
[7]: https://codewith.mu/en/download
[8]: https://codewith.mu/en/howto/
[9]: https://codewith.mu/en/tutorials/
[10]: https://www.raspberrypi.org/blog/mu-python-ide/
[11]: https://opensource.com/sites/default/files/uploads/mu-1_open.png (Mu editor)
[12]: https://creativecommons.org/licenses/by-sa/4.0/
[13]: https://opensource.com/sites/default/files/uploads/mu-2_square.png (Mu editor)
[14]: https://opensource.com/sites/default/files/uploads/mu-3_save.png (Saving program in Mu)
[15]: https://opensource.com/sites/default/files/uploads/mu-4_run.png (Running Python program in Mu)
[16]: https://opensource.com/sites/default/files/uploads/mu-5_for-loop.png (for loops in Python with Mu)
[17]: https://opensource.com/sites/default/files/uploads/mu-6_my_square.png (my_square function)
[18]: https://opensource.com/sites/default/files/uploads/mu-7_beyond-basics.png (Mu editor)

View File

@ -0,0 +1,105 @@
[#]: collector: (lujun9972)
[#]: translator: (wxy)
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-12655-1.html)
[#]: subject: (Meet eDEX-UI, A Sci-Fi Inspired Linux Terminal Emulator With Some Cool Features)
[#]: via: (https://itsfoss.com/edex-ui-sci-fi-terminal/)
[#]: author: (Ankush Das https://itsfoss.com/author/ankush/)
eDEX-UI一款科幻风格的酷炫 Linux 终端仿真器
======
> eDEX-UI 是一个很酷的科幻电影式的终端仿真器,看起来很酷,有大量包括系统监控在内的选项。让我们来快速看看它提供了什么。
你可能已经知道了[大量有趣的 Linux 命令][1]。但你知道当谈到 Linux 命令行时,还有什么有趣的东西吗?那就是终端本身。
是的,终端仿真器(俗称终端)也可以很有趣。还记得 80 年代和 90 年代初的[酷炫复古的终端,给你一个复古的终端][2]吗?
那一款深受 《<ruby>[创:战纪][3]<rt>TRON Legacy</rt></ruby>》 电影特效启发的养眼终端感觉怎么样?
在本文中,让我们来看看一款神奇的跨平台终端模拟器,注意口水!
### eDEX-UI: 一个很酷的终端仿真器
[eDEX-UI][5] 是一款开源的跨平台终端仿真器,它为你呈现了一个科幻风格的外观和一些有用的功能。
它最初的灵感来自于 [DEX UI][6] 项目,但该项目已经不再维护。
尽管 eDEX-UI 的重点是外观和未来主义主题的终端,但它也可以作为一个 [Linux 系统监控工具][7]。怎么说呢?因为当你在终端中工作时,它可以在侧边栏中显示系统的统计信息。事实上,其开发者提到,他的目标是将其改进为一个可用的系统管理工具。
让我们来看看它还提供了什么,以及如何让它安装到你的电脑上。
### eDEX-UI 的特点
![][8]
eDEX-UI 本质上是一个终端仿真器。你可以像普通终端一样使用它来运行命令和其他任何你可以在终端中做的事情。
它以全屏方式运行,侧边栏和底部面板可以监控系统和网络的统计信息。此外,还有一个用于触摸设备的虚拟键盘。
我做了一个简短的视频,我建议你观看这个视频,看看这个很酷的终端模拟器运行起来是什么样子。**播放视频时要打开声音**(相信我)。
- [视频](https://player.vimeo.com/video/460435965)
eDEX-UI 的特点:
* 多标签
* 对 curses 的支持
* 目录查看器,显示当前工作目录的内容
* 显示系统信息包括主板信息、网络状态、IP、网络带宽使用情况、CPU 使用情况、CPU 温度、RAM 使用情况等
* 自定义选项以改变主题、键盘布局、CSS 注入
* 可选的声音效果,让你有一种黑客的感觉
* 跨平台支持Windows、macOS 和 Linux
### 在 Linux 上安装 eDEX
![eDEX-UI with Matrix theme][10]
如前所述,它支持所有主要平台,包括 Windows、macOS当然还有 Linux。
要在 Linux 发行版上安装它,你可以从它的 [GitHub 发布部分][11]中抓取 AppImage 文件,或者在包括 [AUR][13] 在内的[可用资源库][12]中找到它。如果你不知道,我建议你去看一下我们关于[在 Linux 中使用 AppImage][14] 的指南。
你可以访问它的 GitHub 页面,如果你喜欢它,可以随时星标他们的仓库。
- [eDEX-UI][5]
### 我对 eDEX-UI 的体验
因为它的科幻风格的外观,我喜欢这个终端仿真器。但是,我发现它对系统资源的消耗相当大。我没有[检查我的 Linux 系统的 CPU 温度][15],但 CPU 消耗肯定很高。
所以,如果你需要它运行在后台或单独的工作空间中(像我这样),你可能要注意这一点。除此以外,它是一个令人印象深刻的工具,拥有目录查看器和系统资源监控等有用的选项。
顺便说一句,如果你想模拟黑客来娱乐一下客人和孩子们,[那么可以试试好莱坞工具][16]。
你觉得 eDEX-UI 怎么样?你是想试一试,还是觉得太幼稚/过于复杂?
--------------------------------------------------------------------------------
via: https://itsfoss.com/edex-ui-sci-fi-terminal/
作者:[Ankush Das][a]
选题:[lujun9972][b]
译者:[wxy](https://github.com/wxy)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://itsfoss.com/author/ankush/
[b]: https://github.com/lujun9972
[1]: https://itsfoss.com/funny-linux-commands/
[2]: https://itsfoss.com/cool-retro-term/
[3]: https://www.imdb.com/title/tt1104001/
[4]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/09/edex-ui-hacking-terminal.jpg?resize=800%2C450&ssl=1
[5]: https://github.com/GitSquared/edex-ui
[6]: https://github.com/seenaburns/dex-ui
[7]: https://itsfoss.com/linux-system-monitoring-tools/
[8]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/09/edex-ui-screenshot-1.png?resize=800%2C450&ssl=1
[9]: https://www.youtube.com/c/itsfoss?sub_confirmation=1
[10]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/09/edex-ui-screenshot.png?resize=800%2C450&ssl=1
[11]: https://github.com/GitSquared/edex-ui/releases
[12]: https://repology.org/project/edex-ui/versions
[13]: https://itsfoss.com/aur-arch-linux/
[14]: https://itsfoss.com/use-appimage-linux/
[15]: https://itsfoss.com/check-laptop-cpu-temperature-ubuntu/
[16]: https://itsfoss.com/hollywood-hacker-screen/

View File

@ -0,0 +1,156 @@
[#]: collector: (lujun9972)
[#]: translator: (robsean)
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-12877-1.html)
[#]: subject: (Add sound to your Python game)
[#]: via: (https://opensource.com/article/20/9/add-sound-python-game)
[#]: author: (Seth Kenlon https://opensource.com/users/seth)
添加声音到你的 Python 游戏
======
> 通过添加声音到你的游戏中,听听当你的英雄战斗、跳跃、收集战利品时会发生什么。学习如何在这个 Pygame 系列的第十三篇文章中,创建一个声音平台类精灵。
![](https://img.linux.net.cn/data/attachment/album/202012/02/092244du74f14837zmo7fz.jpg)
在 [Python 3][2] 中使用 [Pygame][3] 模块来创建电脑游戏的系列文章仍在进行中,这是第十三部分。先前的文章是:
1. [通过构建一个简单的掷骰子游戏去学习怎么用 Python 编程][4]
2. [使用 Python 和 Pygame 模块构建一个游戏框架][5]
3. [如何在你的 Python 游戏中添加一个玩家][6]
4. [用 Pygame 使你的游戏角色移动起来][7]
5. [如何向你的 Python 游戏中添加一个敌人][8]
6. [在 Pygame 游戏中放置平台][9]
7. [在你的 Python 游戏中模拟引力][10]
8. [为你的 Python 平台类游戏添加跳跃功能][11]
9. [使你的 Python 游戏玩家能够向前和向后跑][12]
10. [在你的 Python 平台类游戏中放一些奖励][13]
11. [添加计分到你的 Python 游戏][14]
12. [在你的 Python 游戏中加入投掷机制][15]
Pygame 提供了一种简单的方法来集成声音到你的 Python 电脑游戏中。Pygame 的 [mixer 模块][16] 可以依据命令播放一个或多个声音,并且你也可以将这些声音混合在一起,例如,你能够在听到你的英雄收集奖励或跳过敌人声音的同时播放背景音乐。
集成 `mixer` 模块到一个已存在的游戏中是很容易的,因此,与其给你代码示例来向你展示放置它们的位置,不如在这篇文章解释在你的应用程序中获得声音所需的四个步骤。
### 启动 mixer
首先,在你代码的设置部分,启动 `mixer` 进程。你的代码已经启动 Pygame 和 Pygame 字体,因此将它们归类到一起是一个很好的主意:
```
pygame.init()
pygame.font.init()
pygame.mixer.init() # add this line
```
### 定义声音
接下来,你必需定义你想要使用的声音。这样就要求你的计算机上有声音文件,就像使用字体就要求你有字体文件,使用图像就要求你有图像文件一样。
你还必需把这些声音与你的游戏捆绑在一起,以便任何玩你游戏的人都有这些声音文件。
为将一个声音与你的游戏捆绑在一起,首先在你的游戏目录中创建一个新的目录,就像你为你图像和字体创建的目录一样。称它为 `sound`:
```
s = 'sound'
```
尽管在互联网上有很多声音文件,下载这些声音文件并将其与你的游戏一起分发并不一定是合法的。这看起来是很奇怪的,因为这么多来自著名电脑游戏的声音是流行文化的一部分,但法律就是这样运作的。如果你想与你的游戏一起分发一个声音文件,你必需找到一个开源或[共创许可][17]的声音文件,它们准许与游戏一起提供声音。
这里有一些专门提供自由和合法的声音文件的网站,包括:
* [Freesound][18] 托管存储所有种类的音效。
* [Incompetech][19] 托管存储背景音乐。
* [Open Game Art][20] 托管存储一些音效和音乐。
一些声音文件只要你给予作曲家或声音设计师一个致谢就可以自由使用。在与你的游戏捆绑前,仔细阅读使用条件!音乐家和声音设计师在声音上的工作就像你在代码上的工作一样努力,因此即使他们不要求,给予他们致谢也是极好的。
给予你的声音源文件一些致谢,在一个名为 `CREDIT` 的文本文件中列出你使用的声音,并在你的游戏文件夹中放置该文本文件。
你也可以尝试制作你自己的音乐。优秀的 [LMMS][21] 音频工作站易于使用,并带有很多有趣的声音。它在所有主要的平台上都可以使用,也可以导出为 [Ogg Vorbis][22]OGG音频格式。
### 添加声音到 Pygame
当你找到你喜欢的一个声音文件时,下载它。如果它是一个 ZIP 或 TAR 文件,提取它并将其移动到你游戏目录中的 `sound` 文件夹中。
如果声音文件的名字带有空格或特殊字符,重新命名它。文件名称是完全随意的,它的名称越简单,你就越容易输入到你的代码中。
大多数的电脑游戏使用 OGG 格式声音文件,因为这种格式可以占有较小空间而提供高质量的声音。当你下载一个声音文件时,它可能是一个 MP3、WAVE、FLAC 或者其它的音频格式。为保持你的文件的较高兼容性和降低下载文件大小,使用一个像 [fre:ac][23] 或 [Miro][24] 这样的工具来转换这些的文件格式为 Ogg 格式。
例如,假设你已经下载一个称为 `ouch.ogg` 的声音文件。
在你代码的设置部分中,创建一个变量,代表你想使用的声音文件:
```
ouch = pygame.mixer.Sound(os.path.join(s, 'ouch.ogg'))
```
### 触发一个声音
为使用一个声音,你所要做的就是在你想触发它的时候调用这个变量。例如,当你的玩家击中一名敌人时,触发 `OUCH` 声音效果:
```
for enemy in enemy_hit_list:
pygame.mixer.Sound.play(ouch)
score -= 1
```
你可以为各种动作创建声音,例如,跳跃、收集奖励、投掷、碰撞,以及其他任何你能想象到的动作。
### 添加背景音乐
如果你有想在你的游戏的背景中播放的音乐或令人激动的音效,你可以使用 Pygame 中的 `mixer` 模块中的 `music` 函数。在你的设置部分中,加载音乐文件:
```
music = pygame.mixer.music.load(os.path.join(s, 'music.ogg'))
```
然后,开始音乐:
```
pygame.mixer.music.play(-1)
```
`-1` 值告诉 Pygame 无限循环音乐文件。你可以将其设置为从 0 到更高的值之间的任意数值,以定义音乐在停止前循环多少次。
### 享受音效
音乐和声音可以为你的游戏添加很多韵味。尝试添加一些声音到你的 Pygame 工程!
--------------------------------------------------------------------------------
via: https://opensource.com/article/20/9/add-sound-python-game
作者:[Seth Kenlon][a]
选题:[lujun9972][b]
译者:[robsean](https://github.com/robsean)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://opensource.com/users/seth
[b]: https://github.com/lujun9972
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/colorful_sound_wave.png?itok=jlUJG0bM (Colorful sound wave graph)
[2]: https://www.python.org/
[3]: https://www.pygame.org/news
[4]: https://linux.cn/article-9071-1.html
[5]: https://linux.cn/article-10850-1.html
[6]: https://linux.cn/article-10858-1.html
[7]: https://linux.cn/article-10874-1.html
[8]: https://linux.cn/article-10883-1.html
[9]: https://linux.cn/article-10902-1.html
[10]: https://linux.cn/article-11780-1.html
[11]: https://linux.cn/article-11790-1.html
[12]: https://linux.cn/article-11819-1.html
[13]: https://linux.cn/article-11828-1.html
[14]: https://linux.cn/article-11839-1.html
[15]: https://linux.cn/article-12872-1.html
[16]: https://www.pygame.org/docs/ref/mixer.html
[17]: https://opensource.com/article/20/1/what-creative-commons
[18]: https://freesound.org
[19]: https://incompetech.filmmusic.io
[20]: https://opengameart.org
[21]: https://opensource.com/life/16/2/linux-multimedia-studio
[22]: https://en.wikipedia.org/wiki/Vorbis
[23]: https://www.freac.org/index.php/en/downloads-mainmenu-330
[24]: http://getmiro.com

View File

@ -0,0 +1,935 @@
[#]: collector: (oska874)
[#]: translator: (gxlct008)
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-12747-1.html)
[#]: subject: (Go on very small hardware Part 2)
[#]: via: (https://ziutek.github.io/2018/04/14/go_on_very_small_hardware2.html)
[#]: author: (Michał Derkacz https://ziutek.github.io/)
Go 语言在极小硬件上的运用(二)
============================================================
![](https://img.linux.net.cn/data/attachment/album/201909/24/210256yihkuy8kcigugr2h.png)
在本文的 [第一部分][2] 的结尾,我承诺要写关于接口的内容。我不想在这里写有关接口或完整或简短的讲义。相反,我将展示一个简单的示例,来说明如何定义和使用接口,以及如何利用无处不在的 `io.Writer` 接口。还有一些关于<ruby>反射<rt>reflection</rt></ruby><ruby>半主机<rt>semihosting</rt></ruby>的内容。
![STM32F030F4P6](https://ziutek.github.io/images/mcu/f030-demo-board/board.jpg)
接口是 Go 语言的重要组成部分。如果你想了解更多有关它们的信息,我建议你阅读《[高效的 Go 编程][3]》 和 [Russ Cox 的文章][4]。
### 并发 Blinky 回顾
当你阅读前面示例的代码时,你可能会注意到一中打开或关闭 LED 的反直觉方式。 `Set` 方法用于关闭 LED`Clear` 方法用于打开 LED。这是由于在 <ruby>漏极开路配置<rt>open-drain configuration</rt></ruby> 下驱动了 LED。我们可以做些什么来减少代码的混乱让我们用 `On``Off` 方法来定义 `LED` 类型:
```
type LED struct {
pin gpio.Pin
}
func (led LED) On() {
led.pin.Clear()
}
func (led LED) Off() {
led.pin.Set()
}
```
现在我们可以简单地调用 `led.On()``led.Off()`,这不会再引起任何疑惑了。
在前面的所有示例中,我都尝试使用相同的 <ruby>漏极开路配置<rt>open-drain configuration</rt></ruby>来避免代码复杂化。但是在最后一个示例中,对于我来说,将第三个 LED 连接到 GND 和 PA3 引脚之间并将 PA3 配置为<ruby>推挽模式<rt>push-pull mode</rt></ruby>会更容易。下一个示例将使用以此方式连接的 LED。
但是我们的新 `LED` 类型不支持推挽配置,实际上,我们应该将其称为 `OpenDrainLED`,并定义另一个类型 `PushPullLED`
```
type PushPullLED struct {
pin gpio.Pin
}
func (led PushPullLED) On() {
led.pin.Set()
}
func (led PushPullLED) Off() {
led.pin.Clear()
}
```
请注意,这两种类型都具有相同的方法,它们的工作方式也相同。如果在 LED 上运行的代码可以同时使用这两种类型,而不必注意当前使用的是哪种类型,那就太好了。 接口类型可以提供帮助:
```
package main
import (
"delay"
"stm32/hal/gpio"
"stm32/hal/system"
"stm32/hal/system/timer/systick"
)
type LED interface {
On()
Off()
}
type PushPullLED struct{ pin gpio.Pin }
func (led PushPullLED) On() {
led.pin.Set()
}
func (led PushPullLED) Off() {
led.pin.Clear()
}
func MakePushPullLED(pin gpio.Pin) PushPullLED {
pin.Setup(&gpio.Config{Mode: gpio.Out, Driver: gpio.PushPull})
return PushPullLED{pin}
}
type OpenDrainLED struct{ pin gpio.Pin }
func (led OpenDrainLED) On() {
led.pin.Clear()
}
func (led OpenDrainLED) Off() {
led.pin.Set()
}
func MakeOpenDrainLED(pin gpio.Pin) OpenDrainLED {
pin.Setup(&gpio.Config{Mode: gpio.Out, Driver: gpio.OpenDrain})
return OpenDrainLED{pin}
}
var led1, led2 LED
func init() {
system.SetupPLL(8, 1, 48/8)
systick.Setup(2e6)
gpio.A.EnableClock(false)
led1 = MakeOpenDrainLED(gpio.A.Pin(4))
led2 = MakePushPullLED(gpio.A.Pin(3))
}
func blinky(led LED, period int) {
for {
led.On()
delay.Millisec(100)
led.Off()
delay.Millisec(period - 100)
}
}
func main() {
go blinky(led1, 500)
blinky(led2, 1000)
}
```
我们定义了 `LED` 接口,它有两个方法: `On``Off``PushPullLED``OpenDrainLED` 类型代表两种驱动 LED 的方式。我们还定义了两个用作构造函数的 `Make*LED` 函数。这两种类型都实现了 `LED` 接口,因此可以将这些类型的值赋给 `LED` 类型的变量:
```
led1 = MakeOpenDrainLED(gpio.A.Pin(4))
led2 = MakePushPullLED(gpio.A.Pin(3))
```
在这种情况下,<ruby>可赋值性<rt>assignability</rt></ruby>在编译时检查。赋值后,`led1` 变量包含一个 `OpenDrainLED{gpio.A.Pin(4)}`,以及一个指向 `OpenDrainLED` 类型的方法集的指针。 `led1.On()` 调用大致对应于以下 C 代码:
```
led1.methods->On(led1.value)
```
如你所见,如果仅考虑函数调用的开销,这是相当廉价的抽象。
但是,对接口的任何赋值都会导致包含有关已赋值类型的大量信息。对于由许多其他类型组成的复杂类型,可能会有很多信息:
```
$ egc
$ arm-none-eabi-size cortexm0.elf
text data bss dec hex filename
10356 196 212 10764 2a0c cortexm0.elf
```
如果我们不使用 [反射][5],可以通过避免包含类型和结构字段的名称来节省一些字节:
```
$ egc -nf -nt
$ arm-none-eabi-size cortexm0.elf
text data bss dec hex filename
10312 196 212 10720 29e0 cortexm0.elf
```
生成的二进制文件仍然包含一些有关类型的必要信息和关于所有导出方法(带有名称)的完整信息。在运行时,主要是当你将存储在接口变量中的一个值赋值给任何其他变量时,需要此信息来检查可赋值性。
我们还可以通过重新编译所导入的包来删除它们的类型和字段名称:
```
$ cd $HOME/emgo
$ ./clean.sh
$ cd $HOME/firstemgo
$ egc -nf -nt
$ arm-none-eabi-size cortexm0.elf
text data bss dec hex filename
10272 196 212 10680 29b8 cortexm0.elf
```
让我们加载这个程序,看看它是否按预期工作。这一次我们将使用 [st-flash][6] 命令:
```
$ arm-none-eabi-objcopy -O binary cortexm0.elf cortexm0.bin
$ st-flash write cortexm0.bin 0x8000000
st-flash 1.4.0-33-gd76e3c7
2018-04-10T22:04:34 INFO usb.c: -- exit_dfu_mode
2018-04-10T22:04:34 INFO common.c: Loading device parameters....
2018-04-10T22:04:34 INFO common.c: Device connected is: F0 small device, id 0x10006444
2018-04-10T22:04:34 INFO common.c: SRAM size: 0x1000 bytes (4 KiB), Flash: 0x4000 bytes (16 KiB) in pages of 1024 bytes
2018-04-10T22:04:34 INFO common.c: Attempting to write 10468 (0x28e4) bytes to stm32 address: 134217728 (0x8000000)
Flash page at addr: 0x08002800 erased
2018-04-10T22:04:34 INFO common.c: Finished erasing 11 pages of 1024 (0x400) bytes
2018-04-10T22:04:34 INFO common.c: Starting Flash write for VL/F0/F3/F1_XL core id
2018-04-10T22:04:34 INFO flash_loader.c: Successfully loaded flash loader in sram
11/11 pages written
2018-04-10T22:04:35 INFO common.c: Starting verification of write complete
2018-04-10T22:04:35 INFO common.c: Flash written and verified! jolly good!
```
我没有将 NRST 信号连接到编程器,因此无法使用 `-reset` 选项,必须按下复位按钮才能运行程序。
![Interfaces](https://ziutek.github.io/images/mcu/f030-demo-board/interfaces.png)
看来,`st-flash` 与此板配合使用有点不可靠(通常需要复位 ST-LINK 加密狗)。此外,当前版本不会通过 SWD 发出复位命令(仅使用 NRST 信号)。软件复位是不现实的,但是它通常是有效的,缺少它会将会带来不便。对于<ruby>板卡程序员<rt>board-programmer</rt></ruby> 来说 OpenOCD 工作得更好。
### UART
UART<ruby>通用异步收发传输器<rt>Universal Aynchronous Receiver-Transmitter</rt></ruby>)仍然是当今微控制器最重要的外设之一。它的优点是以下属性的独特组合:
* 相对较高的速度,
* 仅两条信号线(在 <ruby>半双工<rt>half-duplex</rt></ruby> 通信的情况下甚至一条),
* 角色对称,
* 关于新数据的 <ruby>同步带内信令<rt>synchronous in-band signaling</rt></ruby>(起始位),
* 在传输 <ruby><rt>words</rt></ruby> 内的精确计时。
这使得最初用于传输由 7-9 位的字组成的异步消息的 UART也被用于有效地实现各种其他物理协议例如被 [WS28xx LEDs][7] 或 [1-wire][8] 设备使用的协议。
但是,我们将以其通常的角色使用 UART从程序中打印文本消息。
```
package main
import (
"io"
"rtos"
"stm32/hal/dma"
"stm32/hal/gpio"
"stm32/hal/irq"
"stm32/hal/system"
"stm32/hal/system/timer/systick"
"stm32/hal/usart"
)
var tts *usart.Driver
func init() {
system.SetupPLL(8, 1, 48/8)
systick.Setup(2e6)
gpio.A.EnableClock(true)
tx := gpio.A.Pin(9)
tx.Setup(&gpio.Config{Mode: gpio.Alt})
tx.SetAltFunc(gpio.USART1_AF1)
d := dma.DMA1
d.EnableClock(true)
tts = usart.NewDriver(usart.USART1, d.Channel(2, 0), nil, nil)
tts.Periph().EnableClock(true)
tts.Periph().SetBaudRate(115200)
tts.Periph().Enable()
tts.EnableTx()
rtos.IRQ(irq.USART1).Enable()
rtos.IRQ(irq.DMA1_Channel2_3).Enable()
}
func main() {
io.WriteString(tts, "Hello, World!\r\n")
}
func ttsISR() {
tts.ISR()
}
func ttsDMAISR() {
tts.TxDMAISR()
}
//c:__attribute__((section(".ISRs")))
var ISRs = [...]func(){
irq.USART1: ttsISR,
irq.DMA1_Channel2_3: ttsDMAISR,
}
```
你会发现此代码可能有些复杂,但目前 STM32 HAL 中没有更简单的 UART 驱动程序(在某些情况下,简单的轮询驱动程序可能会很有用)。 `usart.Driver` 是使用 DMA 和中断来减轻 CPU 负担的高效驱动程序。
STM32 USART 外设提供传统的 UART 及其同步版本。要将其用作输出,我们必须将其 Tx 信号连接到正确的 GPIO 引脚:
```
tx.Setup(&gpio.Config{Mode: gpio.Alt})
tx.SetAltFunc(gpio.USART1_AF1)
```
在 Tx-only 模式下配置 `usart.Driver` rxdma 和 rxbuf 设置为 nil
```
tts = usart.NewDriver(usart.USART1, d.Channel(2, 0), nil, nil)
```
我们使用它的 `WriteString` 方法来打印这句名言。让我们清理所有内容并编译该程序:
```
$ cd $HOME/emgo
$ ./clean.sh
$ cd $HOME/firstemgo
$ egc
$ arm-none-eabi-size cortexm0.elf
text data bss dec hex filename
12728 236 176 13140 3354 cortexm0.elf
```
要查看某些内容,你需要在 PC 中使用 UART 外设。
**请勿使用 RS232 端口或 USB 转 RS232 转换器!**
STM32 系列使用 3.3V 逻辑,但是 RS232 可以产生 -15 V ~ +15 V 的电压,这可能会损坏你的 MCU。你需要使用 3.3V 逻辑的 USB 转 UART 转换器。流行的转换器基于 FT232 或 CP2102 芯片。
![UART](https://ziutek.github.io/images/mcu/f030-demo-board/uart.jpg)
你还需要一些终端仿真程序(我更喜欢 [picocom][9])。刷新新图像,运行终端仿真器,然后按几次复位按钮:
```
$ openocd -d0 -f interface/stlink.cfg -f target/stm32f0x.cfg -c 'init; program cortexm0.elf; reset run; exit'
Open On-Chip Debugger 0.10.0+dev-00319-g8f1f912a (2018-03-07-19:20)
Licensed under GNU GPL v2
For bug reports, read
http://openocd.org/doc/doxygen/bugs.html
debug_level: 0
adapter speed: 1000 kHz
adapter_nsrst_delay: 100
none separate
adapter speed: 950 kHz
target halted due to debug-request, current mode: Thread
xPSR: 0xc1000000 pc: 0x080016f4 msp: 0x20000a20
adapter speed: 4000 kHz
** Programming Started **
auto erase enabled
target halted due to breakpoint, current mode: Thread
xPSR: 0x61000000 pc: 0x2000003a msp: 0x20000a20
wrote 13312 bytes from file cortexm0.elf in 1.020185s (12.743 KiB/s)
** Programming Finished **
adapter speed: 950 kHz
$
$ picocom -b 115200 /dev/ttyUSB0
picocom v3.1
port is : /dev/ttyUSB0
flowcontrol : none
baudrate is : 115200
parity is : none
databits are : 8
stopbits are : 1
escape is : C-a
local echo is : no
noinit is : no
noreset is : no
hangup is : no
nolock is : no
send_cmd is : sz -vv
receive_cmd is : rz -vv -E
imap is :
omap is :
emap is : crcrlf,delbs,
logfile is : none
initstring : none
exit_after is : not set
exit is : no
Type [C-a] [C-h] to see available commands
Terminal ready
Hello, World!
Hello, World!
Hello, World!
```
每次按下复位按钮都会产生新的 “HelloWorld”行。一切都在按预期进行。
要查看此 MCU 的 <ruby>双向<rt>bi-directional</rt></ruby> UART 代码,请查看 [此示例][10]。
### io.Writer 接口
`io.Writer` 接口可能是 Go 中第二种最常用的接口类型,仅次于 `error` 接口。其定义如下所示:
```
type Writer interface {
Write(p []byte) (n int, err error)
}
```
`usart.Driver` 实现了 `io.Writer`,因此我们可以替换:
```
tts.WriteString("Hello, World!\r\n")
```
```
io.WriteString(tts, "Hello, World!\r\n")
```
此外,你需要将 `io` 包添加到 `import` 部分。
`io.WriteString` 函数的声明如下所示:
```
func WriteString(w Writer, s string) (n int, err error)
```
如你所见,`io.WriteString` 允许使用实现了 `io.Writer` 接口的任何类型来编写字符串。在内部,它检查基础类型是否具有 `WriteString` 方法,并使用该方法代替 `Write`(如果可用)。
让我们编译修改后的程序:
```
$ egc
$ arm-none-eabi-size cortexm0.elf
text data bss dec hex filename
15456 320 248 16024 3e98 cortexm0.elf
```
如你所见,`io.WriteString` 导致二进制文件的大小显着增加15776-12964 = 2812 字节。 Flash 上没有太多空间了。是什么引起了这么大规模的增长?
使用这个命令:
```
arm-none-eabi-nm --print-size --size-sort --radix=d cortexm0.elf
```
我们可以打印两种情况下按其大小排序的所有符号。通过过滤和分析获得的数据(`awk``diff`),我们可以找到大约 80 个新符号。最大的十个如下所示:
```
> 00000062 T stm32$hal$usart$Driver$DisableRx
> 00000072 T stm32$hal$usart$Driver$RxDMAISR
> 00000076 T internal$Type$Implements
> 00000080 T stm32$hal$usart$Driver$EnableRx
> 00000084 t errors$New
> 00000096 R $8$stm32$hal$usart$Driver$$
> 00000100 T stm32$hal$usart$Error$Error
> 00000360 T io$WriteString
> 00000660 T stm32$hal$usart$Driver$Read
```
因此,即使我们不使用 `usart.Driver.Read` 方法,但它被编译进来了,与 `DisableRx`、`RxDMAISR`、`EnableRx` 以及上面未提及的其他方法一样。不幸的是,如果你为接口赋值了一些内容,就需要它的完整方法集(包含所有依赖项)。对于使用大多数方法的大型程序来说,这不是问题。但是对于我们这种极简的情况而言,这是一个巨大的负担。
我们已经接近 MCU 的极限,但让我们尝试打印一些数字(你需要在 `import` 部分中用 `strconv` 替换 `io` 包):
```
func main() {
a := 12
b := -123
tts.WriteString("a = ")
strconv.WriteInt(tts, a, 10, 0, 0)
tts.WriteString("\r\n")
tts.WriteString("b = ")
strconv.WriteInt(tts, b, 10, 0, 0)
tts.WriteString("\r\n")
tts.WriteString("hex(a) = ")
strconv.WriteInt(tts, a, 16, 0, 0)
tts.WriteString("\r\n")
tts.WriteString("hex(b) = ")
strconv.WriteInt(tts, b, 16, 0, 0)
tts.WriteString("\r\n")
}
```
与使用 `io.WriteString` 函数的情况一样,`strconv.WriteInt` 的第一个参数的类型为 `io.Writer`
```
$ egc
/usr/local/arm/bin/arm-none-eabi-ld: /home/michal/firstemgo/cortexm0.elf section `.rodata' will not fit in region `Flash'
/usr/local/arm/bin/arm-none-eabi-ld: region `Flash' overflowed by 692 bytes
exit status 1
```
这一次我们的空间超出的不多。让我们试着精简一下有关类型的信息:
```
$ cd $HOME/emgo
$ ./clean.sh
$ cd $HOME/firstemgo
$ egc -nf -nt
$ arm-none-eabi-size cortexm0.elf
text data bss dec hex filename
15876 316 320 16512 4080 cortexm0.elf
```
很接近,但很合适。让我们加载并运行此代码:
```
a = 12
b = -123
hex(a) = c
hex(b) = -7b
```
Emgo 中的 `strconv` 包与 Go 中的原型有很大的不同。它旨在直接用于写入格式化的数字,并且在许多情况下可以替换沉重的 `fmt` 包。 这就是为什么函数名称以 `Write` 而不是 `Format` 开头,并具有额外的两个参数的原因。 以下是其用法示例:
```
func main() {
b := -123
strconv.WriteInt(tts, b, 10, 0, 0)
tts.WriteString("\r\n")
strconv.WriteInt(tts, b, 10, 6, ' ')
tts.WriteString("\r\n")
strconv.WriteInt(tts, b, 10, 6, '0')
tts.WriteString("\r\n")
strconv.WriteInt(tts, b, 10, 6, '.')
tts.WriteString("\r\n")
strconv.WriteInt(tts, b, 10, -6, ' ')
tts.WriteString("\r\n")
strconv.WriteInt(tts, b, 10, -6, '0')
tts.WriteString("\r\n")
strconv.WriteInt(tts, b, 10, -6, '.')
tts.WriteString("\r\n")
}
```
下面是它的输出:
```
-123
-123
-00123
..-123
-123
-123
-123..
```
### Unix 流 和 <ruby>莫尔斯电码<rt>Morse code</rt></ruby>
由于大多数写入的函数都使用 `io.Writer` 而不是具体类型(例如 C 中的 `FILE` ),因此我们获得了类似于 Unix <ruby><rt>stream</rt></ruby> 的功能。在 Unix 中,我们可以轻松地组合简单的命令来执行更大的任务。例如,我们可以通过以下方式将文本写入文件:
```
echo "Hello, World!" > file.txt
```
`>` 操作符将前面命令的输出流写入文件。还有 `|` 操作符,用于连接相邻命令的输出流和输入流。
多亏了流,我们可以轻松地转换/过滤任何命令的输出。例如,要将所有字母转换为大写,我们可以通过 `tr` 命令过滤 `echo` 的输出:
```
echo "Hello, World!" | tr a-z A-Z > file.txt
```
为了显示 `io.Writer` 和 Unix 流之间的类比,让我们编写以下代码:
```
io.WriteString(tts, "Hello, World!\r\n")
```
采用以下伪 unix 形式:
```
io.WriteString "Hello, World!" | usart.Driver usart.USART1
```
下一个示例将显示如何执行此操作:
```
io.WriteString "Hello, World!" | MorseWriter | usart.Driver usart.USART1
```
让我们来创建一个简单的编码器,它使用莫尔斯电码对写入的文本进行编码:
```
type MorseWriter struct {
W io.Writer
}
func (w *MorseWriter) Write(s []byte) (int, error) {
var buf [8]byte
for n, c := range s {
switch {
case c == '\n':
c = ' ' // Replace new lines with spaces.
case 'a' <= c && c <= 'z':
c -= 'a' - 'A' // Convert to upper case.
}
if c < ' ' || 'Z' < c {
continue // c is outside ASCII [' ', 'Z']
}
var symbol morseSymbol
if c == ' ' {
symbol.length = 1
buf[0] = ' '
} else {
symbol = morseSymbols[c-'!']
for i := uint(0); i < uint(symbol.length); i++ {
if (symbol.code>>i)&1 != 0 {
buf[i] = '-'
} else {
buf[i] = '.'
}
}
}
buf[symbol.length] = ' '
if _, err := w.W.Write(buf[:symbol.length+1]); err != nil {
return n, err
}
}
return len(s), nil
}
type morseSymbol struct {
code, length byte
}
//emgo:const
var morseSymbols = [...]morseSymbol{
{1<<0 | 1<<1 | 1<<2, 4}, // ! ---.
{1<<1 | 1<<4, 6}, // " .-..-.
{}, // #
{1<<3 | 1<<6, 7}, // $ ...-..-
// Some code omitted...
{1<<0 | 1<<3, 4}, // X -..-
{1<<0 | 1<<2 | 1<<3, 4}, // Y -.--
{1<<0 | 1<<1, 4}, // Z --..
}
```
你可以在 [这里][11] 找到完整的 `morseSymbols` 数组。 `//emgo:const` 指令确保 `morseSymbols` 数组不会被复制到 RAM 中。
现在我们可以通过两种方式打印句子:
```
func main() {
s := "Hello, World!\r\n"
mw := &MorseWriter{tts}
io.WriteString(tts, s)
io.WriteString(mw, s)
}
```
我们使用指向 `MorseWriter` `&MorseWriter{tts}` 的指针而不是简单的 `MorseWriter{tts}` 值,因为 `MorseWriter` 太大,不适合接口变量。
与 Go 不同Emgo 不会为存储在接口变量中的值动态分配内存。接口类型的大小受限制,相当于三个指针(适合 `slice` )或两个 `float64`(适合 `complex128`)的大小,以较大者为准。它可以直接存储所有基本类型和小型 “结构体/数组” 的值,但是对于较大的值,你必须使用指针。
让我们编译此代码并查看其输出:
```
$ egc
$ arm-none-eabi-size cortexm0.elf
text data bss dec hex filename
15152 324 248 15724 3d6c cortexm0.elf
```
```
Hello, World!
.... . .-.. .-.. --- --..-- .-- --- .-. .-.. -.. ---.
```
### 终极闪烁
Blinky 是等效于 “HelloWorld” 程序的硬件。一旦有了摩尔斯编码器,我们就可以轻松地将两者结合起来以获得终极闪烁程序:
```
package main
import (
"delay"
"io"
"stm32/hal/gpio"
"stm32/hal/system"
"stm32/hal/system/timer/systick"
)
var led gpio.Pin
func init() {
system.SetupPLL(8, 1, 48/8)
systick.Setup(2e6)
gpio.A.EnableClock(false)
led = gpio.A.Pin(4)
cfg := gpio.Config{Mode: gpio.Out, Driver: gpio.OpenDrain, Speed: gpio.Low}
led.Setup(&cfg)
}
type Telegraph struct {
Pin gpio.Pin
Dotms int // Dot length [ms]
}
func (t Telegraph) Write(s []byte) (int, error) {
for _, c := range s {
switch c {
case '.':
t.Pin.Clear()
delay.Millisec(t.Dotms)
t.Pin.Set()
delay.Millisec(t.Dotms)
case '-':
t.Pin.Clear()
delay.Millisec(3 * t.Dotms)
t.Pin.Set()
delay.Millisec(t.Dotms)
case ' ':
delay.Millisec(3 * t.Dotms)
}
}
return len(s), nil
}
func main() {
telegraph := &MorseWriter{Telegraph{led, 100}}
for {
io.WriteString(telegraph, "Hello, World! ")
}
}
// Some code omitted...
```
在上面的示例中,我省略了 `MorseWriter` 类型的定义,因为它已在前面展示过。完整版可通过 [这里][12] 获取。让我们编译它并运行:
```
$ egc
$ arm-none-eabi-size cortexm0.elf
text data bss dec hex filename
11772 244 244 12260 2fe4 cortexm0.elf
```
![Ultimate Blinky](https://ziutek.github.io/images/mcu/f030-demo-board/morse.png)
### 反射
是的Emgo 支持 [反射][13]。`reflect` 包尚未完成,但是已完成的部分足以实现 `fmt.Print` 函数族了。来看看我们可以在小型 MCU 上做什么。
为了减少内存使用,我们将使用 <ruby>[半主机][14]<rt>semihosting</rt></ruby> 作为标准输出。为了方便起见,我们还编写了简单的 `println` 函数,它在某种程度上类似于 `fmt.Println`
```
package main
import (
"debug/semihosting"
"reflect"
"strconv"
"stm32/hal/system"
"stm32/hal/system/timer/systick"
)
var stdout semihosting.File
func init() {
system.SetupPLL(8, 1, 48/8)
systick.Setup(2e6)
var err error
stdout, err = semihosting.OpenFile(":tt", semihosting.W)
for err != nil {
}
}
type stringer interface {
String() string
}
func println(args ...interface{}) {
for i, a := range args {
if i > 0 {
stdout.WriteString(" ")
}
switch v := a.(type) {
case string:
stdout.WriteString(v)
case int:
strconv.WriteInt(stdout, v, 10, 0, 0)
case bool:
strconv.WriteBool(stdout, v, 't', 0, 0)
case stringer:
stdout.WriteString(v.String())
default:
stdout.WriteString("%unknown")
}
}
stdout.WriteString("\r\n")
}
type S struct {
A int
B bool
}
func main() {
p := &S{-123, true}
v := reflect.ValueOf(p)
println("kind(p) =", v.Kind())
println("kind(*p) =", v.Elem().Kind())
println("type(*p) =", v.Elem().Type())
v = v.Elem()
println("*p = {")
for i := 0; i < v.NumField(); i++ {
ft := v.Type().Field(i)
fv := v.Field(i)
println(" ", ft.Name(), ":", fv.Interface())
}
println("}")
}
```
`semihosting.OpenFile` 函数允许在主机端打开/创建文件。特殊路径 `:tt` 对应于主机的标准输出。
`println` 函数接受任意数量的参数,每个参数的类型都是任意的:
```
func println(args ...interface{})
```
可能是因为任何类型都实现了空接口 `interface{}``println` 使用 [类型开关][15] 打印字符串,整数和布尔值:
```
switch v := a.(type) {
case string:
stdout.WriteString(v)
case int:
strconv.WriteInt(stdout, v, 10, 0, 0)
case bool:
strconv.WriteBool(stdout, v, 't', 0, 0)
case stringer:
stdout.WriteString(v.String())
default:
stdout.WriteString("%unknown")
}
```
此外,它还支持任何实现了 `stringer` 接口的类型,即任何具有 `String()` 方法的类型。在任何 `case` 子句中,`v` 变量具有正确的类型,与 `case` 关键字后列出的类型相同。
`reflect.ValueOf(p)` 函数通过允许以编程的方式分析其类型和内容的形式返回 `p`。如你所见,我们甚至可以使用 `v.Elem()` 取消引用指针,并打印所有结构体及其名称。
让我们尝试编译这段代码。现在让我们看看如果编译时没有类型和字段名,会有什么结果:
```
$ egc -nt -nf
$ arm-none-eabi-size cortexm0.elf
text data bss dec hex filename
16028 216 312 16556 40ac cortexm0.elf
```
闪存上只剩下 140 个可用字节。让我们使用启用了半主机的 OpenOCD 加载它:
```
$ openocd -d0 -f interface/stlink.cfg -f target/stm32f0x.cfg -c 'init; program cortexm0.elf; arm semihosting enable; reset run'
Open On-Chip Debugger 0.10.0+dev-00319-g8f1f912a (2018-03-07-19:20)
Licensed under GNU GPL v2
For bug reports, read
http://openocd.org/doc/doxygen/bugs.html
debug_level: 0
adapter speed: 1000 kHz
adapter_nsrst_delay: 100
none separate
adapter speed: 950 kHz
target halted due to debug-request, current mode: Thread
xPSR: 0xc1000000 pc: 0x08002338 msp: 0x20000a20
adapter speed: 4000 kHz
** Programming Started **
auto erase enabled
target halted due to breakpoint, current mode: Thread
xPSR: 0x61000000 pc: 0x2000003a msp: 0x20000a20
wrote 16384 bytes from file cortexm0.elf in 0.700133s (22.853 KiB/s)
** Programming Finished **
semihosting is enabled
adapter speed: 950 kHz
kind(p) = ptr
kind(*p) = struct
type(*p) =
*p = {
X. : -123
X. : true
}
```
如果你实际运行此代码,则会注意到半主机运行缓慢,尤其是在逐字节写入时(缓冲很有用)。
如你所见,`*p` 没有类型名称,并且所有结构字段都具有相同的 `X.` 名称。让我们再次编译该程序,这次不带 `-nt -nf` 选项:
```
$ egc
$ arm-none-eabi-size cortexm0.elf
text data bss dec hex filename
16052 216 312 16580 40c4 cortexm0.elf
```
现在已经包括了类型和字段名称,但仅在 ~~_main.go_ 文件中~~ `main` 包中定义了它们。该程序的输出如下所示:
```
kind(p) = ptr
kind(*p) = struct
type(*p) = S
*p = {
A : -123
B : true
}
```
反射是任何易于使用的序列化库的关键部分,而像 [JSON][16] 这样的序列化 ~~算法~~<ruby>物联网<rt>IoT</rt></ruby>时代也越来越重要。
这些就是我完成的本文的第二部分。我认为有机会进行第三部分,更具娱乐性的部分,在那里我们将各种有趣的设备连接到这块板上。如果这块板装不下,我们就换一块大一点的。
--------------------------------------------------------------------------------
via: https://ziutek.github.io/2018/04/14/go_on_very_small_hardware2.html
作者:[Michał Derkacz][a]
译者:[gxlct008](https://github.com/gxlct008)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://ziutek.github.io/
[1]:https://ziutek.github.io/2018/04/14/go_on_very_small_hardware2.html
[2]:https://linux.cn/article-11383-1.html
[3]:https://golang.org/doc/effective_go.html#interfaces
[4]:https://research.swtch.com/interfaces
[5]:https://blog.golang.org/laws-of-reflection
[6]:https://github.com/texane/stlink
[7]:http://www.world-semi.com/solution/list-4-1.html
[8]:https://en.wikipedia.org/wiki/1-Wire
[9]:https://github.com/npat-efault/picocom
[10]:https://github.com/ziutek/emgo/blob/master/egpath/src/stm32/examples/f030-demo-board/usart/main.go
[11]:https://github.com/ziutek/emgo/blob/master/egpath/src/stm32/examples/f030-demo-board/morseuart/main.go
[12]:https://github.com/ziutek/emgo/blob/master/egpath/src/stm32/examples/f030-demo-board/morseled/main.go
[13]:https://blog.golang.org/laws-of-reflection
[14]:http://infocenter.arm.com/help/topic/com.arm.doc.dui0471g/Bgbjjgij.html
[15]:https://golang.org/doc/effective_go.html#type_switch
[16]:https://en.wikipedia.org/wiki/JSON

View File

@ -0,0 +1,315 @@
[#]: collector: (lujun9972)
[#]: translator: (gxlct008)
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-12680-1.html)
[#]: subject: (Building a Messenger App: Messages)
[#]: via: (https://nicolasparada.netlify.com/posts/go-messenger-messages/)
[#]: author: (Nicolás Parada https://nicolasparada.netlify.com/)
构建一个即时消息应用(四):消息
======
![](https://img.linux.net.cn/data/attachment/album/202010/04/114458z1p1188epequ686p.jpg)
本文是该系列的第四篇。
* [第一篇: 模式][1]
* [第二篇: OAuth][2]
* [第三篇: 对话][3]
在这篇文章中,我们将对端点进行编码,以创建一条消息并列出它们,同时还将编写一个端点以更新参与者上次阅读消息的时间。 首先在 `main()` 函数中添加这些路由。
```
router.HandleFunc("POST", "/api/conversations/:conversationID/messages", requireJSON(guard(createMessage)))
router.HandleFunc("GET", "/api/conversations/:conversationID/messages", guard(getMessages))
router.HandleFunc("POST", "/api/conversations/:conversationID/read_messages", guard(readMessages))
```
消息会进入对话,因此端点包含对话 ID。
### 创建消息
该端点处理对 `/api/conversations/{conversationID}/messages` 的 POST 请求,其 JSON 主体仅包含消息内容,并返回新创建的消息。它有两个副作用:更新对话 `last_message_id` 以及更新参与者 `messages_read_at`
```
func createMessage(w http.ResponseWriter, r *http.Request) {
var input struct {
Content string `json:"content"`
}
defer r.Body.Close()
if err := json.NewDecoder(r.Body).Decode(&input); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
errs := make(map[string]string)
input.Content = removeSpaces(input.Content)
if input.Content == "" {
errs["content"] = "Message content required"
} else if len([]rune(input.Content)) > 480 {
errs["content"] = "Message too long. 480 max"
}
if len(errs) != 0 {
respond(w, Errors{errs}, http.StatusUnprocessableEntity)
return
}
ctx := r.Context()
authUserID := ctx.Value(keyAuthUserID).(string)
conversationID := way.Param(ctx, "conversationID")
tx, err := db.BeginTx(ctx, nil)
if err != nil {
respondError(w, fmt.Errorf("could not begin tx: %v", err))
return
}
defer tx.Rollback()
isParticipant, err := queryParticipantExistance(ctx, tx, authUserID, conversationID)
if err != nil {
respondError(w, fmt.Errorf("could not query participant existance: %v", err))
return
}
if !isParticipant {
http.Error(w, "Conversation not found", http.StatusNotFound)
return
}
var message Message
if err := tx.QueryRowContext(ctx, `
INSERT INTO messages (content, user_id, conversation_id) VALUES
($1, $2, $3)
RETURNING id, created_at
`, input.Content, authUserID, conversationID).Scan(
&message.ID,
&message.CreatedAt,
); err != nil {
respondError(w, fmt.Errorf("could not insert message: %v", err))
return
}
if _, err := tx.ExecContext(ctx, `
UPDATE conversations SET last_message_id = $1
WHERE id = $2
`, message.ID, conversationID); err != nil {
respondError(w, fmt.Errorf("could not update conversation last message ID: %v", err))
return
}
if err = tx.Commit(); err != nil {
respondError(w, fmt.Errorf("could not commit tx to create a message: %v", err))
return
}
go func() {
if err = updateMessagesReadAt(nil, authUserID, conversationID); err != nil {
log.Printf("could not update messages read at: %v\n", err)
}
}()
message.Content = input.Content
message.UserID = authUserID
message.ConversationID = conversationID
// TODO: notify about new message.
message.Mine = true
respond(w, message, http.StatusCreated)
}
```
首先,它将请求正文解码为包含消息内容的结构。然后,它验证内容不为空并且少于 480 个字符。
```
var rxSpaces = regexp.MustCompile("\\s+")
func removeSpaces(s string) string {
if s == "" {
return s
}
lines := make([]string, 0)
for _, line := range strings.Split(s, "\n") {
line = rxSpaces.ReplaceAllLiteralString(line, " ")
line = strings.TrimSpace(line)
if line != "" {
lines = append(lines, line)
}
}
return strings.Join(lines, "\n")
}
```
这是删除空格的函数。它遍历每一行,删除两个以上的连续空格,然后回非空行。
验证之后,它将启动一个 SQL 事务。首先,它查询对话中的参与者是否存在。
```
func queryParticipantExistance(ctx context.Context, tx *sql.Tx, userID, conversationID string) (bool, error) {
if ctx == nil {
ctx = context.Background()
}
var exists bool
if err := tx.QueryRowContext(ctx, `SELECT EXISTS (
SELECT 1 FROM participants
WHERE user_id = $1 AND conversation_id = $2
)`, userID, conversationID).Scan(&exists); err != nil {
return false, err
}
return exists, nil
}
```
我将其提取到一个函数中,因为稍后可以重用。
如果用户不是对话参与者,我们将返回一个 `404 NOT Found` 错误。
然后,它插入消息并更新对话 `last_message_id`。从这时起,由于我们不允许删除消息,因此 `last_message_id` 不能为 `NULL`
接下来提交事务,并在 goroutine 中更新参与者 `messages_read_at`
```
func updateMessagesReadAt(ctx context.Context, userID, conversationID string) error {
if ctx == nil {
ctx = context.Background()
}
if _, err := db.ExecContext(ctx, `
UPDATE participants SET messages_read_at = now()
WHERE user_id = $1 AND conversation_id = $2
`, userID, conversationID); err != nil {
return err
}
return nil
}
```
在回复这条新消息之前,我们必须通知一下。这是我们将要在下一篇文章中编写的实时部分,因此我在那里留一了个注释。
### 获取消息
这个端点处理对 `/api/conversations/{conversationID}/messages` 的 GET 请求。 它用一个包含会话中所有消息的 JSON 数组进行响应。它还具有更新参与者 `messages_read_at` 的副作用。
```
func getMessages(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
authUserID := ctx.Value(keyAuthUserID).(string)
conversationID := way.Param(ctx, "conversationID")
tx, err := db.BeginTx(ctx, &sql.TxOptions{ReadOnly: true})
if err != nil {
respondError(w, fmt.Errorf("could not begin tx: %v", err))
return
}
defer tx.Rollback()
isParticipant, err := queryParticipantExistance(ctx, tx, authUserID, conversationID)
if err != nil {
respondError(w, fmt.Errorf("could not query participant existance: %v", err))
return
}
if !isParticipant {
http.Error(w, "Conversation not found", http.StatusNotFound)
return
}
rows, err := tx.QueryContext(ctx, `
SELECT
id,
content,
created_at,
user_id = $1 AS mine
FROM messages
WHERE messages.conversation_id = $2
ORDER BY messages.created_at DESC
`, authUserID, conversationID)
if err != nil {
respondError(w, fmt.Errorf("could not query messages: %v", err))
return
}
defer rows.Close()
messages := make([]Message, 0)
for rows.Next() {
var message Message
if err = rows.Scan(
&message.ID,
&message.Content,
&message.CreatedAt,
&message.Mine,
); err != nil {
respondError(w, fmt.Errorf("could not scan message: %v", err))
return
}
messages = append(messages, message)
}
if err = rows.Err(); err != nil {
respondError(w, fmt.Errorf("could not iterate over messages: %v", err))
return
}
if err = tx.Commit(); err != nil {
respondError(w, fmt.Errorf("could not commit tx to get messages: %v", err))
return
}
go func() {
if err = updateMessagesReadAt(nil, authUserID, conversationID); err != nil {
log.Printf("could not update messages read at: %v\n", err)
}
}()
respond(w, messages, http.StatusOK)
}
```
首先,它以只读模式开始一个 SQL 事务。检查参与者是否存在,并查询所有消息。在每条消息中,我们使用当前经过身份验证的用户 ID 来了解用户是否拥有该消息(`mine`)。 然后,它提交事务,在 goroutine 中更新参与者 `messages_read_at` 并以消息响应。
### 读取消息
该端点处理对 `/api/conversations/{conversationID}/read_messages` 的 POST 请求。 没有任何请求或响应主体。 在前端,每次有新消息到达实时流时,我们都会发出此请求。
```
func readMessages(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
authUserID := ctx.Value(keyAuthUserID).(string)
conversationID := way.Param(ctx, "conversationID")
if err := updateMessagesReadAt(ctx, authUserID, conversationID); err != nil {
respondError(w, fmt.Errorf("could not update messages read at: %v", err))
return
}
w.WriteHeader(http.StatusNoContent)
}
```
它使用了与更新参与者 `messages_read_at` 相同的函数。
* * *
到此为止。实时消息是后台仅剩的部分了。请等待下一篇文章。
- [源代码][4]
--------------------------------------------------------------------------------
via: https://nicolasparada.netlify.com/posts/go-messenger-messages/
作者:[Nicolás Parada][a]
选题:[lujun9972][b]
译者:[gxlct008](https://github.com/gxlct008)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://nicolasparada.netlify.com/
[b]: https://github.com/lujun9972
[1]: https://linux.cn/article-11396-1.html
[2]: https://linux.cn/article-11510-1.html
[3]: https://linux.cn/article-12056-1.html
[4]: https://github.com/nicolasparada/go-messenger-demo

View File

@ -0,0 +1,175 @@
[#]: collector: (lujun9972)
[#]: translator: (gxlct008)
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-12685-1.html)
[#]: subject: (Building a Messenger App: Realtime Messages)
[#]: via: (https://nicolasparada.netlify.com/posts/go-messenger-realtime-messages/)
[#]: author: (Nicolás Parada https://nicolasparada.netlify.com/)
构建一个即时消息应用(五):实时消息
======
![](https://img.linux.net.cn/data/attachment/album/202010/05/091113edbuavorm89looja.jpg)
本文是该系列的第五篇。
* [第一篇: 模式][1]
* [第二篇: OAuth][2]
* [第三篇: 对话][3]
* [第四篇: 消息][4]
对于实时消息,我们将使用 <ruby>[服务器发送事件][5]<rt>Server-Sent Events</rt></ruby>。这是一个打开的连接,我们可以在其中传输数据流。我们会有个端点,用户会在其中订阅发送给他的所有消息。
### 消息户端
在 HTTP 部分之前,让我们先编写一个<ruby>映射<rt>map</rt></ruby> ,让所有客户端都监听消息。 像这样全局初始化:
```go
type MessageClient struct {
Messages chan Message
UserID string
}
var messageClients sync.Map
```
### 已创建的新消息
还记得在 [上一篇文章][4] 中,当我们创建这条消息时,我们留下了一个 “TODO” 注释。在那里,我们将使用这个函数来调度一个 goroutine。
```go
go messageCreated(message)
```
把这行代码插入到我们留注释的位置。
```go
func messageCreated(message Message) error {
if err := db.QueryRow(`
SELECT user_id FROM participants
WHERE user_id != $1 and conversation_id = $2
`, message.UserID, message.ConversationID).
Scan(&message.ReceiverID); err != nil {
return err
}
go broadcastMessage(message)
return nil
}
func broadcastMessage(message Message) {
messageClients.Range(func(key, _ interface{}) bool {
client := key.(*MessageClient)
if client.UserID == message.ReceiverID {
client.Messages <- message
}
return true
})
}
```
该函数查询接收者 ID其他参与者 ID并将消息发送给所有客户端。
### 订阅消息
让我们转到 `main()` 函数并添加以下路由:
```go
router.HandleFunc("GET", "/api/messages", guard(subscribeToMessages))
```
此端点处理 `/api/messages` 上的 GET 请求。请求应该是一个 [EventSource][6] 连接。它用一个事件流响应,其中的数据是 JSON 格式的。
```go
func subscribeToMessages(w http.ResponseWriter, r *http.Request) {
if a := r.Header.Get("Accept"); !strings.Contains(a, "text/event-stream") {
http.Error(w, "This endpoint requires an EventSource connection", http.StatusNotAcceptable)
return
}
f, ok := w.(http.Flusher)
if !ok {
respondError(w, errors.New("streaming unsupported"))
return
}
ctx := r.Context()
authUserID := ctx.Value(keyAuthUserID).(string)
h := w.Header()
h.Set("Cache-Control", "no-cache")
h.Set("Connection", "keep-alive")
h.Set("Content-Type", "text/event-stream")
messages := make(chan Message)
defer close(messages)
client := &MessageClient{Messages: messages, UserID: authUserID}
messageClients.Store(client, nil)
defer messageClients.Delete(client)
for {
select {
case <-ctx.Done():
return
case message := <-messages:
if b, err := json.Marshal(message); err != nil {
log.Printf("could not marshall message: %v\n", err)
fmt.Fprintf(w, "event: error\ndata: %v\n\n", err)
} else {
fmt.Fprintf(w, "data: %s\n\n", b)
}
f.Flush()
}
}
}
```
首先,它检查请求头是否正确,并检查服务器是否支持流式传输。我们创建一个消息通道,用它来构建一个客户端,并将其存储在客户端映射中。每当创建新消息时,它都会进入这个通道,因此我们可以通过 `for-select` 循环从中读取。
<ruby>服务器发送事件<rt>Server-Sent Events</rt></ruby>使用以下格式发送数据:
```go
data: some data here\n\n
```
我们以 JSON 格式发送:
```json
data: {"foo":"bar"}\n\n
```
我们使用 `fmt.Fprintf()` 以这种格式写入响应<ruby>写入器<rt>writter</rt></ruby>,并在循环的每次迭代中刷新数据。
这个循环会一直运行,直到使用请求上下文关闭连接为止。我们延迟了通道的关闭和客户端的删除,因此,当循环结束时,通道将被关闭,客户端不会收到更多的消息。
注意,<ruby>服务器发送事件<rt>Server-Sent Events</rt></ruby>EventSource的 JavaScript API 不支持设置自定义请求头😒,所以我们不能设置 `Authorization: Bearer <token>`。这就是为什么 `guard()` 中间件也会从 URL 查询字符串中读取令牌的原因。
* * *
实时消息部分到此结束。我想说的是,这就是后端的全部内容。但是为了编写前端代码,我将再增加一个登录端点:一个仅用于开发的登录。
- [源代码][7]
--------------------------------------------------------------------------------
via: https://nicolasparada.netlify.com/posts/go-messenger-realtime-messages/
作者:[Nicolás Parada][a]
选题:[lujun9972][b]
译者:[gxlct008](https://github.com/gxlct008)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://nicolasparada.netlify.com/
[b]: https://github.com/lujun9972
[1]: https://linux.cn/article-11396-1.html
[2]: https://linux.cn/article-11510-1.html
[3]: https://linux.cn/article-12056-1.html
[4]: https://linux.cn/article-12680-1.html
[5]: https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events
[6]: https://developer.mozilla.org/en-US/docs/Web/API/EventSource
[7]: https://github.com/nicolasparada/go-messenger-demo

View File

@ -1,38 +1,38 @@
[#]: collector: (lujun9972)
[#]: translator: ( )
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )
[#]: translator: (gxlct008)
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-12692-1.html)
[#]: subject: (Building a Messenger App: Development Login)
[#]: via: (https://nicolasparada.netlify.com/posts/go-messenger-dev-login/)
[#]: author: (Nicolás Parada https://nicolasparada.netlify.com/)
Building a Messenger App: Development Login
构建一个即时消息应用(六):仅用于开发的登录
======
This post is the 6th on a series:
![](https://img.linux.net.cn/data/attachment/album/202010/07/101437garmhgi9aza9f9fz.jpg)
* [Part 1: Schema][1]
* [Part 2: OAuth][2]
* [Part 3: Conversations][3]
* [Part 4: Messages][4]
* [Part 5: Realtime Messages][5]
本文是该系列的第六篇。
* [第一篇: 模式][1]
* [第二篇: OAuth][2]
* [第三篇: 对话][3]
* [第四篇: 消息][4]
* [第五篇: 实时消息][5]
我们已经实现了通过 GitHub 登录,但是如果想把玩一下这个 app我们需要几个用户来测试它。在这篇文章中我们将添加一个为任何用户提供登录的端点只需提供用户名即可。该端点仅用于开发。
We already implemented login through GitHub, but if we want to play around with the app, we need a couple of users to test it. In this post well add an endpoint to login as any user just giving an username. This endpoint will be just for development.
首先在 `main()` 函数中添加此路由。
Start by adding this route in the `main()` function.
```
```go
router.HandleFunc("POST", "/api/login", requireJSON(login))
```
### Login
### 登录
This function handles POST requests to `/api/login` with a JSON body with just an username and returns the authenticated user, a token and expiration date of it in JSON format.
此函数处理对 `/api/login` 的 POST 请求,其中 JSON body 只包含用户名,并以 JSON 格式返回通过认证的用户、令牌和过期日期。
```
```go
func login(w http.ResponseWriter, r *http.Request) {
if origin.Hostname() != "localhost" {
http.NotFound(w, r)
@ -81,9 +81,9 @@ func login(w http.ResponseWriter, r *http.Request) {
}
```
First it checks we are on localhost or it responds with `404 Not Found`. It decodes the body skipping validation since this is just for development. Then it queries to the database for a user with the given username, if none is found, it returns with `404 Not Found`. Then it issues a new JSON web token using the user ID as Subject.
首先,它检查我们是否在本地主机上,或者响应为 `404 Not Found`。它解码主体跳过验证,因为这只是为了开发。然后在数据库中查询给定用户名的用户,如果没有,则返回 `404 NOT Found`。然后,它使用用户 ID 作为主题发布一个新的 JSON Web 令牌。
```
```go
func issueToken(subject string, exp time.Time) (string, error) {
token, err := jwtSigner.Encode(jwt.Claims{
Subject: subject,
@ -96,33 +96,33 @@ func issueToken(subject string, exp time.Time) (string, error) {
}
```
The function does the same we did [previously][2]. I just moved it to reuse code.
该函数执行的操作与 [前文][2] 相同。我只是将其移过来以重用代码。
After creating the token, it responds with the user, token and expiration date.
创建令牌后,它将使用用户、令牌和到期日期进行响应。
### Seed Users
### 种子用户
Now you can add users to play with to the database.
现在,你可以将要操作的用户添加到数据库中。
```
```sql
INSERT INTO users (id, username) VALUES
(1, 'john'),
(2, 'jane');
```
You can save it to a file and pipe it to the Cockroach CLI.
你可以将其保存到文件中,并通过管道将其传送到 Cockroach CLI。
```
```bash
cat seed_users.sql | cockroach sql --insecure -d messenger
```
* * *
Thats it. Once you deploy the code to production and use your own domain this login function wont be available.
就是这样。一旦将代码部署到生产环境并使用自己的域后,该登录功能将不可用。
This post concludes the backend.
本文也结束了所有的后端开发部分。
[Souce Code][6]
- [源代码][6]
--------------------------------------------------------------------------------
@ -130,16 +130,16 @@ via: https://nicolasparada.netlify.com/posts/go-messenger-dev-login/
作者:[Nicolás Parada][a]
选题:[lujun9972][b]
译者:[译者ID](https://github.com/译者ID)
校对:[校对者ID](https://github.com/校对者ID)
译者:[gxlct008](https://github.com/gxlct008)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://nicolasparada.netlify.com/
[b]: https://github.com/lujun9972
[1]: https://nicolasparada.netlify.com/posts/go-messenger-schema/
[2]: https://nicolasparada.netlify.com/posts/go-messenger-oauth/
[3]: https://nicolasparada.netlify.com/posts/go-messenger-conversations/
[4]: https://nicolasparada.netlify.com/posts/go-messenger-messages/
[5]: https://nicolasparada.netlify.com/posts/go-messenger-realtime-messages/
[1]: https://linux.cn/article-11396-1.html
[2]: https://linux.cn/article-11510-1.html
[3]: https://linux.cn/article-12056-1.html
[4]: https://linux.cn/article-12680-1.html
[5]: https://linux.cn/article-12685-1.html
[6]: https://github.com/nicolasparada/go-messenger-demo

View File

@ -1,31 +1,31 @@
[#]: collector: (lujun9972)
[#]: translator: ( )
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )
[#]: translator: (gxlct008)
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-12704-1.html)
[#]: subject: (Building a Messenger App: Access Page)
[#]: via: (https://nicolasparada.netlify.com/posts/go-messenger-access-page/)
[#]: author: (Nicolás Parada https://nicolasparada.netlify.com/)
Building a Messenger App: Access Page
构建一个即时消息应用Access 页面
======
This post is the 7th on a series:
![](https://img.linux.net.cn/data/attachment/album/202010/10/101345zj7gfybyee2g9x9e.jpg)
* [Part 1: Schema][1]
* [Part 2: OAuth][2]
* [Part 3: Conversations][3]
* [Part 4: Messages][4]
* [Part 5: Realtime Messages][5]
* [Part 6: Development Login][6]
本文是该系列的第七篇。
* [第一篇: 模式][1]
* [第二篇: OAuth][2]
* [第三篇: 对话][3]
* [第四篇: 消息][4]
* [第五篇: 实时消息][5]
* [第六篇: 仅用于开发的登录][6]
现在我们已经完成了后端,让我们转到前端。 我将采用单页应用程序方案。
Now that were done with the backend, lets move to the frontend. I will go with a single-page application.
首先,我们创建一个 `static/index.html` 文件,内容如下。
Lets start by creating a file `static/index.html` with the following content.
```
```html
<!DOCTYPE html>
<html lang="en">
<head>
@ -40,11 +40,11 @@ Lets start by creating a file `static/index.html` with the following content.
</html>
```
This HTML file must be server for every URL and JavaScript will take care of rendering the correct page.
这个 HTML 文件必须为每个 URL 提供服务,并且使用 JavaScript 负责呈现正确的页面。
So lets go the the `main.go` for a moment and in the `main()` function add the following route:
因此,让我们将注意力转到 `main.go` 片刻,然后在 `main()` 函数中添加以下路由:
```
```go
router.Handle("GET", "/...", http.FileServer(SPAFileSystem{http.Dir("static")}))
type SPAFileSystem struct {
@ -60,15 +60,15 @@ func (spa SPAFileSystem) Open(name string) (http.File, error) {
}
```
We use a custom file system so instead of returning `404 Not Found` for unknown URLs, it serves the `index.html`.
我们使用一个自定义的文件系统,因此它不是为未知的 URL 返回 `404 Not Found`,而是转到 `index.html`
### Router
### 路由器
In the `index.html` we loaded two files: `styles.css` and `main.js`. I leave styling to your taste.
`index.html` 中我们加载了两个文件:`styles.css` 和 `main.js`。我把样式留给你自由发挥。
Lets move to `main.js`. Create a `static/main.js` file with the following content:
让我们移动到 `main.js`。 创建一个包含以下内容的 `static/main.js` 文件:
```
```javascript
import { guard } from './auth.js'
import Router from './router.js'
@ -98,19 +98,19 @@ function view(pageName) {
}
```
If you are follower of this blog, you already know how this works. That router is the one showed [here][7]. Just download it from [@nicolasparada/router][8] and save it to `static/router.js`.
如果你是这个博客的关注者,你已经知道它是如何工作的了。 该路由器就是在 [这里][7] 显示的那个。 只需从 [@nicolasparada/router][8] 下载并保存到 `static/router.js` 即可。
We registered four routes. At the root `/` we show the home or access page whether the user is authenticated. At `/callback` we show the callback page. On `/conversations/{conversationID}` we show the conversation or access page whether the user is authenticated and for every other URL, we show a not found page.
我们注册了四条路由。 在根路由 `/` 处,我们展示 `home``access` 页面,无论用户是否通过身份验证。 在 `/callback` 中,我们展示 `callback` 页面。 在 `/conversations/{conversationID}` 上,我们展示对话或 `access` 页面,无论用户是否通过验证,对于其他 URL我们展示一个 `not-found` 页面。
We tell the router to render the result to the document body and dispatch a `disconnect` event to each page before leaving.
我们告诉路由器将结果渲染为文档主体,并在离开之前向每个页面调度一个 `disconnect` 事件。
We have each page in a different file and we import them with the new dynamic `import()`.
我们将每个页面放在不同的文件中,并使用新的动态 `import()` 函数导入它们。
### Auth
### 身份验证
`guard()` is a function that given two functions, executes the first one if the user is authenticated, or the sencond one if not. It comes from `auth.js` so lets create a `static/auth.js` file with the following content:
`guard()` 是一个函数,给它两个函数作为参数,如果用户通过了身份验证,则执行第一个函数,否则执行第二个。它来自 `auth.js`,所以我们创建一个包含以下内容的 `static/auth.js` 文件:
```
```javascript
export function isAuthenticated() {
const token = localStorage.getItem('token')
const expiresAtItem = localStorage.getItem('expires_at')
@ -150,17 +150,17 @@ export function getAuthUser() {
}
```
`isAuthenticated()` checks for `token` and `expires_at` from localStorage to tell if the user is authenticated. `getAuthUser()` gets the authenticated user from localStorage.
`isAuthenticated()` 检查 `localStorage` 中的 `token``expires_at`,以判断用户是否已通过身份验证。`getAuthUser()` 从 `localStorage` 中获取经过身份验证的用户。
When we login, well save all the data to localStorage so it will make sense.
当我们登录时,我们会将所有的数据保存到 `localStorage`,这样才有意义。
### Access Page
### Access 页面
![access page screenshot][9]
Lets start with the access page. Create a file `static/pages/access-page.js` with the following content:
让我们从 `access` 页面开始。 创建一个包含以下内容的文件 `static/pages/access-page.js`
```
```javascript
const template = document.createElement('template')
template.innerHTML = `
<h1>Messenger</h1>
@ -172,15 +172,15 @@ export default function accessPage() {
}
```
Because the router intercepts all the link clicks to do its navigation, we must prevent the event propagation for this link in particular.
因为路由器会拦截所有链接点击来进行导航,所以我们必须特别阻止此链接的事件传播。
Clicking on that link will redirect us to the backend, then to GitHub, then to the backend and then to the frontend again; to the callback page.
单击该链接会将我们重定向到后端,然后重定向到 GitHub再重定向到后端然后再次重定向到前端`callback` 页面。
### Callback Page
### Callback 页面
Create the file `static/pages/callback-page.js` with the following content:
创建包括以下内容的 `static/pages/callback-page.js` 文件:
```
```javascript
import http from '../http.js'
import { navigate } from '../router.js'
@ -211,13 +211,13 @@ function getAuthUser(token) {
}
```
The callback page doesnt render anything. Its an async function that does a GET request to `/api/auth_user` using the token from the URL query string and saves all the data to localStorage. Then it redirects to `/`.
`callback` 页面不呈现任何内容。这是一个异步函数,它使用 URL 查询字符串中的 token 向 `/api/auth_user` 发出 GET 请求,并将所有数据保存到 `localStorage`。 然后重定向到 `/`
### HTTP
There is an HTTP module. Create a `static/http.js` file with the following content:
这里是一个 HTTP 模块。 创建一个包含以下内容的 `static/http.js` 文件:
```
```javascript
import { isAuthenticated } from './auth.js'
async function handleResponse(res) {
@ -297,15 +297,15 @@ export default {
}
```
This module is a wrapper around the [fetch][10] and [EventSource][11] APIs. The most important part is that it adds the JSON web token to the requests.
这个模块是 [fetch][10] 和 [EventSource][11] API 的包装器。最重要的部分是它将 JSON web 令牌添加到请求中。
### Home Page
### Home 页面
![home page screenshot][12]
So, when the user login, the home page will be shown. Create a `static/pages/home-page.js` file with the following content:
因此,当用户登录时,将显示 `home` 页。 创建一个具有以下内容的 `static/pages/home-page.js` 文件:
```
```javascript
import { getAuthUser } from '../auth.js'
import { avatar } from '../shared.js'
@ -334,15 +334,15 @@ function onLogoutClick() {
}
```
For this post, this is the only content we render on the home page. We show the current authenticated user and a logout button.
对于这篇文章,这是我们在 `home` 页上呈现的唯一内容。我们显示当前经过身份验证的用户和注销按钮。
When the user clicks to logout, we clear all inside localStorage and do a reload of the page.
当用户单击注销时,我们清除 `localStorage` 中的所有内容并重新加载页面。
### Avatar
That `avatar()` function is to show the users avatar. Because its used in more than one place, I moved it to a `shared.js` file. Create the file `static/shared.js` with the following content:
那个 `avatar()` 函数用于显示用户的头像。 由于已在多个地方使用,因此我将它移到 `shared.js` 文件中。 创建具有以下内容的文件 `static/shared.js`
```
```javascript
export function avatar(user) {
return user.avatarUrl === null
? `<figure class="avatar" data-initial="${user.username[0]}"></figure>`
@ -350,23 +350,23 @@ export function avatar(user) {
}
```
We use a small figure with the users initial in case the avatar URL is null.
如果头像网址为 `null`,我们将使用用户的姓名首字母作为初始头像。
You can show the initial with a little of CSS using the `attr()` function.
你可以使用 `attr()` 函数显示带有少量 CSS 样式的首字母。
```
```css
.avatar[data-initial]::after {
content: attr(data-initial);
}
```
### Development Login
### 仅开发使用的登录
![access page with login form screenshot][13]
In the previous post we coded a login for development. Lets add a form for that in the access page. Go to `static/pages/access-page.js` and modify it a little.
在上一篇文章中,我们为编写了一个登录代码。让我们在 `access` 页面中为此添加一个表单。 进入 `static/ages/access-page.js`,稍微修改一下。
```
```javascript
import http from '../http.js'
const template = document.createElement('template')
@ -420,15 +420,15 @@ function login(username) {
}
```
I added a login form. When the user submits the form. It does a POST requets to `/api/login` with the username. Saves all the data to localStorage and reloads the page.
我添加了一个登录表单。当用户提交表单时。它使用用户名对 `/api/login` 进行 POST 请求。将所有数据保存到 `localStorage` 并重新加载页面。
Remember to remove this form once you are done with the frontend.
记住在前端完成后删除此表单。
* * *
Thats all for this post. In the next one, well continue with the home page to add a form to start conversations and display a list with the latest ones.
这就是这篇文章的全部内容。在下一篇文章中,我们将继续使用主页添加一个表单来开始对话,并显示包含最新对话的列表。
[Souce Code][14]
- [源代码][14]
--------------------------------------------------------------------------------
@ -436,19 +436,19 @@ via: https://nicolasparada.netlify.com/posts/go-messenger-access-page/
作者:[Nicolás Parada][a]
选题:[lujun9972][b]
译者:[译者ID](https://github.com/译者ID)
校对:[校对者ID](https://github.com/校对者ID)
译者:[gxlct008](https://github.com/gxlct008)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://nicolasparada.netlify.com/
[b]: https://github.com/lujun9972
[1]: https://nicolasparada.netlify.com/posts/go-messenger-schema/
[2]: https://nicolasparada.netlify.com/posts/go-messenger-oauth/
[3]: https://nicolasparada.netlify.com/posts/go-messenger-conversations/
[4]: https://nicolasparada.netlify.com/posts/go-messenger-messages/
[5]: https://nicolasparada.netlify.com/posts/go-messenger-realtime-messages/
[6]: https://nicolasparada.netlify.com/posts/go-messenger-dev-login/
[1]: https://linux.cn/article-11396-1.html
[2]: https://linux.cn/article-11510-1.html
[3]: https://linux.cn/article-12056-1.html
[4]: https://linux.cn/article-12680-1.html
[5]: https://linux.cn/article-12685-1.html
[6]: https://linux.cn/article-12692-1.html
[7]: https://nicolasparada.netlify.com/posts/js-router/
[8]: https://unpkg.com/@nicolasparada/router
[9]: https://nicolasparada.netlify.com/img/go-messenger-access-page/access-page.png

View File

@ -1,50 +1,50 @@
[#]: collector: (lujun9972)
[#]: translator: ( )
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )
[#]: translator: (gxlct008)
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-12722-1.html)
[#]: subject: (Building a Messenger App: Home Page)
[#]: via: (https://nicolasparada.netlify.com/posts/go-messenger-home-page/)
[#]: author: (Nicolás Parada https://nicolasparada.netlify.com/)
Building a Messenger App: Home Page
构建一个即时消息应用Home 页面
======
This post is the 8th on a series:
![](https://img.linux.net.cn/data/attachment/album/202010/15/213116evlwzdwwv66kmldj.jpg)
* [Part 1: Schema][1]
* [Part 2: OAuth][2]
* [Part 3: Conversations][3]
* [Part 4: Messages][4]
* [Part 5: Realtime Messages][5]
* [Part 6: Development Login][6]
* [Part 7: Access Page][7]
本文是该系列的第八篇。
* [第一篇: 模式][1]
* [第二篇: OAuth][2]
* [第三篇: 对话][3]
* [第四篇: 消息][4]
* [第五篇: 实时消息][5]
* [第六篇: 仅用于开发的登录][6]
* [第七篇: Access 页面][7]
继续前端部分,让我们在本文中完成 `home` 页面的开发。 我们将添加一个开始对话的表单和一个包含最新对话的列表。
Continuing the frontend, lets finish the home page in this post. Well add a form to start conversations and a list with the latest ones.
### Conversation Form
### 对话表单
![conversation form screenshot][8]
In the `static/pages/home-page.js` file add some markup in the HTML view.
转到 `static/ages/home-page.js` 文件,在 HTML 视图中添加一些标记。
```
```html
<form id="conversation-form">
<input type="search" placeholder="Start conversation with..." required>
</form>
```
Add that form just below the section in which we displayed the auth user and logout button.
将该表单添加到我们显示 “auth user” 和 “logout” 按钮部分的下方。
```
```js
page.getElementById('conversation-form').onsubmit = onConversationSubmit
```
Now we can listen to the “submit” event to create the conversation.
现在我们可以监听 “submit” 事件来创建对话了。
```
```js
import http from '../http.js'
import { navigate } from '../router.js'
@ -79,15 +79,15 @@ function createConversation(username) {
}
```
On submit we do a POST request to `/api/conversations` with the username and redirect to the conversation page (for the next post).
在提交时,我们使用用户名对 `/api/conversations` 进行 POST 请求,并重定向到 `conversation` 页面(用于下一篇文章)。
### Conversation List
### 对话列表
![conversation list screenshot][9]
In the same file, we are going to make the `homePage()` function async to load the conversations first.
还是在这个文件中,我们将创建 `homePage()` 函数用来先异步加载对话。
```
```js
export default async function homePage() {
const conversations = await getConversations().catch(err => {
console.error(err)
@ -101,24 +101,24 @@ function getConversations() {
}
```
Then, add a list in the markup to render conversations there.
然后,在标记中添加一个列表来渲染对话。
```
```html
<ol id="conversations"></ol>
```
Add it just below the current markup.
将其添加到当前标记的正下方。
```
```js
const conversationsOList = page.getElementById('conversations')
for (const conversation of conversations) {
conversationsOList.appendChild(renderConversation(conversation))
}
```
So we can append each conversation to the list.
因此,我们可以将每个对话添加到这个列表中。
```
```js
import { avatar, escapeHTML } from '../shared.js'
function renderConversation(conversation) {
@ -146,11 +146,11 @@ function renderConversation(conversation) {
}
```
Each conversation item contains a link to the conversation page and displays the other participant info and a preview of the last message. Also, you can use `.hasUnreadMessages` to add a class to the item and do some styling with CSS. Maybe a bolder font or accent the color.
每个对话条目都包含一个指向对话页面的链接,并显示其他参与者信息和最后一条消息的预览。另外,您可以使用 `.hasUnreadMessages` 向该条目添加一个类,并使用 CSS 进行一些样式设置。也许是粗体字体或强调颜色。
Note that were escaping the message content. That function comes from `static/shared.js`:
请注意,我们需要转义信息的内容。该函数来自于 `static/shared.js` 文件:
```
```js
export function escapeHTML(str) {
return str
.replace(/&/g, '&amp;')
@ -161,35 +161,34 @@ export function escapeHTML(str) {
}
```
That prevents displaying as HTML the message the user wrote. If the user happens to write something like:
这会阻止将用户编写的消息显示为 HTML。如果用户碰巧编写了类似以下内容的代码
```
```js
<script>alert('lololo')</script>
```
It would be very annoying because that script will be executed 😅
So yeah, always remember to escape content from untrusted sources.
这将非常烦人,因为该脚本将被执行😅。所以,永远记住要转义来自不可信来源的内容。
### Messages Subscription
### 消息订阅
Last but not least, I want to subscribe to the message stream here.
最后但并非最不重要的一点,我想在这里订阅消息流。
```
```js
const unsubscribe = subscribeToMessages(onMessageArrive)
page.addEventListener('disconnect', unsubscribe)
```
Add that line in the `homePage()` function.
`homePage()` 函数中添加这一行。
```
```js
function subscribeToMessages(cb) {
return http.subscribe('/api/messages', cb)
}
```
The `subscribe()` function returns a function that once called it closes the underlying connection. Thats why I passed it to the “disconnect” event; so when the user leaves the page, the event stream will be closed.
函数 `subscribe()` 返回一个函数,该函数一旦调用就会关闭底层连接。这就是为什么我把它传递给 <ruby>“断开连接”<rt>disconnect</rt></ruby>事件的原因;因此,当用户离开页面时,事件流将被关闭。
```
```js
async function onMessageArrive(message) {
const conversationLI = document.querySelector(`li[data-id="${message.conversationID}"]`)
if (conversationLI !== null) {
@ -221,14 +220,14 @@ function getConversation(id) {
}
```
Every time a new message arrives, we go and query for the conversation item in the DOM. If found, we add the `has-unread-messages` class to the item, and update the view. If not found, it means the message is from a new conversation created just now. We go and do a GET request to `/api/conversations/{conversationID}` to get the conversation in which the message was created and prepend it to the conversation list.
每次有新消息到达时,我们都会在 DOM 中查询会话条目。如果找到,我们会将 `has-unread-messages` 类添加到该条目中,并更新视图。如果未找到,则表示该消息来自刚刚创建的新对话。我们去做一个对 `/api/conversations/{conversationID}` 的 GET 请求,以获取在其中创建消息的对话,并将其放在对话列表的前面。
* * *
That covers the home page 😊
On the next post well code the conversation page.
以上这些涵盖了主页的所有内容 😊。
在下一篇文章中,我们将对 conversation 页面进行编码。
[Souce Code][10]
- [源代码][10]
--------------------------------------------------------------------------------
@ -236,20 +235,20 @@ via: https://nicolasparada.netlify.com/posts/go-messenger-home-page/
作者:[Nicolás Parada][a]
选题:[lujun9972][b]
译者:[译者ID](https://github.com/译者ID)
校对:[校对者ID](https://github.com/校对者ID)
译者:[gxlct008](https://github.com/gxlct008)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://nicolasparada.netlify.com/
[b]: https://github.com/lujun9972
[1]: https://nicolasparada.netlify.com/posts/go-messenger-schema/
[2]: https://nicolasparada.netlify.com/posts/go-messenger-oauth/
[3]: https://nicolasparada.netlify.com/posts/go-messenger-conversations/
[4]: https://nicolasparada.netlify.com/posts/go-messenger-messages/
[5]: https://nicolasparada.netlify.com/posts/go-messenger-realtime-messages/
[6]: https://nicolasparada.netlify.com/posts/go-messenger-dev-login/
[7]: https://nicolasparada.netlify.com/posts/go-messenger-access-page/
[1]: https://linux.cn/article-11396-1.html
[2]: https://linux.cn/article-11510-1.html
[3]: https://linux.cn/article-12056-1.html
[4]: https://linux.cn/article-12680-1.html
[5]: https://linux.cn/article-12685-1.html
[6]: https://linux.cn/article-12692-1.html
[7]: https://linux.cn/article-12704-1.html
[8]: https://nicolasparada.netlify.com/img/go-messenger-home-page/conversation-form.png
[9]: https://nicolasparada.netlify.com/img/go-messenger-home-page/conversation-list.png
[10]: https://github.com/nicolasparada/go-messenger-demo

View File

@ -1,37 +1,37 @@
[#]: collector: (lujun9972)
[#]: translator: ( )
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )
[#]: translator: (gxlct008)
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-12723-1.html)
[#]: subject: (Building a Messenger App: Conversation Page)
[#]: via: (https://nicolasparada.netlify.com/posts/go-messenger-conversation-page/)
[#]: author: (Nicolás Parada https://nicolasparada.netlify.com/)
Building a Messenger App: Conversation Page
构建一个即时消息应用Conversation 页面
======
This post is the 9th and last in a series:
![](https://img.linux.net.cn/data/attachment/album/202010/15/220239arr978u7t7oulv73.jpg)
* [Part 1: Schema][1]
* [Part 2: OAuth][2]
* [Part 3: Conversations][3]
* [Part 4: Messages][4]
* [Part 5: Realtime Messages][5]
* [Part 6: Development Login][6]
* [Part 7: Access Page][7]
* [Part 8: Home Page][8]
本文是该系列的第九篇,也是最后一篇。
* [第一篇: 模式][1]
* [第二篇: OAuth][2]
* [第三篇: 对话][3]
* [第四篇: 消息][4]
* [第五篇: 实时消息][5]
* [第六篇: 仅用于开发的登录][6]
* [第七篇: Access 页面][7]
* [第八篇: Home 页面][8]
在这篇文章中,我们将对<ruby>对话<rt>conversation</rt></ruby>页面进行编码。此页面是两个用户之间的聊天室。在顶部我们将显示其他参与者的信息,下面接着的是最新消息列表,以及底部的消息表单。
In this post well code the conversation page. This page is the chat between the two users. At the top well show info about the other participant, below, a list of the latest messages and a message form at the bottom.
### Chat heading
### 聊天标题
![chat heading screenshot][9]
Lets start by creating the file `static/pages/conversation-page.js` with the following content:
让我们从创建 `static/pages/conversation-page.js` 文件开始,它包含以下内容:
```
```js
import http from '../http.js'
import { navigate } from '../router.js'
import { avatar, escapeHTML } from '../shared.js'
@ -65,17 +65,17 @@ function getConversation(id) {
}
```
This page receives the conversation ID the router extracted from the URL.
此页面接收路由从 URL 中提取的会话 ID。
First it does a GET request to `/api/conversations/{conversationID}` to get info about the conversation. In case of error, we show it and redirect back to `/`. Then we render info about the other participant.
首先,它向 `/api/ conversations/{conversationID}` 发起一个 GET 请求,以获取有关对话的信息。 如果出现错误,我们会将其显示,并重定向回 `/`。然后我们呈现有关其他参与者的信息。
### Conversation List
### 对话列表
![chat heading screenshot][10]
Well fetch the latest messages too to display them.
我们也会获取最新的消息并显示它们。
```
```js
let conversation, messages
try {
[conversation, messages] = await Promise.all([
@ -85,32 +85,32 @@ try {
}
```
Update the `conversationPage()` function to fetch the messages too. We use `Promise.all()` to do both request at the same time.
更新 `conversationPage()` 函数以获取消息。我们使用 `Promise.all()` 同时执行这两个请求。
```
```js
function getMessages(conversationID) {
return http.get(`/api/conversations/${conversationID}/messages`)
}
```
A GET request to `/api/conversations/{conversationID}/messages` gets the latest messages of the conversation.
发起对 `/api/conversations/{conversationID}/messages` 的 GET 请求可以获取对话中的最新消息。
```
```html
<ol id="messages"></ol>
```
Now, add that list to the markup.
现在,将该列表添加到标记中。
```
```js
const messagesOList = page.getElementById('messages')
for (const message of messages.reverse()) {
messagesOList.appendChild(renderMessage(message))
}
```
So we can append messages to the list. We show them in reverse order.
这样我们就可以将消息附加到列表中了。我们以时间倒序来显示它们。
```
```js
function renderMessage(message) {
const messageContent = escapeHTML(message.content)
const messageDate = new Date(message.createdAt).toLocaleString()
@ -127,28 +127,28 @@ function renderMessage(message) {
}
```
Each message item displays the message content itself with its timestamp. Using `.mine` we can append a different class to the item so maybe you can show the message to the right.
每个消息条目显示消息内容本身及其时间戳。使用 `.mine`,我们可以将不同的 css 类附加到条目,这样您就可以将消息显示在右侧。
### Message Form
### 消息表单
![chat heading screenshot][11]
```
```html
<form id="message-form">
<input type="text" placeholder="Type something" maxlength="480" required>
<button>Send</button>
</form>
```
Add that form to the current markup.
将该表单添加到当前标记中。
```
```js
page.getElementById('message-form').onsubmit = messageSubmitter(conversationID)
```
Attach an event listener to the “submit” event.
将事件监听器附加到 “submit” 事件。
```
```js
function messageSubmitter(conversationID) {
return async ev => {
ev.preventDefault()
@ -191,19 +191,20 @@ function createMessage(content, conversationID) {
}
```
We make use of [partial application][12] to have the conversation ID in the “submit” event handler. It takes the message content from the input and does a POST request to `/api/conversations/{conversationID}/messages` with it. Then prepends the newly created message to the list.
### Messages Subscription
我们利用 [partial application][12] 在 “submit” 事件处理程序中获取对话 ID。它 从输入中获取消息内容,并用它对 `/api/conversations/{conversationID}/messages` 发出 POST 请求。 然后将新创建的消息添加到列表中。
To make it realtime well subscribe to the message stream in this page also.
### 消息订阅
```
为了实现实时,我们还将订阅此页面中的消息流。
```js
page.addEventListener('disconnect', subscribeToMessages(messageArriver(conversationID)))
```
Add that line in the `conversationPage()` function.
将该行添加到 `conversationPage()` 函数中。
```
```js
function subscribeToMessages(cb) {
return http.subscribe('/api/messages', cb)
}
@ -229,16 +230,15 @@ function readMessages(conversationID) {
}
```
We also make use of partial application to have the conversation ID here.
When a new message arrives, first we check if its from this conversation. If it is, we go a prepend a message item to the list and do a POST request to `/api/conversations/{conversationID}/read_messages` to updated the last time the participant read messages.
在这里我们仍然使用这个应用的部分来获取会话 ID。
当新消息到达时,我们首先检查它是否来自此对话。如果是,我们会将消息条目预先添加到列表中,并向 `/api/conversations/{conversationID}/read_messages` 发起 POST 一个请求,以更新参与者上次阅读消息的时间。
* * *
That concludes this series. The messenger app is now functional.
本系列到此结束。 消息应用现在可以运行了。
~~Ill add pagination on the conversation and message list, also user searching before sharing the source code. Ill updated once its ready along with a hosted demo 👨‍💻~~
[Souce Code][13] • [Demo][14]
- [源代码][13]
- [演示][14]
--------------------------------------------------------------------------------
@ -246,21 +246,21 @@ via: https://nicolasparada.netlify.com/posts/go-messenger-conversation-page/
作者:[Nicolás Parada][a]
选题:[lujun9972][b]
译者:[译者ID](https://github.com/译者ID)
校对:[校对者ID](https://github.com/校对者ID)
译者:[gxlct008](https://github.com/gxlct008)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://nicolasparada.netlify.com/
[b]: https://github.com/lujun9972
[1]: https://nicolasparada.netlify.com/posts/go-messenger-schema/
[2]: https://nicolasparada.netlify.com/posts/go-messenger-oauth/
[3]: https://nicolasparada.netlify.com/posts/go-messenger-conversations/
[4]: https://nicolasparada.netlify.com/posts/go-messenger-messages/
[5]: https://nicolasparada.netlify.com/posts/go-messenger-realtime-messages/
[6]: https://nicolasparada.netlify.com/posts/go-messenger-dev-login/
[7]: https://nicolasparada.netlify.com/posts/go-messenger-access-page/
[8]: https://nicolasparada.netlify.com/posts/go-messenger-home-page/
[1]: https://linux.cn/article-11396-1.html
[2]: https://linux.cn/article-11510-1.html
[3]: https://linux.cn/article-12056-1.html
[4]: https://linux.cn/article-12680-1.html
[5]: https://linux.cn/article-12685-1.html
[6]: https://linux.cn/article-12692-1.html
[7]: https://linux.cn/article-12704-1.html
[8]: https://linux.cn/article-12722-1.html
[9]: https://nicolasparada.netlify.com/img/go-messenger-conversation-page/heading.png
[10]: https://nicolasparada.netlify.com/img/go-messenger-conversation-page/list.png
[11]: https://nicolasparada.netlify.com/img/go-messenger-conversation-page/form.png

View File

@ -0,0 +1,273 @@
[#]: collector: (lujun9972)
[#]: translator: (gxlct008)
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-12737-1.html)
[#]: subject: (Using Yarn on Ubuntu and Other Linux Distributions)
[#]: via: (https://itsfoss.com/install-yarn-ubuntu)
[#]: author: (Abhishek Prakash https://itsfoss.com/author/abhishek/)
在 Ubuntu 和其他 Linux 发行版上使用 Yarn
======
> 本速成教程向你展示了在 Ubuntu 和 Debian Linux 上安装 Yarn 包管理器的官方方法。你还将学习到一些基本的 Yarn 命令以及彻底删除 Yarn 的步骤。
[Yarn][1] 是 Facebook 开发的开源 JavaScript 包管理器。它是流行的 npm 包管理器的一个替代品,或者应该说是改进。 [Facebook 开发团队][2] 创建 Yarn 是为了克服 [npm][3] 的缺点。 Facebook 声称 Yarn 比 npm 更快、更可靠、更安全。
与 npm 一样Yarn 为你提供一种自动安装、更新、配置和删除从全局注册库中检索到的程序包的方法。
Yarn 的优点是它更快因为它可以缓存已下载的每个包所以无需再次下载。它还将操作并行化以最大化资源利用率。在执行每个已安装的包代码之前Yarn 还使用 [校验和来验证完整性][4]。 Yarn 还保证可以在一个系统上运行的安装,在任何其他系统上都会以完全相同地方式工作。
如果你正 [在 Ubuntu 上使用 node.js][5],那么你的系统上可能已经安装了 npm。在这种情况下你可以使用 npm 通过以下方式全局安装 Yarn
```
sudo npm install yarn -g
```
不过,我推荐使用官方方式在 Ubuntu/Debian 上安装 Yarn。
### 在 Ubuntu 和 Debian 上安装 Yarn [官方方式]
![Yarn JS][6]
这里提到的说明应该适用于所有版本的 Ubuntu例如 Ubuntu 18.04、16.04 等。同样的一组说明也适用于 Debian 和其他基于 Debian 的发行版。
由于本教程使用 `curl` 来添加 Yarn 项目的 GPG 密钥,所以最好验证一下你是否已经安装了 `curl`
```
sudo apt install curl
```
如果 `curl` 尚未安装,则上面的命令将安装它。既然有了 `curl`,你就可以使用它以如下方式添加 Yarn 项目的 GPG 密钥:
```
curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
```
在此之后,将存储库添加到源列表中,以便将来可以轻松地升级 Yarn 包,并进行其余系统更新:
```
sudo sh -c 'echo "deb https://dl.yarnpkg.com/debian/ stable main" >> /etc/apt/sources.list.d/yarn.list'
```
你现在可以继续了。[更新 Ubuntu][7] 或 Debian 系统,以刷新可用软件包列表,然后安装 Yarn
```
sudo apt update
sudo apt install yarn
```
这将一起安装 Yarn 和 node.js。该过程完成后请验证是否已成功安装 Yarn。 你可以通过检查 Yarn 版本来做到这一点。
```
yarn --version
```
对我来说,它显示了这样的输出:
```
yarn --version
1.12.3
```
这意味着我的系统上安装了 Yarn 版本 1.12.3。
### 使用 Yarn
我假设你对 JavaScript 编程以及依赖项的工作原理有一些基本的了解。我在这里不做详细介绍。我将向你展示一些基本的 Yarn 命令,这些命令将帮助你入门。
#### 使用 Yarn 创建一个新项目
`npm` 一样Yarn 也可以使用 `package.json` 文件。在这里添加依赖项。所有依赖包都缓存在项目根目录下的 `node_modules` 目录中。
在项目的根目录中,运行以下命令以生成新的 `package.json` 文件:
它会问你一些问题。你可以按回车键跳过或使用默认值。
```
yarn init
yarn init v1.12.3
question name (test_yarn): test_yarn_proect
question version (1.0.0): 0.1
question description: Test Yarn
question entry point (index.js):
question repository url:
question author: abhishek
question license (MIT):
question private:
success Saved package.json
Done in 82.42s.
```
这样,你就得到了一个如下的 `package.json` 文件:
```
{
"name": "test_yarn_proect",
"version": "0.1",
"description": "Test Yarn",
"main": "index.js",
"author": "abhishek",
"license": "MIT"
}
```
现在你有了 `package.json`,你可以手动编辑它以添加或删除包依赖项,也可以使用 Yarn 命令(首选)。
#### 使用 Yarn 添加依赖项
你可以通过以下方式添加对特定包的依赖关系:
```
yarn add <包名>
```
例如,如果你想在项目中使用 [Lodash][8],则可以使用 Yarn 添加它,如下所示:
```
yarn add lodash
yarn add v1.12.3
info No lockfile found.
[1/4] Resolving packages…
[2/4] Fetching packages…
[3/4] Linking dependencies…
[4/4] Building fresh packages…
success Saved lockfile.
success Saved 1 new dependency.
info Direct dependencies
└─ [email protected]
info All dependencies
└─ [email protected]
Done in 2.67s.
```
你可以看到,此依赖项已自动添加到 `package.json` 文件中:
```
{
"name": "test_yarn_proect",
"version": "0.1",
"description": "Test Yarn",
"main": "index.js",
"author": "abhishek",
"license": "MIT",
"dependencies": {
"lodash": "^4.17.11"
}
}
```
默认情况下Yarn 将在依赖项中添加最新版本的包。如果要使用特定版本,可以在添加时指定。
```
yarn add package@version-or-tag
```
像往常一样,你也可以手动更新 `package.json` 文件。
#### 使用 Yarn 升级依赖项
你可以使用以下命令将特定依赖项升级到其最新版本:
```
yarn upgrade <包名>
```
它将查看所​​涉及的包是否具有较新的版本,并且会相应地对其进行更新。
你还可以通过以下方式更改已添加的依赖项的版本:
```
yarn upgrade package_name@version_or_tag
```
你还可以使用一个命令将项目的所有依赖项升级到它们的最新版本:
```
yarn upgrade
```
它将检查所有依赖项的版本,如果有任何较新的版本,则会更新它们。
#### 使用 Yarn 删除依赖项
你可以通过以下方式从项目的依赖项中删除包:
```
yarn remove <包名>
```
#### 安装所有项目依赖项
如果对你 `project.json` 文件进行了任何更改,则应该运行:
```
yarn
```
或者,
```
yarn install
```
一次安装所有依赖项。
### 如何从 Ubuntu 或 Debian 中删除 Yarn
我将通过介绍从系统中删除 Yarn 的步骤来完成本教程,如果你使用上述步骤安装 Yarn 的话。如果你意识到不再需要 Yarn 了,则可以将它删除。
使用以下命令删除 Yarn 及其依赖项。
```
sudo apt purge yarn
```
你也应该从源列表中把存储库信息一并删除掉:
```
sudo rm /etc/apt/sources.list.d/yarn.list
```
下一步删除已添加到受信任密钥的 GPG 密钥是可选的。但要做到这一点,你需要知道密钥。你可以使用 `apt-key` 命令获得它:
```
Warning: apt-key output should not be parsed (stdout is not a terminal) pub rsa4096 2016-10-05 [SC] 72EC F46A 56B4 AD39 C907 BBB7 1646 B01B 86E5 0310 uid [ unknown] Yarn Packaging yarn@dan.cx sub rsa4096 2016-10-05 [E] sub rsa4096 2019-01-02 [S] [expires: 2020-02-02]
```
这里的密钥是以 `pub` 开始的行中 GPG 密钥指纹的最后 8 个字符。
因此,对于我来说,密钥是 `86E50310`,我将使用以下命令将其删除:
```
sudo apt-key del 86E50310
```
你会在输出中看到 `OK`,并且 Yarn 包的 GPG 密钥将从系统信任的 GPG 密钥列表中删除。
我希望本教程可以帮助你在 Ubuntu、Debian、Linux Mint、 elementary OS 等操作系统上安装 Yarn。 我提供了一些基本的 Yarn 命令,以帮助你入门,并完成了从系统中删除 Yarn 的完整步骤。
希望你喜欢本教程,如果有任何疑问或建议,请随时在下面留言。
--------------------------------------------------------------------------------
via: https://itsfoss.com/install-yarn-ubuntu
作者:[Abhishek Prakash][a]
选题:[lujun9972][b]
译者:[gxlct008](https://github.com/gxlct008)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://itsfoss.com/author/abhishek/
[b]: https://github.com/lujun9972
[1]: https://yarnpkg.com/lang/en/
[2]: https://code.fb.com/
[3]: https://www.npmjs.com/
[4]: https://itsfoss.com/checksum-tools-guide-linux/
[5]: https://itsfoss.com/install-nodejs-ubuntu/
[6]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2019/01/yarn-js-ubuntu-debian.jpeg?resize=800%2C450&ssl=1
[7]: https://itsfoss.com/update-ubuntu/
[8]: https://lodash.com/

View File

@ -0,0 +1,221 @@
[#]: collector: (lujun9972)
[#]: translator: (rakino)
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-12689-1.html)
[#]: subject: (How to Disable IPv6 on Ubuntu Linux)
[#]: via: (https://itsfoss.com/disable-ipv6-ubuntu-linux/)
[#]: author: (Sergiu https://itsfoss.com/author/sergiu/)
如何在 Ubuntu Linux 上禁用 IPv6
======
想知道怎样在 Ubuntu 上**禁用 IPv6** 吗?我会在这篇文章中介绍一些方法,以及为什么你应该考虑这一选择;以防改变主意,我也会提到如何**启用,或者说重新启用 IPv6**。
### 什么是 IPv6为什么会想要禁用它
<ruby>[互联网协议第 6 版][1]<rt>Internet Protocol version 6</rt></ruby>IPv6是互联网协议IP的最新版本。互联网协议是一种通信协议它为网络上的计算机提供识别和定位系统并在互联网上进行通信路由。IPv6 于 1998 年设计,以取代 IPv4 协议。
**IPv6** 意在提高安全性与性能的同时保证地址不被用尽;它可以在全球范围内为每台设备分配唯一的以 **128 位比特**存储的地址,而 IPv4 只使用了 32 位比特。
![Disable IPv6 Ubuntu][2]
尽管 IPv6 的目标是取代 IPv4但目前还有很长的路要走互联网上只有不到 **30%** 的网站支持 IPv6[这里][3] 是谷歌的统计IPv6 有时也给 [一些应用带来问题][4]。
由于 IPv6 使用全球(唯一分配的)路由地址,以及(仍然)有<ruby>互联网服务供应商<rt>Internet Service Provider</rt></ruby>ISP不提供 IPv6 支持的事实IPv6 这一功能在提供全球服务的<ruby>**虚拟私人网络**<rt>Virtual Private Network</rt></ruby>VPN供应商的优先级列表中处于较低的位置这样一来他们就可以专注于对 VPN 用户最重要的事情:安全。
不想让自己暴露在各种威胁之下可能是另一个让你想在系统上禁用 IPv6 的原因。虽然 IPv6 本身比 IPv4 更安全,但我所指的风险是另一种性质上的。如果你不实际使用 IPv6 及其功能,那么[启用 IPv6 后,你会很容易受到各种攻击][5],因而为黑客提供另一种可能的利用工具。
同样,只配置基本的网络规则是不够的;你必须像对 IPv4 一样,对调整 IPv6 的配置给予同样的关注,这可能会是一件相当麻烦的事情(维护也是)。并且随着 IPv6 而来的将会是一套不同于 IPv4 的问题(鉴于这个协议的年龄,许多问题已经可以在网上找到了),这又会使你的系统多了一层复杂性。
据观察,在某些情况下,禁用 IPv6 有助于提高 Ubuntu 的 WiFi 速度。
### 在 Ubuntu 上禁用 IPv6 [高级用户]
在本节中,我会详述如何在 Ubuntu 上禁用 IPv6 协议,请打开终端(默认快捷键:`CTRL+ALT+T`),让我们开始吧!
**注意:** 接下来大部分输入终端的命令都需要 root 权限(`sudo`)。
> 警告!
>
> 如果你是一个普通 Linux 桌面用户,并且偏好稳定的工作系统,请避开本教程,接下来的部分是为那些知道自己在做什么以及为什么要这么做的用户准备的。
#### 1、使用 sysctl 禁用 IPv6
首先,可以执行以下命令来**检查** IPv6 是否已经启用:
```
ip a
```
如果启用了,你应该会看到一个 IPv6 地址(网卡的名字可能会与图中有所不同)
![IPv6 Address Ubuntu][7]
在教程《[在 Ubuntu 中重启网络][8]》LCTT 译注:其实这篇文章并没有提到使用 sysctl 的方法……)中,你已经见过 `sysctl` 命令了,在这里我们也同样会用到它。要**禁用 IPv6**,只需要输入三条命令:
```
sudo sysctl -w net.ipv6.conf.all.disable_ipv6=1
sudo sysctl -w net.ipv6.conf.default.disable_ipv6=1
sudo sysctl -w net.ipv6.conf.lo.disable_ipv6=1
```
检查命令是否生效:
```
ip a
```
如果命令生效,你应该会发现 IPv6 的条目消失了:
![IPv6 Disabled Ubuntu][9]
然而这种方法只能**临时禁用 IPv6**因此在下次系统启动的时候IPv6 仍然会被启用。
LCTT 译注:这里的临时禁用是指这次所做的改变直到此次关机之前都有效,因为相关的参数是存储在内存中的,可以改变值,但是在内存断电后就会丢失;这种意义上来讲,下文所述的两种方法都是临时的,只不过改变参数值的时机是在系统启动的早期,并且每次系统启动时都有应用而已。那么如何完成这种意义上的永久改变?答案是在编译内核的时候禁用相关功能,然后要后悔就只能重新编译内核了(悲)。)
一种让选项持续生效的方式是修改文件 `/etc/sysctl.conf`,在这里我用 `vim` 来编辑文件,不过你可以使用任何你想使用的编辑器,以及请确保你拥有**管理员权限**(用 `sudo`
![Sysctl Configuration][10]
将下面这几行(和之前使用的参数相同)加入到文件中:
```
net.ipv6.conf.all.disable_ipv6=1
net.ipv6.conf.default.disable_ipv6=1
net.ipv6.conf.lo.disable_ipv6=1
```
执行以下命令应用设置:
```
sudo sysctl -p
```
如果在重启之后 IPv6 仍然被启用了,而你还想继续这种方法的话,那么你必须(使用 root 权限)创建文件 `/etc/rc.local` 并加入以下内容:
```
#!/bin/bash
# /etc/rc.local
/etc/sysctl.d
/etc/init.d/procps restart
exit 0
```
接着使用 [chmod 命令][11] 来更改文件权限,使其可执行:
```
sudo chmod 755 /etc/rc.local
```
这会让系统(在启动的时候)从之前编辑过的 sysctl 配置文件中读取内核参数。
#### 2、使用 GRUB 禁用 IPv6
另外一种方法是配置 **GRUB**,它会在系统启动时向内核传递参数。这样做需要编辑文件 `/etc/default/grub`(请确保拥有管理员权限)。
![GRUB Configuration][13]
现在需要修改文件中分别以 `GRUB_CMDLINE_LINUX_DEFAULT``GRUB_CMDLINE_LINUX` 开头的两行来在启动时禁用 IPv6
```
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash ipv6.disable=1"
GRUB_CMDLINE_LINUX="ipv6.disable=1"
```
LCTT 译注:这里是指在上述两行内增加参数 `ipv6.disable=1`,不同的系统中这两行的默认值可能有所不同。)
保存文件,然后执行命令:
```
sudo update-grub
```
LCTT 译注:该命令用以更新 GRUB 的配置文件,在没有 `update-grub` 命令的系统中需要使用 `sudo grub-mkconfig -o /boot/grub/grub.cfg`
设置会在重启后生效。
### 在 Ubuntu 上重新启用 IPv6
要想重新启用 IPv6你需要撤销之前的所有修改。不过只是想临时启用 IPv6 的话,可以执行以下命令:
```
sudo sysctl -w net.ipv6.conf.all.disable_ipv6=0
sudo sysctl -w net.ipv6.conf.default.disable_ipv6=0
sudo sysctl -w net.ipv6.conf.lo.disable_ipv6=0
```
否则想要持续启用的话,看看是否修改过 `/etc/sysctl.conf`,可以删除掉之前增加的部分,也可以将它们改为以下值(两种方法等效):
```
net.ipv6.conf.all.disable_ipv6=0
net.ipv6.conf.default.disable_ipv6=0
net.ipv6.conf.lo.disable_ipv6=0
```
然后应用设置(可选):
```
sudo sysctl -p
```
LCTT 译注:这里可选的意思可能是如果之前临时启用了 IPv6 就没必要再重新加载配置文件了)
这样应该可以再次看到 IPv6 地址了:
![IPv6 Reenabled in Ubuntu][14]
另外,你也可以删除之前创建的文件 `/etc/rc.local`(可选):
```
sudo rm /etc/rc.local
```
如果修改了文件 `/etc/default/grub`,回去删掉你所增加的参数:
```
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"
GRUB_CMDLINE_LINUX=""
```
然后更新 GRUB 配置文件:
```
sudo update-grub
```
### 尾声
在这篇文章中,我介绍了在 Linux 上**禁用 IPv6** 的方法,并简述了什么是 IPv6 以及可能想要禁用掉它的原因。
那么,这篇文章对你有用吗?你有禁用掉 IPv6 连接吗?让我们评论区见吧~
--------------------------------------------------------------------------------
via: https://itsfoss.com/disable-ipv6-ubuntu-linux/
作者:[Sergiu][a]
选题:[lujun9972][b]
译者:[rakino](https://github.com/rakino)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://itsfoss.com/author/sergiu/
[b]: https://github.com/lujun9972
[1]: https://en.wikipedia.org/wiki/IPv6
[2]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2019/05/disable_ipv6_ubuntu.png?fit=800%2C450&ssl=1
[3]: https://www.google.com/intl/en/ipv6/statistics.html
[4]: https://whatismyipaddress.com/ipv6-issues
[5]: https://www.internetsociety.org/blog/2015/01/ipv6-security-myth-1-im-not-running-ipv6-so-i-dont-have-to-worry/
[6]: https://itsfoss.com/remove-drive-icons-from-unity-launcher-in-ubuntu/
[7]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2019/05/ipv6_address_ubuntu.png?fit=800%2C517&ssl=1
[8]: https://linux.cn/article-10804-1.html
[9]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2019/05/ipv6_disabled_ubuntu.png?fit=800%2C442&ssl=1
[10]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2019/05/sysctl_configuration.jpg?fit=800%2C554&ssl=1
[11]: https://linuxhandbook.com/chmod-command/
[12]: https://itsfoss.com/find-which-kernel-version-is-running-in-ubuntu/
[13]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2019/05/grub_configuration-1.jpg?fit=800%2C565&ssl=1
[14]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2019/05/ipv6_address_ubuntu-1.png?fit=800%2C517&ssl=1

View File

@ -0,0 +1,132 @@
[#]: collector: (lujun9972)
[#]: translator: (rakino)
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-12706-1.html)
[#]: subject: (Things You Didn't Know About GNU Readline)
[#]: via: (https://twobithistory.org/2019/08/22/readline.html)
[#]: author: (Two-Bit History https://twobithistory.org)
你所不知的 GNU Readline
======
![](https://img.linux.net.cn/data/attachment/album/202010/10/222755etdndudtu97wddz7.jpg)
有时我会觉得自己的计算机是一栋非常大的房子,我每天都会访问这栋房子,也对一楼的大部分房间都了如指掌,但仍然还是有我没有去过的卧室,有我没有打开过的衣柜,有我没有探索过的犄角旮旯。我感到有必要更多地了解我的计算机了,就像任何人都会觉得有必要看看自己家里从未去过的房间一样。
GNU Readline 是个不起眼的小软件库,我依赖了它多年却没有意识到它的存在,也许有成千上万的人每天都在不经意间使用它。如果你用 Bash shell 的话,每当你自动补全一个文件名,或者在输入的一行文本中移动光标,以及搜索之前命令的历史记录时,你都在使用 GNU Readline当你在 Postgres`psql`)或是 Ruby REPL`irb`)的命令行界面中进行同样的操作时,你依然在使用 GNU Readline。很多软件都依赖 GNU Readline 库来实现用户所期望的功能,不过这些功能是如此的辅助与不显眼,以至于在我看来很少有人会停下来去想它是从哪里来的。
GNU Readline 最初是自由软件基金会在 20 世纪 80 年代创建的,如今作为每个人的基础计算设施的重要的、甚至看不见的组成部分的它,由一位志愿者维护。
### 充满特色
GNU Readline 库的存在,主要是为了增强各种命令行界面,它提供了一组通用的按键,使你可以在一个单行输入中移动和编辑。例如,在 Bash 提示符中按下 `Ctrl-A`,你的光标会跳到行首,而按下 `Ctrl-E` 则会跳到行末;另一个有用的命令是 `Ctrl-U`,它会删除该行中光标之前的所有内容。
有很长一段时间,我通过反复敲击方向键来在命令行上移动,如今看来这十分尴尬,也不知道为什么,当时的我从来没有想过可以有一种更快的方法。当然了,没有哪一个熟悉 Vim 或 Emacs 这种文本编辑器的程序员愿意长时间地击打方向键,所以像 Readline 这样的东西必然会被创造出来。在 Readline 上可以做的绝非仅仅跳来跳去你可以像使用文本编辑器那样编辑单行文本——这里有删除单词、单词换位、大写单词、复制和粘贴字符等命令。Readline 的大部分按键/快捷键都是基于 Emacs 的,它基本上就是一个单行文本版的 Emacs 了,甚至还有录制和重放宏的功能。
我从来没有用过 Emacs所以很难记住所有不同的 Readline 命令。不过 Readline 有着很巧妙的一点,那就是能够切换到基于 Vim 的模式,在 Bash 中可以使用内置的 `set` 命令来这样做。下面会让 Readline 在当前的 shell 中使用 Vim 风格的命令:
```
$ set -o vi
```
该选项启用后,就可以使用 `dw` 等命令来删除单词了,此时相当于 Emacs 模式下的 `Ctrl-U` 的命令是 `d0`
我第一次知道有这个功能的时候很兴奋地想尝试一下,但它对我来说并不是那么好用。我很高兴知道有这种对 Vim 用户的让步,在使用这个功能上你可能会比我更幸运,尤其是你还没有使用 Readline 的默认按键的话;我的问题在于,我听说有基于 Vim 的界面时已经学会了几种默认按键,因此即使启用了 Vim 的选项,也一直在错误地用着默认的按键;另外因为没有某种指示器,所以 Vim 的模态设计在这里会很尴尬——你很容易就忘记了自己处于哪个模式,就因为这样,我卡在了一种虽然使用 Vim 作为文本编辑器,但却在 Readline 上用着 Emacs 风格的命令的情况里,我猜其他很多人也是这样的。
如果你觉得 Vim 和 Emacs 的键盘命令系统诡异而神秘(这并不是没有道理的),你可以按照喜欢的方式自定义 Readline 的键绑定。Readline 在启动时会读取文件 `~/.inputrc`,它可以用来配置各种选项与键绑定,我做的一件事是重新配置了 `Ctrl-K`:通常情况下该命令会从光标处删除到行末,但我很少这样做,所以我在 `~/.inputrc` 中添加了以下内容,把它绑定为直接删除整行:
```
Control-k: kill-whole-line
```
每个 Readline 命令(文档中称它们为 “函数” )都有一个名称,你可以用这种方式将其与一个键序列联系起来。如果你在 Vim 中编辑 `~/.inputrc`,就会发现 Vim 知道这种文件类型,还会帮你高亮显示有效的函数名,而不高亮无效的函数名。
`~/.inputrc` 可以做的另一件事是通过将键序列映射到输入字符串上来创建预制宏。[Readline 手册][1]给出了一个我认为特别有用的例子:我经常想把一个程序的输出保存到文件中,这意味着我得经常在 Bash 命令中追加类似 `> output.txt` 这样的东西,为了节省时间,可以把它做成一个 Readline 宏:
```
Control-o: "> output.txt"
```
这样每当你按下 `Ctrl-O` 时,你都会看到 `> output.txt` 被添加到了命令行光标的后面,这样很不错!
不过你可以用宏做的可不仅仅是为文本串创建快捷方式;在 `~/.inputrc` 中使用以下条目意味着每次按下 `Ctrl-J` 时,行内已有的文本都会被 `$(``)` 包裹住。该宏先用 `Ctrl-A` 移动到行首,添加 `$(` ,然后再用 `Ctrl-E` 移动到行尾,添加 `)`
```
Control-j: "\C-a$(\C-e)"
```
如果你经常需要像下面这样把一个命令的输出用于另一个命令的话,这个宏可能会对你有帮助:
```
$ cd $(brew --prefix)
```
`~/.inputrc` 文件也允许你为 Readline 手册中所谓的 “变量” 设置不同的值,这些变量会启用或禁用某些 Readline 行为,你也可以使用这些变量来改变 Readline 中像是自动补全或者历史搜索这些行为的工作方式。我建议开启的一个变量是 `revert-all-at-newline`,它是默认关闭的,当这个变量关闭时,如果你使用反向搜索功能从命令历史记录中提取一行并编辑,但随后又决定搜索另一行,那么你所做的编辑会被保存在历史记录中。我觉得这样会很混乱,因为这会导致你的 Bash 命令历史中出现从未运行过的行。所以在你的 `~/.inputrc` 中加入这个:
```
set revert-all-at-newline on
```
在你用 `~/.inputrc` 设置了选项或键绑定以后,它们会适用于任何使用 Readline 库的地方,显然 Bash 也包括在内,不过你也会在其它像是 `irb``psql` 这样的程序中受益。如果你经常使用关系型数据库的命令行界面,一个用于插入 `SELECT * FROM` 的 Readline 宏可能会很有用。
### Chet Ramey
GNU Readline 如今由凯斯西储大学的高级技术架构师 Chet Ramey 维护Ramey 同时还负责维护 Bash shell这两个项目都是由一位名叫 Brian Fox 的自由软件基金会员工在 1988 年开始编写的,但从 1994 年左右开始Ramey 一直是它们唯一的维护者。
Ramey 通过电子邮件告诉我Readline 远非一个原创的想法,它是为了实现 POSIX 规范所规定的功能而被创建的,而 POSIX 规范又是在 20 世纪 80 年代末被制定的。许多早期的 shell包括 Korn shell 和至少一个版本的 Unix System V shell都包含行编辑功能。1988 年版的 Korn shell`ksh88`)提供了 Emacs 风格和 Vi/Vim 风格的编辑模式。据我从[手册页][2]中得知Korn shell 会通过查看 `VISUAL``EDITOR` 环境变量来决定你使用的模式这一点非常巧妙。POSIX 中指定 shell 功能的部分近似于 `ksh88` 的实现,所以 GNU Bash 也要实现一个类似的灵活的行编辑系统来保持兼容,因此就有了 Readline。
Ramey 第一次参与 Bash 开发时Readline 还是 Bash 项目目录下的一个单一的源文件,它其实只是 Bash 的一部分随着时间的推移Readline 文件慢慢地成为了独立的项目,不过直到 1994 年Readline 2.0 版本发布Readline 才完全成为了一个独立的库。
Readline 与 Bash 密切相关Ramey 也通常把 Readline 与 Bash 的发布配对但正如我上面提到的Readline 是一个可以被任何有命令行界面的软件使用的库,而且它真的很容易使用。下面是一个例子,虽然简单,但这就是在 C 程序中使用 Readline 的方法。向 `readline()` 函数传递的字符串参数就是你希望 Readline 向用户显示的提示符:
```
#include <stdio.h>
#include <stdlib.h>
#include "readline/readline.h"
int main(int argc, char** argv)
{
char* line = readline("my-rl-example> ");
printf("You entered: \"%s\"\n", line);
free(line);
return 0;
}
```
你的程序会把控制权交给 Readline它会负责从用户那里获得一行输入以这样的方式让用户可以做所有花哨的行编辑工作一旦用户真正提交了这一行Readline 就会把它返回给你。在我的库搜索路径中有 Readline 库,所以我可以通过调用以下内容来链接 Readline 库,从而编译上面的内容:
```
$ gcc main.c -lreadline
```
当然Readline 的 API 比起那个单一的函数要丰富得多,任何使用它的人都可以对库的行为进行各种调整,库的用户(开发者)甚至可以添加新的函数,来让最终用户可以通过 `~/.inputrc` 来配置它们,这意味着 Readline 非常容易扩展。但是据我所知,即使是 Bash ,虽然事先有很多配置,最终也会像上面的例子一样调用简单的 `readline()` 函数来获取输入。(参见 GNU Bash 源代码中的[这一行][3]Bash 似乎在这里将获取输入的责任交给了 Readline
Ramey 现在已经在 Bash 和 Readline 上工作了二十多年,但他的工作却从来没有得到过报酬 —— 他一直都是一名志愿者。Bash 和 Readline 仍然在积极开发中,尽管 Ramey 说 Readline 的变化比 Bash 慢得多。我问 Ramey 作为这么多人使用的软件唯一的维护者是什么感觉,他说可能有几百万人在不知不觉中使用 Bash因为每个苹果设备都运行 Bash这让他担心一个破坏性的变化会造成多大的混乱不过他已经慢慢习惯了所有这些人的想法。他还说他会继续在 Bash 和 Readline 上工作,因为在这一点上他已经深深地投入了,而且他也只是单纯地喜欢把有用的软件提供给世界。
_你可以在 [Chet Ramey 的网站][4]上找到更多关于他的信息。_
_喜欢这篇文章吗我会每四周写出一篇像这样的文章。关注推特帐号 [@TwoBitHistory][5] 或者[订阅 RSS][6] 来获取更新吧_
--------------------------------------------------------------------------------
via: https://twobithistory.org/2019/08/22/readline.html
作者:[Two-Bit History][a]
选题:[lujun9972][b]
译者:[rakino](https://github.com/rakino)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://twobithistory.org
[b]: https://github.com/lujun9972
[1]: https://tiswww.case.edu/php/chet/readline/readline.html
[2]: https://web.archive.org/web/20151105130220/http://www2.research.att.com/sw/download/man/man1/ksh88.html
[3]: https://github.com/bminor/bash/blob/9f597fd10993313262cab400bf3c46ffb3f6fd1e/parse.y#L1487
[4]: https://tiswww.case.edu/php/chet/
[5]: https://twitter.com/TwoBitHistory
[6]: https://twobithistory.org/feed.xml
[7]: https://twitter.com/TwoBitHistory/status/1112492084383092738?ref_src=twsrc%5Etfw

View File

@ -0,0 +1,59 @@
[#]: collector: (lujun9972)
[#]: translator: (chenmu-kk)
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-12768-1.html)
[#]: subject: (My first contribution to open source: Making a decision)
[#]: via: (https://opensource.com/article/19/11/my-first-open-source-contribution-mistake-decisions)
[#]: author: (Galen Corey https://opensource.com/users/galenemco)
我的第一次开源贡献:做出决定
======
> 一位新的开源贡献者告诉你如何加入到开源项目中。
![](https://img.linux.net.cn/data/attachment/album/202010/30/112350rh0xwp1x1y6awehn.jpg)
先前,我把我的第一次开源贡献的拖延归咎于[冒牌综合症][2]。但还有一个我无法忽视的因素:我做出决定太艰难了。在[成千上百万][3]的开源项目中选择时,选择一个要做贡献的项目是难以抉择的。如此重负,以至于我常常不得不关掉我的笔记本去思考:“或许我改天再做吧”。
错误之二是让我对做出决定的恐惧妨碍了我做出第一次贡献。在理想世界里,也许开始我的开源之旅时,心中就已经有了一个真正关心和想去做的具体项目,但我有的只是总得为开源项目做出贡献的模糊目标。对于那些处于同一处境的人来说,这儿有一些帮助我挑选出合适的项目(或者至少是一个好的项目)来做贡献的策略。
### 经常使用的工具
一开始,我不认为有必要将自己局限于已经熟悉的工具或项目。有一些项目我之前从未使用过,但由于它们的社区很活跃,或者它们解决的问题很有趣,因此看起来很有吸引力。
但是,考虑我投入到这个项目中的时间有限,我决定继续投入到我了解的工具上去。要了解工具需求,你需要熟悉它的工作方式。如果你想为自己不熟悉的项目做贡献,则需要完成一个额外的步骤来了解代码的功能和目标。这个额外的工作量可能是有趣且值得的,但也会使你的工作时间加倍。因为我的目标主要是贡献,投入到我了解的工具上是缩小范围的很好方式。回馈一个你认为有用的项目也是有意义的。
### 活跃而友好的社区
在选择项目的时候,我希望在那里有人会审查我写的代码才会觉得有信心。当然,我也希望审核我代码的人是个和善的人。毕竟,把你的作品放在那里接受公众监督是很可怕的。虽然我对建设性的反馈持开放态度,但开发者社区中的一些有毒角落是我希望避免的。
为了评估我将要加入的社区,我查看了我正在考虑加入的仓库的<ruby>议题<rt>issue</rt></ruby>部分。我要查看核心团队中是否有人定期回复。更重要的是,我试着确保没有人在评论中互相诋毁(这在议题讨论中是很常见的)。我还留意了那些有行为准则的项目,概述了什么是适当的和不适当的在线互动行为。
### 明确的贡献准则
因为这是我第一次为开源项目做出贡献,在此过程中我有很多问题。一些项目社区在流程的文档记录方面做的很好,可以用来指导挑选其中的议题并发起拉取请求。 [Gatsby][4] 是这种做法的典范,尽管那时我没有选择它们,因为在此之前我从未使用过该产品。
这种清晰的文档帮助我们缓解了一些不知如何去做的不安全感。它也给了我希望:项目对新的贡献者是开放的,并且会花时间来查看我的工作。除了贡献准则外,我还查看了议题部分,看看这个项目是否使用了“<ruby>第一个好议题<rt>good first issue</rt></ruby>”标志。这是该项目对初学者开放的另一个迹象(并可以帮助你学会要做什么)。
### 总结
如果你还没有计划好选择一个项目,那么选择合适的领域进行你的第一个开源贡献更加可行。列出一系列标准可以帮助自己缩减选择范围,并为自己的第一个拉取请求找到一个好的项目。
--------------------------------------------------------------------------------
via: https://opensource.com/article/19/11/my-first-open-source-contribution-mistake-decisions
作者:[Galen Corey][a]
选题:[lujun9972][b]
译者:[chenmu-kk](https://github.com/chenmu-kk)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://opensource.com/users/galenemco
[b]: https://github.com/lujun9972
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/lightbulb-idea-think-yearbook-lead.png?itok=5ZpCm0Jh (Lightbulb)
[2]: https://opensource.com/article/19/10/my-first-open-source-contribution-mistakes
[3]: https://github.blog/2018-02-08-open-source-project-trends-for-2018/
[4]: https://www.gatsbyjs.org/contributing/

View File

@ -0,0 +1,380 @@
[#]: collector: (lujun9972)
[#]: translator: (wxy)
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-12696-1.html)
[#]: subject: (Scan your Linux security with Lynis)
[#]: via: (https://opensource.com/article/20/5/linux-security-lynis)
[#]: author: (Gaurav Kamathe https://opensource.com/users/gkamathe)
使用 Lynis 扫描 Linux 安全性
======
> 使用这个全面的开源安全审计工具检查你的 Linux 机器的安全性。
![](https://img.linux.net.cn/data/attachment/album/202010/08/095516k6bdgeb6jhiajutm.jpg)
你有没有想过你的 Linux 机器到底安全不安全Linux 发行版众多,每个发行版都有自己的默认设置,你在上面运行着几十个版本各异的软件包,还有众多的服务在后台运行,而我们几乎不知道或不关心这些。
要想确定安全态势(指你的 Linux 机器上运行的软件、网络和服务的整体安全状态),你可以运行几个命令,得到一些零碎的相关信息,但你需要解析的数据量是巨大的。
如果能运行一个工具,生成一份关于机器安全状况的报告,那就好得多了。而幸运的是,有一个这样的软件:[Lynis][2]。它是一个非常流行的开源安全审计工具,可以帮助强化基于 Linux 和 Unix 的系统。根据该项目的介绍:
> “它运行在系统本身可以进行深入的安全扫描。主要目标是测试安全防御措施并提供进一步强化系统的提示。它还将扫描一般系统信息、易受攻击的软件包和可能的配置问题。Lynis 常被系统管理员和审计人员用来评估其系统的安全防御。”
### 安装 Lynis
你的 Linux 软件仓库中可能有 Lynis。如果有的话你可以用以下方法安装它
```
dnf install lynis
```
```
apt install lynis
```
然而,如果你的仓库中的版本不是最新的,你最好从 GitHub 上安装它。(我使用的是 Red Hat Linux 系统,但你可以在任何 Linux 发行版上运行它)。就像所有的工具一样,先在虚拟机上试一试是有意义的。要从 GitHub 上安装它:
```
$ cat /etc/redhat-release
Red Hat Enterprise Linux Server release 7.8 (Maipo)
$
$ uname  -r
3.10.0-1127.el7.x86_64
$
$ git clone https://github.com/CISOfy/lynis.git
Cloning into 'lynis'...
remote: Enumerating objects: 30, done.
remote: Counting objects: 100% (30/30), done.
remote: Compressing objects: 100% (30/30), done.
remote: Total 12566 (delta 15), reused 8 (delta 0), pack-reused 12536
Receiving objects: 100% (12566/12566), 6.36 MiB | 911.00 KiB/s, done.
Resolving deltas: 100% (9264/9264), done.
$
```
一旦你克隆了这个版本库,那么进入该目录,看看里面有什么可用的。主要的工具在一个叫 `lynis` 的文件里。它实际上是一个 shell 脚本所以你可以打开它看看它在做什么。事实上Lynis 主要是用 shell 脚本来实现的:
```
$ cd lynis/
$ ls
CHANGELOG.md        CONTRIBUTING.md  db           developer.prf  FAQ             include  LICENSE  lynis.8  README     SECURITY.md
CODE_OF_CONDUCT.md  CONTRIBUTORS.md  default.prf  extras         HAPPY_USERS.md  INSTALL  lynis    plugins  README.md
$
$ file lynis
lynis: POSIX shell script, ASCII text executable, with very long lines
$
```
### 运行 Lynis
通过给 Lynis 一个 `-h` 选项来查看帮助部分,以便有个大概了解:
```
$ ./lynis -h
```
你会看到一个简短的信息屏幕,然后是 Lynis 支持的所有子命令。
接下来,尝试一些测试命令以大致熟悉一下。要查看你正在使用的 Lynis 版本,请运行:
```
$ ./lynis show version
3.0.0
$
```
要查看 Lynis 中所有可用的命令:
```
$ ./lynis show commands
Commands:
lynis audit
lynis configure
lynis generate
lynis show
lynis update
lynis upload-only
$
```
### 审计 Linux 系统
要审计你的系统的安全态势,运行以下命令:
```
$ ./lynis audit system
```
这个命令运行得很快,并会返回一份详细的报告,输出结果可能一开始看起来很吓人,但我将在下面引导你来阅读它。这个命令的输出也会被保存到一个日志文件中,所以你可以随时回过头来检查任何可能感兴趣的东西。
Lynis 将日志保存在这里:
```
  Files:
  - Test and debug information      : /var/log/lynis.log
  - Report data                     : /var/log/lynis-report.dat
```
你可以验证是否创建了日志文件。它确实创建了:
```
$ ls -l /var/log/lynis.log
-rw-r-----. 1 root root 341489 Apr 30 05:52 /var/log/lynis.log
$
$ ls -l /var/log/lynis-report.dat
-rw-r-----. 1 root root 638 Apr 30 05:55 /var/log/lynis-report.dat
$
```
### 探索报告
Lynis 提供了相当全面的报告所以我将介绍一些重要的部分。作为初始化的一部分Lynis 做的第一件事就是找出机器上运行的操作系统的完整信息。之后是检查是否安装了什么系统工具和插件:
```
[+] Initializing program
------------------------------------
- Detecting OS... [ DONE ]
- Checking profiles... [ DONE ]
---------------------------------------------------
Program version: 3.0.0
Operating system: Linux
Operating system name: Red Hat Enterprise Linux Server 7.8 (Maipo)
Operating system version: 7.8
Kernel version: 3.10.0
Hardware platform: x86_64
Hostname: example
---------------------------------------------------
<<截断>>
[+] System Tools
------------------------------------
- Scanning available tools...
- Checking system binaries...
[+] Plugins (phase 1)
------------------------------------
Note: plugins have more extensive tests and may take several minutes to complete
- Plugin: pam
[..]
- Plugin: systemd
[................]
```
接下来,该报告被分为不同的部分,每个部分都以 `[+]` 符号开头。下面可以看到部分章节。要审核的地方有这么多Lynis 是最合适的工具!)
```
[+] Boot and services
[+] Kernel
[+] Memory and Processes
[+] Users, Groups and Authentication
[+] Shells
[+] File systems
[+] USB Devices
[+] Storage
[+] NFS
[+] Name services
[+] Ports and packages
[+] Networking
[+] Printers and Spools
[+] Software: e-mail and messaging
[+] Software: firewalls
[+] Software: webserver
[+] SSH Support
[+] SNMP Support
[+] Databases
[+] LDAP Services
[+] PHP
[+] Squid Support
[+] Logging and files
[+] Insecure services
[+] Banners and identification
[+] Scheduled tasks
[+] Accounting
[+] Time and Synchronization
[+] Cryptography
[+] Virtualization
[+] Containers
[+] Security frameworks
[+] Software: file integrity
[+] Software: System tooling
[+] Software: Malware
[+] File Permissions
[+] Home directories
[+] Kernel Hardening
[+] Hardening
[+] Custom tests
```
Lynis 使用颜色编码使报告更容易解读。
* 绿色。一切正常
* 黄色。跳过、未找到,可能有个建议
* 红色。你可能需要仔细看看这个
在我的案例中,大部分的红色标记都是在 “Kernel Hardening” 部分找到的。内核有各种可调整的设置,它们定义了内核的功能,其中一些可调整的设置可能有其安全场景。发行版可能因为各种原因没有默认设置这些,但是你应该检查每一项,看看你是否需要根据你的安全态势来改变它的值:
```
[+] Kernel Hardening
------------------------------------
  - Comparing sysctl key pairs with scan profile
    - fs.protected_hardlinks (exp: 1)                         [ OK ]
    - fs.protected_symlinks (exp: 1)                          [ OK ]
    - fs.suid_dumpable (exp: 0)                               [ OK ]
    - kernel.core_uses_pid (exp: 1)                           [ OK ]
    - kernel.ctrl-alt-del (exp: 0)                            [ OK ]
    - kernel.dmesg_restrict (exp: 1)                          [ DIFFERENT ]
    - kernel.kptr_restrict (exp: 2)                           [ DIFFERENT ]
    - kernel.randomize_va_space (exp: 2)                      [ OK ]
    - kernel.sysrq (exp: 0)                                   [ DIFFERENT ]
    - kernel.yama.ptrace_scope (exp: 1 2 3)                   [ DIFFERENT ]
    - net.ipv4.conf.all.accept_redirects (exp: 0)             [ DIFFERENT ]
    - net.ipv4.conf.all.accept_source_route (exp: 0)          [ OK ]
    - net.ipv4.conf.all.bootp_relay (exp: 0)                  [ OK ]
    - net.ipv4.conf.all.forwarding (exp: 0)                   [ OK ]
    - net.ipv4.conf.all.log_martians (exp: 1)                 [ DIFFERENT ]
    - net.ipv4.conf.all.mc_forwarding (exp: 0)                [ OK ]
    - net.ipv4.conf.all.proxy_arp (exp: 0)                    [ OK ]
    - net.ipv4.conf.all.rp_filter (exp: 1)                    [ OK ]
    - net.ipv4.conf.all.send_redirects (exp: 0)               [ DIFFERENT ]
    - net.ipv4.conf.default.accept_redirects (exp: 0)         [ DIFFERENT ]
    - net.ipv4.conf.default.accept_source_route (exp: 0)      [ OK ]
    - net.ipv4.conf.default.log_martians (exp: 1)             [ DIFFERENT ]
    - net.ipv4.icmp_echo_ignore_broadcasts (exp: 1)           [ OK ]
    - net.ipv4.icmp_ignore_bogus_error_responses (exp: 1)     [ OK ]
    - net.ipv4.tcp_syncookies (exp: 1)                        [ OK ]
    - net.ipv4.tcp_timestamps (exp: 0 1)                      [ OK ]
    - net.ipv6.conf.all.accept_redirects (exp: 0)             [ DIFFERENT ]
    - net.ipv6.conf.all.accept_source_route (exp: 0)          [ OK ]
    - net.ipv6.conf.default.accept_redirects (exp: 0)         [ DIFFERENT ]
    - net.ipv6.conf.default.accept_source_route (exp: 0)      [ OK ]
```
看看 SSH 这个例子,因为它是一个需要保证安全的关键领域。这里没有什么红色的东西,但是 Lynis 对我的环境给出了很多强化 SSH 服务的建议:
```
[+] SSH Support
------------------------------------
  - Checking running SSH daemon                               [ FOUND ]
    - Searching SSH configuration                             [ FOUND ]
    - OpenSSH option: AllowTcpForwarding                      [ SUGGESTION ]
    - OpenSSH option: ClientAliveCountMax                     [ SUGGESTION ]
    - OpenSSH option: ClientAliveInterval                     [ OK ]
    - OpenSSH option: Compression                             [ SUGGESTION ]
    - OpenSSH option: FingerprintHash                         [ OK ]
    - OpenSSH option: GatewayPorts                            [ OK ]
    - OpenSSH option: IgnoreRhosts                            [ OK ]
    - OpenSSH option: LoginGraceTime                          [ OK ]
    - OpenSSH option: LogLevel                                [ SUGGESTION ]
    - OpenSSH option: MaxAuthTries                            [ SUGGESTION ]
    - OpenSSH option: MaxSessions                             [ SUGGESTION ]
    - OpenSSH option: PermitRootLogin                         [ SUGGESTION ]
    - OpenSSH option: PermitUserEnvironment                   [ OK ]
    - OpenSSH option: PermitTunnel                            [ OK ]
    - OpenSSH option: Port                                    [ SUGGESTION ]
    - OpenSSH option: PrintLastLog                            [ OK ]
    - OpenSSH option: StrictModes                             [ OK ]
    - OpenSSH option: TCPKeepAlive                            [ SUGGESTION ]
    - OpenSSH option: UseDNS                                  [ SUGGESTION ]
    - OpenSSH option: X11Forwarding                           [ SUGGESTION ]
    - OpenSSH option: AllowAgentForwarding                    [ SUGGESTION ]
    - OpenSSH option: UsePrivilegeSeparation                  [ OK ]
    - OpenSSH option: AllowUsers                              [ NOT FOUND ]
    - OpenSSH option: AllowGroups                             [ NOT FOUND ]
```
我的系统上没有运行虚拟机或容器,所以这些显示的结果是空的:
```
[+] Virtualization
------------------------------------
[+] Containers
------------------------------------
```
Lynis 会检查一些从安全角度看很重要的文件的文件权限:
```
[+] File Permissions
------------------------------------
  - Starting file permissions check
    File: /boot/grub2/grub.cfg                                [ SUGGESTION ]
    File: /etc/cron.deny                                      [ OK ]
    File: /etc/crontab                                        [ SUGGESTION ]
    File: /etc/group                                          [ OK ]
    File: /etc/group-                                         [ OK ]
    File: /etc/hosts.allow                                    [ OK ]
    File: /etc/hosts.deny                                     [ OK ]
    File: /etc/issue                                          [ OK ]
    File: /etc/issue.net                                      [ OK ]
    File: /etc/motd                                           [ OK ]
    File: /etc/passwd                                         [ OK ]
    File: /etc/passwd-                                        [ OK ]
    File: /etc/ssh/sshd_config                                [ OK ]
    Directory: /root/.ssh                                     [ SUGGESTION ]
    Directory: /etc/cron.d                                    [ SUGGESTION ]
    Directory: /etc/cron.daily                                [ SUGGESTION ]
    Directory: /etc/cron.hourly                               [ SUGGESTION ]
    Directory: /etc/cron.weekly                               [ SUGGESTION ]
    Directory: /etc/cron.monthly                              [ SUGGESTION ]
```
在报告的底部Lynis 根据报告的发现提出了建议。每项建议后面都有一个 “TEST-ID”为了下一部分方便请将其保存起来
```
Suggestions (47):
----------------------------
* If not required, consider explicit disabling of core dump in /etc/security/limits.conf file [KRNL-5820]
https://cisofy.com/lynis/controls/KRNL-5820/
* Check PAM configuration, add rounds if applicable and expire passwords to encrypt with new values [AUTH-9229]
https://cisofy.com/lynis/controls/AUTH-9229/
```
Lynis 提供了一个选项来查找关于每个建议的更多信息,你可以使用 `show details` 命令和 TEST-ID 号来访问:
```
./lynis show details TEST-ID
```
这将显示该测试的其他信息。例如,我检查了 SSH-7408 的详细信息:
```
$ ./lynis show details SSH-7408
2020-04-30 05:52:23 Performing test ID SSH-7408 (Check SSH specific defined options)
2020-04-30 05:52:23 Test: Checking specific defined options in /tmp/lynis.k8JwazmKc6
2020-04-30 05:52:23 Result: added additional options for OpenSSH &lt; 7.5
2020-04-30 05:52:23 Test: Checking AllowTcpForwarding in /tmp/lynis.k8JwazmKc6
2020-04-30 05:52:23 Result: Option AllowTcpForwarding found
2020-04-30 05:52:23 Result: Option AllowTcpForwarding value is YES
2020-04-30 05:52:23 Result: OpenSSH option AllowTcpForwarding is in a weak configuration state and should be fixed
2020-04-30 05:52:23 Suggestion: Consider hardening SSH configuration [test:SSH-7408] [details:AllowTcpForwarding (set YES to NO)] [solution:-]
```
### 试试吧
如果你想更多地了解你的 Linux 机器的安全性,请试试 Lynis。如果你想了解 Lynis 是如何工作的,可以研究一下它的 shell 脚本,看看它是如何收集这些信息的。
--------------------------------------------------------------------------------
via: https://opensource.com/article/20/5/linux-security-lynis
作者:[Gaurav Kamathe][a]
选题:[lujun9972][b]
译者:[wxy](https://github.com/wxy)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://opensource.com/users/gkamathe
[b]: https://github.com/lujun9972
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/yearbook-haff-rx-linux-file-lead_0.png?itok=-i0NNfDC (Hand putting a Linux file folder into a drawer)
[2]: https://github.com/CISOfy/lynis

View File

@ -0,0 +1,171 @@
[#]: collector: (lujun9972)
[#]: translator: (MjSeven)
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-12772-1.html)
[#]: subject: (Use the internet from the command line with curl)
[#]: via: (https://opensource.com/article/20/5/curl-cheat-sheet)
[#]: author: (Seth Kenlon https://opensource.com/users/seth)
使用 curl 从命令行访问互联网
======
> 下载我们整理的 curl 备忘录。要在不使用图形界面的情况下从互联网上获取所需的信息curl 是一种快速有效的方法。
![](https://img.linux.net.cn/data/attachment/album/202010/31/000543n032ud499yy4d94v.jpg)
`curl` 通常被视作一款非交互式 Web 浏览器,这意味着它能够从互联网上获取信息,并在你的终端中显示,或将其保存到文件中。从表面看,这是 Web 浏览器,类似 Firefox 或 Chromium 所做的工作,只是它们默认情况下会*渲染*信息,而 `curl` 会下载并显示原始信息。实际上,`curl` 命令可以做更多的事情,并且能够使用多种协议与服务器进行双向传输数据,这些协议包括 HTTP、FTP、SFTP、IMAP、POP3、LDAP、SMB、SMTP 等。对于普通终端用户来说,这是一个有用的工具;而对于系统管理员,这非常便捷;对于微服务和云开发人员来说,它是一个质量保证工具。
`curl` 被设计为在没有用户交互的情况下工作,因此与 Firefox 不同,你必须从头到尾考虑与在线数据的交互。例如,如果想要在 Firefox 中查看网页,你需要启动 Firefox 窗口。打开 Firefox 后,在地址栏或搜索引擎中输入要访问的网站。然后,导航到网站,然后单击要查看的页面。
对于 `curl` 来说也是如此,不同之处在于你需要一次执行所有操作:在启动 `curl` 的同时提供需要访问的互联网地址,并告诉它是否要将数据保存在终端或文件中。当你必须与需要身份验证的网站或 API 进行交互时,会变得有点复杂,但是一旦你学习了 `curl` 命令语法,它就会变得自然而然。为了帮助你掌握它,我们在一个方便的[备忘录][2]中收集了相关的语法信息。
### 使用 curl 下载文件
你可以通过提供指向特定 URL 的链接来使用 `curl` 命令下载文件。如果你提供的 URL 默认为 `index.html`,那么将下载此页面,并将下载的文件显示在终端屏幕上。你可以将数据通过管道传递到 `less`、`tail` 或任何其它命令:
```
$ curl "http://example.com" | tail -n 4
<h1>Example Domain</h1>
<p>This domain is for use in illustrative examples in documents. You may use this domain in literature without prior coordination or asking for permission.</p>
<p><a href="https://www.iana.org/domains/example">More information...</a></p>
</div></body></html>
```
由于某些 URL 包含特殊字符shell 通常会将其解释,因此最安全的做法用引号将 URL 包起来。
某些文件无法很好的在终端中转换显示。你可以使用 `--remote-name` 选项使文件根据服务器上的命名进行保存:
```
$ curl --remote-name "https://example.com/linux-distro.iso"
$ ls
linux-distro.iso
```
或者,你可以使用 `--output` 选项来命名你想要下载的内容:
```
curl "http://example.com/foo.html" --output bar.html
```
### 使用 curl 列出带有远程目录的内容
因为 `curl` 不是交互式的,所以很难浏览页面上的可下载元素。如果你要连接的远程服务器允许,可以使用 `curl` 来列出目录的内容:
```
$ curl --list-only "https://example.com/foo/"
```
### 继续中断下载
如果你正在下载一个非常大的文件,你可能会发现有时候必须中断下载。`curl` 非常智能,可以确定下载从何处中断并继续下载。这意味着,下一次当你下载一个 4GB 的 Linux 发行版的 ISO 出现问题时,就不必重新开始了。`--continue-at` 的语法有点不寻常:如果你知道下载中断时的字节数,你可以提供给 `curl`;否则,你可以使用单独的一个破折号(`-`)指示 curl 自动检测:
```
$ curl --remote-name --continue-at - "https://example.com/linux-distro.iso"
```
### 下载文件序列
如果你需要下载多个文件而不是一个大文件,那么 `curl` 可以帮助你解决这个问题。假设你知道要下载的文件的位置和文件名模式,则可以使用 `curl` 的序列标记:中括号里是整数范围的起点和终点。对于输出文件名,使用 `#1` 表示第一个变量:
```
$ curl "https://example.com/file_[1-4].webp" --output "file_#1.webp"
```
如果你需要使用其它变量来表示另一个序列,按照每个变量在命令中出现的顺序表示它们。例如,在这个命令中,`#1` 指目录 `images_000``images_009`,而 `#2` 指目录 `file_1.webp``file_4.webp`
```
$ curl "https://example.com/images_00[0-9]/file_[1-4].webp" --output "file_#1-#2.webp"
```
### 从站点下载所有 PNG 文件
你也可以仅使用 `curl``grep` 进行一些基本的 Web 抓取操作,以找到想要下载的内容。例如,假设你需要下载与正在归档网页关联的所有图像,首先,下载引用了图像的页面。将页面内通过管道传输到 `grep`,搜索所需的图片类型(在此示例中为 PNG。最后创建一个 `while` 循环来构造下载 URL并将文件保存到你的计算机
```
$ curl https://example.com |\
grep --only-matching 'src="[^"]*.[png]"' |\
cut -d\" -f2 |\
while read i; do \
curl https://example.com/"${i}" -o "${i##*/}"; \
done
```
这只是一个示例,但它展示了 `curl` 与 Unix 管道和一些基本而巧妙的解析结合使用时是多么的灵活。
### 获取 HTML 头
用于数据交换的协议在计算机发送通信的数据包中嵌入了大量元数据。HTTP 头是数据初始部分的组件。在连接一个网站出现问题时,查看这些报文头(尤其是响应码)会有所帮助:
```
curl --head "https://example.com"
HTTP/2 200
accept-ranges: bytes
age: 485487
cache-control: max-age=604800
content-type: text/html; charset=UTF-8
date: Sun, 26 Apr 2020 09:02:09 GMT
etag: "3147526947"
expires: Sun, 03 May 2020 09:02:09 GMT
last-modified: Thu, 17 Oct 2019 07:18:26 GMT
server: ECS (sjc/4E76)
x-cache: HIT
content-length: 1256
```
### 快速失败
响应 200 通常是 HTTP 成功指示符,这是你与服务器连接时通常期望的结果。著名的 404 响应表示找不到页面,而 500 则表示服务器在处理请求时出现了错误。
要查看协商过程中发生了什么错误,添加 `--show-error` 选项:
```
$ curl --head --show-error "http://opensource.ga"
```
除非你可以访问要连接的服务器,否则这些问题将很难解决,但是 `curl` 通常会尽力连接你指定的地址。有时在网络上进行测试时,无休止的重试似乎只会浪费时间,因此你可以使用 `--fail-early` 选项来强制 `curl` 在失败时迅速退出:
```
curl --fail-early "http://opensource.ga"
```
### 由 3xx 响应指定的重定向查询
300 这个系列的响应更加灵活。具体来说301 响应意味着一个 URL 已被永久移动到其它位置。对于网站管理员来说,重新定位内容并留下“痕迹”是一种常见的方式,这样访问旧地址的人们仍然可以找到它。默认情况下,`curl` 不会进行 301 重定向,但你可以使用 `--localtion` 选项使其继续进入 301 响应指向的目标:
```
$ curl "https://iana.org" | grep title
<title>301 Moved Permanently</title>
$ curl --location "https://iana.org"
<title>Internet Assigned Numbers Authority</title>
```
### 展开短网址
如果你想要在访问短网址之前先查看它们,那么 `--location` 选项非常有用。短网址对于有字符限制的社交网络(当然,如果你使用[现代和开源的社交网络][4]的话,这可能不是问题),或者对于用户不能复制粘贴长地址的印刷媒体来说是有用处的。但是,它们也可能存在风险,因为其目的地址本质上是隐藏的。通过结合使用 `--head` 选项仅查看 HTTP 头,`--location` 选项可以查看一个 URL 的最终地址,你可以查看一个短网址而无需加载其完整的资源:
```
$ curl --head --location "<https://bit.ly/2yDyS4T>"
```
### 下载我们的 curl 备忘录
一旦你开始考虑了将探索 web 由一条命令来完成,那么 `curl` 就成为一种快速有效的方式,可以从互联网上获取所需的信息,而无需麻烦图形界面。为了帮助你适应到工作流中,我们创建了一个 [curl 备忘录][2],它包含常见的 `curl` 用法和语法,包括使用它查询 API 的概述。
--------------------------------------------------------------------------------
via: https://opensource.com/article/20/5/curl-cheat-sheet
作者:[Seth Kenlon][a]
选题:[lujun9972][b]
译者:[MjSeven](https://github.com/MjSeven)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://opensource.com/users/seth
[b]: https://github.com/lujun9972
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/coverimage_cheat_sheet.png?itok=lYkNKieP (Cheat Sheet cover image)
[2]: https://opensource.com/downloads/curl-command-cheat-sheet
[3]: https://www.iana.org/domains/example"\>More
[4]: https://opensource.com/article/17/4/guide-to-mastodon

View File

@ -0,0 +1,142 @@
[#]: collector: (lujun9972)
[#]: translator: (HankChow)
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-12715-1.html)
[#]: subject: (Using Bash traps in your scripts)
[#]: via: (https://opensource.com/article/20/6/bash-trap)
[#]: author: (Seth Kenlon https://opensource.com/users/seth)
在脚本中使用 Bash 信号捕获
======
> 无论你的脚本是否成功运行,<ruby>信号捕获<rt>trap</rt></ruby>都能让它平稳结束。
![](https://img.linux.net.cn/data/attachment/album/202010/13/182135f2nktcrnryncisg8.jpg)
Shell 脚本的启动并不难被检测到,但 Shell 脚本的终止检测却并不容易,因为我们无法确定脚本会按照预期地正常结束,还是由于意外的错误导致失败。当脚本执行失败时,将正在处理的内容记录下来是非常有用的做法,但有时候这样做起来并不方便。而 [Bash][2] 中 `trap` 命令的存在正是为了解决这个问题,它可以捕获到脚本的终止信号,并以某种预设的方式作出应对。
### 响应失败
如果出现了一个错误,可能导致发生一连串错误。下面示例脚本中,首先在 `/tmp` 中创建一个临时目录,这样可以在临时目录中执行解包、文件处理等操作,然后再以另一种压缩格式进行打包:
```
#!/usr/bin/env bash
CWD=`pwd`
TMP=${TMP:-/tmp/tmpdir}
## create tmp dir
mkdir "${TMP}"
## extract files to tmp
tar xf "${1}" --directory "${TMP}"
## move to tmpdir and run commands
pushd "${TMP}"
for IMG in *.jpg; do
mogrify -verbose -flip -flop "${IMG}"
done
tar --create --file "${1%.*}".tar *.jpg
## move back to origin
popd
## bundle with bzip2
bzip2 --compress "${TMP}"/"${1%.*}".tar \
--stdout > "${1%.*}".tbz
## clean up
/usr/bin/rm -r /tmp/tmpdir
```
一般情况下,这个脚本都可以按照预期执行。但如果归档文件中的文件是 PNG 文件而不是期望的 JPEG 文件,脚本就会在中途失败,这时候另一个问题就出现了:最后一步删除临时目录的操作没有被正常执行。如果你手动把临时目录删掉,倒是不会造成什么影响,但是如果没有手动把临时目录删掉,在下一次执行这个脚本的时候,它必须处理一个现有的临时目录,里面充满了不可预知的剩余文件。
其中一个解决方案是在脚本开头增加一个预防性删除逻辑用来处理这种情况。但这种做法显得有些暴力,而我们更应该从结构上解决这个问题。使用 `trap` 是一个优雅的方法。
### 使用 trap 捕获信号
我们可以通过 `trap` 捕捉程序运行时的信号。如果你使用过 `kill` 或者 `killall` 命令,那你就已经使用过名为 `SIGTERM` 的信号了。除此以外,还可以执行 `trap -l``trap --list` 命令列出其它更多的信号:
```
$ trap --list
 1) SIGHUP       2) SIGINT       3) SIGQUIT      4) SIGILL       5) SIGTRAP
 6) SIGABRT      7) SIGBUS       8) SIGFPE       9) SIGKILL     10) SIGUSR1
11) SIGSEGV     12) SIGUSR2     13) SIGPIPE     14) SIGALRM     15) SIGTERM
16) SIGSTKFLT   17) SIGCHLD     18) SIGCONT     19) SIGSTOP     20) SIGTSTP
21) SIGTTIN     22) SIGTTOU     23) SIGURG      24) SIGXCPU     25) SIGXFSZ
26) SIGVTALRM   27) SIGPROF     28) SIGWINCH    29) SIGIO       30) SIGPWR
31) SIGSYS      34) SIGRTMIN    35) SIGRTMIN+1  36) SIGRTMIN+2  37) SIGRTMIN+3
38) SIGRTMIN+4  39) SIGRTMIN+5  40) SIGRTMIN+6  41) SIGRTMIN+7  42) SIGRTMIN+8
43) SIGRTMIN+9  44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9  56) SIGRTMAX-8  57) SIGRTMAX-7
58) SIGRTMAX-6  59) SIGRTMAX-5  60) SIGRTMAX-4  61) SIGRTMAX-3  62) SIGRTMAX-2
63) SIGRTMAX-1  64) SIGRTMAX
```
可以被 `trap` 识别的信号除了以上这些,还包括:
* `EXIT`:进程退出时发出的信号
* `ERR`:进程以非 0 状态码退出时发出的信号
* `DEBUG`:表示调试模式的布尔值
如果要在 Bash 中实现信号捕获,只需要在 `trap` 后加上需要执行的命令,再加上需要捕获的信号列表就可以了。
例如,下面的这行语句可以捕获到在进程运行时用户按下 `Ctrl + C` 组合键发出的 `SIGINT` 信号:
```
trap "{ echo 'Terminated with Ctrl+C'; }" SIGINT
```
因此,上文中脚本的缺陷可以通过使用 `trap` 捕获 `SIGINT`、`SIGTERM`、进程错误退出、进程正常退出等信号,并正确处理临时目录的方式来修复:
```
#!/usr/bin/env bash
CWD=`pwd`
TMP=${TMP:-/tmp/tmpdir}
trap \
"{ /usr/bin/rm -r "${TMP}" ; exit 255; }" \
SIGINT SIGTERM ERR EXIT
## create tmp dir
mkdir "${TMP}"
tar xf "${1}" --directory "${TMP}"
## move to tmp and run commands
pushd "${TMP}"
for IMG in *.jpg; do
mogrify -verbose -flip -flop "${IMG}"
done
tar --create --file "${1%.*}".tar *.jpg
## move back to origin
popd
## zip tar
bzip2 --compress $TMP/"${1%.*}".tar \
--stdout > "${1%.*}".tbz
```
对于更复杂的功能,还可以用 [Bash 函数][3]来简化 `trap` 语句。
### Bash 中的信号捕获
信号捕获可以让脚本在无论是否成功执行所有任务的情况下都能够正确完成清理工作,能让你的脚本更加可靠,这是一个很好的习惯。尽管尝试把信号捕获加入到你的脚本里看看能够起到什么作用吧。
--------------------------------------------------------------------------------
via: https://opensource.com/article/20/6/bash-trap
作者:[Seth Kenlon][a]
选题:[lujun9972][b]
译者:[HankChow](https://github.com/HankChow)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://opensource.com/users/seth
[b]: https://github.com/lujun9972
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/programming-code-keyboard-laptop.png?itok=pGfEfu2S (Hands programming)
[2]: https://opensource.com/resources/what-bash
[3]: https://opensource.com/article/20/6/how-write-functions-bash

View File

@ -0,0 +1,140 @@
[#]: collector: "lujun9972"
[#]: translator: "lxbwolf"
[#]: reviewer: "wxy"
[#]: publisher: "wxy"
[#]: url: "https://linux.cn/article-12700-1.html"
[#]: subject: "Automate testing for website errors with this Python tool"
[#]: via: "https://opensource.com/article/20/7/seodeploy"
[#]: author: "JR Oakes https://opensource.com/users/jroakes"
使用这个 Python 工具对网站 SEO 问题进行自动化测试
======
> SEODeploy 可以帮助我们在网站部署之前识别出 SEO 问题。
![](https://img.linux.net.cn/data/attachment/album/202010/09/194928xbqvdd81amapgdae.jpg)
作为一个技术性搜索引擎优化开发者,我经常被请来协助做网站迁移、新网站发布、分析实施和其他一些影响网站在线可见性和测量等领域,以控制风险。许多公司每月经常性收入的很大一部分来自用户通过搜索引擎找到他们的产品和服务。虽然搜索引擎已经能妥善地处理没有被良好格式化的代码,但在开发过程中还是会出问题,对搜索引擎如何索引和为用户显示页面产生不利影响。
我曾经也尝试通过评审各阶段会破坏 SEO<ruby>搜索引擎优化<rt>search engine optimization</rt></ruby>)的问题来手动降低这种风险。我的团队最终审查到的结果,决定了该项目是否可以上线。但这个过程通常很低效,只能用于有限的页面,而且很有可能出现人为错误。
长期以来,这个行业一直在寻找可用且值得信赖的方式来自动化这一过程,同时还能让开发人员和搜索引擎优化人员在必须测试的内容上获得有意义的发言权。这是非常重要的,因为这些团队在开发冲刺中优先级通常会发生冲突,搜索引擎优化者需要推动变化,而开发人员需要控制退化和预期之外的情况。
### 常见的破坏 SEO 的问题
我合作过的很多网站有成千上万的页面,甚至上百万。实在令人费解,为什么一个开发过程中的改动能影响这么多页面。在 SEO 的世界中Google 或其他搜索引擎展示你的页面时,一个非常微小和看起来无关紧要的修改也可能导致全网站范围的变化。在部署到生产环境之前,必须要处理这类错误。
下面是我去年见过的几个例子。
#### 偶发的 noindex
在部署到生产环境之后,我们用的一个专用的第三方 SEO 监控工具 [ContentKing][2] 马上发现了这个问题。这个错误很隐蔽,因为它在 HTML 中是不可见的,确切地说,它隐藏在服务器响应头里,但它能很快导致搜索不可见。
```
HTTP/1.1 200 OK
Date: Tue May 25 2010 21:12:42 GMT
[...]
X-Robots-Tag: noindex
[...]
```
#### canonical 小写
上线时错误地把整个网站的 [canonical 链接元素][3]全改成小写了。这个改动影响了接近 30000 个 URL。在修改之前所有的 URL 大小写都正常(例如 `URL-Path` 这样)。这之所以是个问题是因为 `canonical` 链接元素是用来给 Google 提示一个网页真实的规范 URL 版本的。这个改动导致很多 URL 被从 Google 的索引中移除并用小写的版本(`/url-path`)重新建立索引。影响范围是流量损失了 10% 到 15%,也污染了未来几个星期的网页监控数据。
#### 源站退化
有个网站的 React 实现复杂而奇特,它有个神奇的问题,`origin.domain.com` URL 退化显示为 CDN 服务器的源站。它会在网站元数据(如 `canonical` 链接元素、URL 和 Open Graph 链接)中间歇性地显示原始的主机而不是 CDN 边缘主机。这个问题在原始的 HTML 和渲染后的 HTML 中都存在。这个问题影响搜索的可见性和在社交媒体上的分享质量。
### SEODeploy 介绍
SEO 通常使用差异测试工具来检测渲染后和原始的 HTML 的差异。差异测试是很理想的,因为它避免了肉眼测试的不确定性。你希望检查 Google 对你的页面的渲染过程的差异,而不是检查用户对你页面的渲染。你希望查看下原始的 HTML 是什么样的,而不是渲染后的 HTML因为 Google 的渲染过程是有独立的两个阶段的。
这促使我和我的同事创造了 [SEODeploy][4] 这个“在部署流水线中用于自动化 SEO 测试的 Python 库。”我们的使命是:
> 开发一个工具,让开发者能提供若干 URL 路径,并允许这些 URL 在生产环境和预演环境的主机上进行差异测试,尤其是对 SEO 相关数据的非预期的退化。
SEODeploy 的机制很简单:提供一个每行内容都是 URL 路径的文本文件SEODeploy 对那些路径运行一系列模块,对比<ruby>生产环境<rt>production</rt></ruby><ruby>预演环境<rt>staging</rt></ruby>的 URL把检测到的所有的错误和改动信息报告出来。
![SEODeploy overview][5]
这个工具及其模块可以用一个 YAML 文件来配置,可以根据预期的变化进行定制。
![SEODeploy output][7]
最初的发布版本包含下面的的核心功能和概念:
1. **开源**:我们坚信分享代码可以被大家批评、改进、扩展、分享和复用。
2. **模块化**Web 开发中有许多不同的堆栈和边缘案例。SEODeploy 工具在概念上很简单,因此采用模块化用来控制复杂性。我们提供了两个建好的模块和一个实例模块来简述基本结构。
3. **URL 抽样**:由于它不是对所有 URL 都是可行和有效的,因此我们引入了一种随机抽取 XML 网站地图 URL 或被 ContentKing 监控的 URL 作为样本的方法。
4. **灵活的差异检测**Web 数据是凌乱的。无论被检测的数据是什么类型(如 ext、数组或列表、JSON 对象或字典、整数、浮点数等等),差异检测功能都会尝试将这些数据转换为差异信息。
5. **自动化**: 你可以在命令行来调用抽样和运行方法,将 SEODeploy 融合到已有的流水线也很简单。
### 模块
虽然核心功能很简单但在设计上SEODeploy 的强大功能和复杂度体现在模块上。模块用来处理更难的任务:获取、清理和组织预演服务器和生产服务器上的数据来作对比。
#### Headless 模块
[Headless 模块][8] 是为那些从库里获取数据时不想为第三方服务付费的开发者准备的。它可以运行任意版本的 Chrome会从每组用来比较的 URL 中提取渲染的数据。
Headless 模块会提取下面的核心数据用来比较:
1. SEO 内容如标题、H1-H6、链接等等。
2. 从 Chrome <ruby>计时器<rt>Timings</rt></ruby>和 CDP<ruby>Chrome 开发工具协议<rt>Chrome DevTools Protocol</rt></ruby>)性能 API 中提取性能数据
3. 计算出的性能指标,包括 CLS<ruby>累积布局偏移<rt>Cumulative Layout Shift</rt></ruby>),这是 Google 最近发布的一个很受欢迎的 [Web 核心数据][9]
4. 从上述 CDP 的覆盖率 API 获取的 CSS 和 JavaScript 的覆盖率数据
这个模块引入了处理预演环境、网络速度预设(为了让对比更规范化)等功能,也引入了一个处理在预演对比数据中替换预演主机的方法。开发者也能很容易地扩展这个模块,以收集他们想要在每个页面上进行比较的任何其他数据。
#### 其他模块
我们为开发者创建了一个[示例模块][10],开发者可以参照它来使用框架创建一个自定义的提取模块。另一个示例模块是与 ContentKing 结合的。ContentKing 模块需要有 ContentKing 订阅,而 Headless 可以在所有能运行 Chrome 的机器上运行。
### 需要解决的问题
我们有扩展和强化工具库的[计划][11],但正在寻求开发人员的[反馈][12],了解哪些是可行的,哪些是不符合他们的需求。我们正在解决的问题和条目有:
1. 对于某些对比元素(尤其是 schema动态时间戳会产生误报。
2. 把测试数据保存到数据库,以便查看部署历史以及与上次的预演推送进行差异测试。
3. 通过云基础设施的渲染,强化提取的规模和速度。
4. 把测试覆盖率从现在的 46% 提高到 99% 以上。
5. 目前,我们依赖 [Poetry][13] 进行部署管理,但我们希望发布一个 PyPl 库,这样就可以用 `pip install` 轻松安装。
6. 我们还在关注更多使用时的问题和相关数据。
### 开始使用
这个项目在 [GitHub][4] 上,我们对大部分功能都提供了 [文档][14]。
我们希望你能克隆 SEODeploy 并试试它。我们的目标是通过这个由技术性搜索引擎优化开发者开发的、经过开发者和工程师们验证的工具来支持开源社区。我们都见过验证复杂的预演问题需要多长时间,也都见过大量 URL 的微小改动能有什么样的业务影响。我们认为这个库可以为开发团队节省时间、降低部署过程中的风险。
如果你有问题或者想提交代码,请查看项目的[关于][15]页面。
--------------------------------------------------------------------------------
via: https://opensource.com/article/20/7/seodeploy
作者:[JR Oakes][a]
选题:[lujun9972][b]
译者:[lxbwolf](https://github.com/lxbwolf)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://opensource.com/users/jroakes
[b]: https://github.com/lujun9972
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/browser_screen_windows_files.png?itok=kLTeQUbY "Computer screen with files or windows open"
[2]: https://www.contentkingapp.com/
[3]: https://en.wikipedia.org/wiki/Canonical_link_element
[4]: https://github.com/locomotive-agency/SEODeploy
[5]: https://opensource.com/sites/default/files/uploads/seodeploy.png "SEODeploy overview"
[6]: https://creativecommons.org/licenses/by-sa/4.0/
[7]: https://opensource.com/sites/default/files/uploads/seodeploy_output.png "SEODeploy output"
[8]: https://locomotive-agency.github.io/SEODeploy/modules/headless/
[9]: https://web.dev/vitals/
[10]: https://locomotive-agency.github.io/SEODeploy/modules/creating/
[11]: https://locomotive-agency.github.io/SEODeploy/todo/
[12]: https://locomotive-agency.github.io/SEODeploy/about/#contact
[13]: https://python-poetry.org/
[14]: https://locomotive-agency.github.io/SEODeploy/
[15]: https://locomotive-agency.github.io/SEODeploy/about/

View File

@ -0,0 +1,216 @@
[#]: collector: (lujun9972)
[#]: translator: (wxy)
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-12697-1.html)
[#]: subject: (How to read Lynis reports to improve Linux security)
[#]: via: (https://opensource.com/article/20/8/linux-lynis-security)
[#]: author: (Alan Formy-Duval https://opensource.com/users/alanfdoss)
如何阅读 Lynis 报告提高 Linux 安全性
======
> 使用 Lynis 的扫描和报告来发现和修复 Linux 安全问题。
![](https://img.linux.net.cn/data/attachment/album/202010/08/102355k7jakojhz9x8xamx.jpg)
当我读到 Gaurav Kamathe 的文章《[使用 Lynis 扫描 Linux 安全性][2]》时,让我想起了我在美国劳工部担任系统管理员的日子。我那时的职责之一是保证我们的 Unix 服务器的安全。每个季度,都会有一个独立的核查员来审查我们服务器的安全状态。每次在核查员预定到达的那一天,我都会运行 Security Readiness ReviewSRR这是一个扫描工具它使用一大套脚本来识别和报告任何安全线索。SRR 是开源的,因此我可以查看所有源码脚本及其功能。这使我能够查看其代码,确定具体是什么问题,并迅速修复它发现的每个问题。
### 什么是 Lynis
[Lynis][3] 是一个开源的安全审计工具,它的工作原理和 SRR 很像,它会扫描 Linux 系统,并提供它发现的任何弱点的详细报告。同样和 SRR 一样,它也是由一大套脚本组成的,每个脚本都会检查一个特定的项目,例如,最小和最大密码时间要求。
运行 Lynis 后,你可以使用它的报告来定位每个项目的脚本,并了解 Lynis 是如何检查和报告每个问题的。你也可以使用相同的脚本代码来创建新的代码来自动解决。
### 如何阅读 Lynis 报告
由于 Gaurav 的文章介绍了 Lynis 的安装和使用,在本文中,我将展示一些如何阅读和使用其报告的例子。
请从运行一次审计开始:
```
# lynis audit system --quick
```
完成后完整的报告将显示在你的屏幕上。在底部“Suggestions” 部分列出了所有可能需要修复以更好地加固系统的项目,以及每个项目的 TEST-ID。
要想加固系统并减少列表的大小,请开始解决每个项目。在 “Suggestions” 部分的描述可能包含了你需要采取的全部行动。如果没有,你可以使用 `show details` 命令。
```
# lynis show details TEST-ID
```
例如,在我的系统中,有一条建议是:
> 找不到 `locate` 所需的数据库,运行 `updatedb``locate.updatedb` 来创建这个文件。[FILE-6410]
看起来我只需要运行 `updatedb` 命令就行,但如果我想确定一下,我可以使用 Lynis 的 `show details` 选项。
```
# lynis show details FILE-6410
2020-06-16 20:54:33 Performing test ID FILE-6410 (Checking Locate database)
2020-06-16 20:54:33 Test: Checking locate database
2020-06-16 20:54:33 Result: file /var/lib/mlocate/mlocate.db not found
2020-06-16 20:54:33 Result: file /var/lib/locate/locatedb not found
2020-06-16 20:54:33 Result: file /var/lib/locatedb not found
2020-06-16 20:54:33 Result: file /var/lib/slocate/slocate.db not found
2020-06-16 20:54:33 Result: file /var/cache/locate/locatedb not found
2020-06-16 20:54:33 Result: file /var/db/locate.database not found
2020-06-16 20:54:33 Result: database not found
2020-06-16 20:54:33 Suggestion: The database required for 'locate' could not be found. Run 'updatedb' or 'locate.updatedb' to create this file. [test:FILE-6410] [details:-] [solution:-]
2020-06-16 20:54:33 ====
```
这些细节表明 Lynis 无法找到各种文件。这个情况描述的非常清楚。我可以运行 `updatedb` 命令,然后重新检查这个测试。
```
# updatedb
# lynis --tests FILE-6410
```
重新检查细节时,会显示它发现哪个文件满足了测试:
```
# lynis show details FILE-6410
2020-06-16 21:38:40 Performing test ID FILE-6410 (Checking Locate database)
2020-06-16 21:38:40 Test: Checking locate database
2020-06-16 21:38:40 Result: locate database found (/var/lib/mlocate/mlocate.db)
2020-06-16 21:38:40 Result: file /var/lib/locate/locatedb not found
2020-06-16 21:38:40 Result: file /var/lib/locatedb not found
2020-06-16 21:38:40 Result: file /var/lib/slocate/slocate.db not found
2020-06-16 21:38:40 Result: file /var/cache/locate/locatedb not found
2020-06-16 21:38:40 Result: file /var/db/locate.database not found
2020-06-16 21:38:40 ====
```
### 深入挖掘
Lynis 的许多建议并不像这个建议那样直接。如果你不确定某个发现或建议指的是什么,就很难知道如何解决问题。假设你在一个新的 Linux 服务器上运行 Lynis有几项与 SSH 守护进程有关的内容,其中一项是关于 `MaxAuthTries` 的设置:
```
* Consider hardening SSH configuration [SSH-7408]
- Details : MaxAuthTries (6 --> 3)
https://cisofy.com/lynis/controls/SSH-7408/
```
要解决这个问题,你需要知道 SSH 配置文件的位置。一个经验丰富的 Linux 管理员可能已经知道在哪里找到它们,但如果你不知道,有一个方法可以看到 Lynis 在哪里找到它们。
#### 定位 Lynis 测试脚本
Lynis 支持多种操作系统,因此你的安装位置可能有所不同。在 Red Hat Enterprise Linux 或 Fedora Linux 系统中,使用 `rpm` 命令来查找测试文件:
```
# rpm -ql lynis
```
这将列出所有测试文件,并报告它们在 `lynis/include` 目录下的位置。在这个目录下搜索你想知道的 TEST-ID本例中为 SSH-7408
```
# grep SSH-7408 /usr/share/lynis/include/*
/usr/share/lynis/include/tests_ssh:    # Test        : SSH-7408
```
#### 查找 SSH 问题
名为 `tests_ssh` 的文件中包含了 TEST-ID在这里可以找到与 SSH 相关的扫描函数。看看这个文件,就可以看到 Lynis 扫描器调用的各种函数。第一部分在一个名为 `SSH_DAEMON_CONFIG_LOCS` 的变量中定义了一个目录列表。下面几节负责检查 SSH 守护进程的状态、定位它的配置文件,并识别它的版本。我在 SSH-7404 测试中找到了查找配置文件的代码,描述为 “确定 SSH 守护进程配置文件位置”。这段代码包含一个 `for` 循环,在列表中的项目中搜索一个名为 `sshd_config` 的文件。我可以用这个逻辑来自己进行搜索:
```
# find /etc /etc/ssh /usr/local/etc/ssh /opt/csw/etc/ssh -name sshd_config
/etc/ssh/sshd_config
/etc/ssh/sshd_config
find: /usr/local/etc/ssh: No such file or directory
find: /opt/csw/etc/ssh: No such file or directory
```
进一步探索这个文件,就会看到寻找 SSH-7408 的相关代码。这个测试涵盖了 `MaxAuthTries` 和其他一些设置。现在我可以在 SSH 配置文件中找到该变量:
```
# grep MaxAuthTries /etc/ssh/sshd_config
#MaxAuthTries 6
```
#### 修复法律横幅问题
Lynis 还报告了一个与登录系统时显示的法律横幅有关的发现。在我的家庭桌面系统上(我并不希望有很多其他人登录),我没有去改变默认的 `issue` 文件。企业或政府的系统很可能被要求包含一个法律横幅以警告用户他们的登录和活动可能被记录和监控。Lynis 用 BANN-7126 测试和 BANN-7130 测试报告了这一点:
```
* Add a legal banner to /etc/issue, to warn unauthorized users [BANN-7126]
https://cisofy.com/lynis/controls/BANN-7126/
* Add legal banner to /etc/issue.net, to warn unauthorized users [BANN-7130]
https://cisofy.com/lynis/controls/BANN-7130/
```
我在运行 Fedora 32 工作站的系统上没有发现什么:
```
# cat /etc/issue /etc/issue.net
\S
Kernel \r on an \m (\l)
\S
Kernel \r on an \m (\l)
```
我可以添加一些诸如 “keep out” 或 “don't break anything” 之类的内容,但测试的描述并没有提供足够的信息来解决这个问题,所以我又看了看 Lynis 的脚本。我注意到 `include` 目录下有一个叫 `tests_banners` 的文件;这似乎是一个很好的地方。在 `grep` 的帮助下,我看到了相关的测试:
```
# grep -E 'BANN-7126|BANN-7130' /usr/share/lynis/include/tests_banners
    # Test        : BANN-7126
    Register --test-no BANN-7126 --preqs-met ${PREQS_MET} --weight L --network NO --category security --description "Check issue banner file contents"
    # Test        : BANN-7130
    Register --test-no BANN-7130 --preqs-met ${PREQS_MET} --weight L --network NO --category security --description "Check issue.net banner file contents"
```
在检查了测试文件中的相关代码后,我发现这两个测试都是通过一个 `for` 循环来迭代一些预定义的法律术语:
```
for ITEM in ${LEGAL_BANNER_STRINGS}; do
```
这些法律术语存储在文件顶部定义的变量 `LEGAL_BANNER_STRINGS` 中。向后滚动到顶部可以看到完整的清单:
```
LEGAL_BANNER_STRINGS="audit access authori condition connect consent continu criminal enforce evidence forbidden intrusion law legal legislat log monitor owner penal policy policies privacy private prohibited record restricted secure subject system terms warning"
```
我最初的建议“keep out” 或 “don't break anything”不会满足这个测试因为它们不包含这个列表中的任何单词。
下面这条横幅信息包含了几个必要的词,因此,它将满足这个测试,并防止 Lynis 报告它:
> Attention, by continuing to connect to this system, you consent to the owner storing a log of all activity. Unauthorized access is prohibited.
请注意,这条信息必须被添加到 `/etc/issue``/etc/issue.net` 中。
### 使其可重复
你可以手动进行这些编辑,但你可能要考虑自动化。例如,可能有许多设置需要更改,或者你可能需要在许多服务器上定期进行这些编辑。创建一个加固脚本将是简化这个过程的好方法。对于 SSH 配置,在你的加固脚本中的一些 `sed` 命令可以解决这些发现。或者,你可以使用 `echo` 语句来添加合法的横幅。
```
sed -i '/MaxAuthTries/s/#MaxAuthTries 6/MaxAuthTries 3/' /etc/ssh/sshd_config
echo "Legal Banner" | tee -a /etc/issue /etc/issue.net
```
自动化使你能够创建一个可重复的脚本,可以在你的基础设施中保存和管理。你也可以在你的初始服务器配置中加入这个脚本。
### 加固你的系统
这种类型的练习可以提高你的脚本技能,既可以跟着现有的代码走,也可以写自己的脚本。因为 Lynis 是开源的,所以你可以很容易地看到你的系统是如何被检查的,以及它的报告意味着什么。最终的结果将是一个完善的系统,你可以在审计人员来的时候随时向他们炫耀。
--------------------------------------------------------------------------------
via: https://opensource.com/article/20/8/linux-lynis-security
作者:[Alan Formy-Duval][a]
选题:[lujun9972][b]
译者:[wxy](https://github.com/wxy)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://opensource.com/users/alanfdoss
[b]: https://github.com/lujun9972
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/security-lock-password.jpg?itok=KJMdkKum (Lock)
[2]: https://linux.cn/article-12696-1.html
[3]: https://github.com/CISOfy/lynis

View File

@ -0,0 +1,304 @@
[#]: collector: (lujun9972)
[#]: translator: (gxlct008)
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-12710-1.html)
[#]: subject: (TCP window scaling, timestamps and SACK)
[#]: via: (https://fedoramagazine.org/tcp-window-scaling-timestamps-and-sack/)
[#]: author: (Florian Westphal https://fedoramagazine.org/author/strlen/)
TCP 窗口缩放、时间戳和 SACK
======
![](https://img.linux.net.cn/data/attachment/album/202010/12/114050up4695djpw6n4tu9.jpg)
Linux TCP 协议栈具有无数个可以更改其行为的 `sysctl` 旋钮。 这包括可用于接收或发送操作的内存量、套接字的最大数量、可选的特性和协议扩展。
有很多文章出于各种“性能调优”或“安全性”原因,建议禁用 TCP 扩展,比如时间戳或<ruby>选择性确认<rt>Selective ACKnowledgments</rt></ruby>SACK
本文提供了这些扩展功能的背景,为什么会默认启用,它们之间是如何关联的,以及为什么通常情况下将它们关闭是个坏主意。
### TCP 窗口缩放
TCP 可以承受的数据传输速率受到几个因素的限制。其中包括:
* <ruby>往返时间<rt>Round trip time</rt></ruby>RTT
这是数据包到达目的地并返回回复所花费的时间。越低越好。
* 所涉及的网络路径的最低链路速度。
* 丢包频率。
* 新数据可用于传输的速度。
例如CPU 需要能够以足够快的速度将数据传递到网络适配器。如果 CPU 需要首先加密数据,则适配器可能必须等待新数据。同样地,如果磁盘存储不能足够快地读取数据,则磁盘存储可能会成为瓶颈。
* TCP 接收窗口的最大可能大小。
接收窗口决定了 TCP 在必须等待接收方报告接收到该数据之前可以传输多少数据(以字节为单位)。这是由接收方宣布的。接收方将在读取并确认接收到传入数据时不断更新此值。接收窗口的当前值包含在 [TCP 报头][2] 中,它是 TCP 发送的每个数据段的一部分。因此只要发送方接收到来自对等方的确认它就知道当前的接收窗口。这意味着往返时间RTT越长发送方获得接收窗口更新所需的时间就越长。
TCP 的未确认(正在传输)数据被限制为最多 64KB。在大多数网络场景中这甚至还不足以维持一个像样的数据速率。让我们看看一些例子。
**理论数据速率**
在往返时间RTT为 100 毫秒的情况下TCP 每秒最多可以传输 640KB。在延迟为 1 秒的情况下,最大理论数据速率降至只有 64KB/s。
这是因为接收窗口的原因。一旦发送了 64KB 的数据,接收窗口就已经满了。发送方必须等待,直到对等方通知它应用程序已经读取了至少一部分数据。
发送的第一个段会把 TCP 窗口缩减去该段的大小。在接收窗口值的更新信息可用之前,需要往返一次。当更新以 1 秒的延迟到达时,即使链路有足够的可用带宽,也会导致 64KB 的限制。
为了充分利用一个具有几毫秒延迟的快速网络,必须有一个比传统 TCP 支持的窗口更大的窗口。“64KB 限制”是协议规范的产物TCP 头只为接收窗口大小保留了 16 个位。这允许接收窗口最大为 64KB。在 TCP 协议最初设计时,这个大小并没有被视为一个限制。
不幸的是,想通过仅仅更改 TCP 头来支持更大的最大窗口值是不可能的。如果这样做就意味着 TCP 的所有实现都必须同时更新,否则它们将无法相互理解。为了解决这个问题,我们改变了对接收窗口值的解释。
“窗口缩放选项”允许你改变这个解释,同时保持与现有实现的兼容性。
#### TCP 选项:向后兼容的协议扩展
TCP 支持可选扩展。这允许使用新特性增强协议,而无需立即更新所有实现。当 TCP 发起方连接到对等方时,它还会发送一个支持的扩展列表。所有扩展都遵循相同的格式:一个唯一的选项号,后跟选项的长度以及选项数据本身。
TCP 响应方检查连接请求中包含的所有选项号。如果它遇到一个不能理解的选项号,则会跳过
该选项号附带的“长度”字节的数据,并检查下一个选项号。响应方忽略了从答复中无法理解的内容。这使发送方和接收方都够理解所支持的公共选项集。
使用窗口缩放时,选项数据总是由单个数字组成。
### 窗口缩放选项
```
Window Scale option (WSopt): Kind: 3, Length: 3
    +---------+---------+---------+
    | Kind=3  |Length=3 |shift.cnt|
    +---------+---------+---------+
         1         1         1
```
[窗口缩放][3] 选项告诉对等方,应该使用给定的数字缩放 TCP 标头中的接收窗口值,以获取实际大小。
例如,一个宣告窗口缩放因子为 7 的 TCP 发起方试图指示响应方,任何将来携带接收窗口值为 512 的数据包实际上都会宣告 65536 字节的窗口。增加了 128 倍2^7。这将允许最大为 8MB 的 TCP 窗口。
不能理解此选项的 TCP 响应方将会忽略它,为响应连接请求而发送的 TCP 数据包SYN-ACK不会包含该窗口缩放选项。在这种情况下双方只能使用 64k 的窗口大小。幸运的是,默认情况下,几乎每个 TCP 栈都支持并默认启用了此选项,包括 Linux。
响应方包括了它自己所需的缩放因子。两个对等方可以使用不同的因子。宣布缩放因子为 0 也是合法的。这意味着对等方应该如实处理它接收到的接收窗口值,但它允许应答方向上的缩放值,然后接收方可以使用更大的接收窗口。
与 SACK 或 TCP 时间戳不同,窗口缩放选项仅出现在 TCP 连接的前两个数据包中,之后无法更改。也不可能通过查看不包含初始连接三次握手的连接的数据包捕获来确定缩放因子。
支持的最大缩放因子为 14。这将允许 TCP 窗口的大小高达 1GB。
**窗口缩放的缺点**
在非常特殊的情况下,它可能导致数据损坏。但在你禁用该选项之前,要知道通常情况下是不可能损坏的。还有一种解决方案可以防止这种情况。不幸的是,有些人在没有意识到它与窗口缩放的关系的情况下禁用了该解决方案。首先,让我们看一下需要解决的实际问题。想象以下事件序列:
1. 发送方发送段s_1、s_2、s_3、... s_n。
2. 接收方看到s_1、s_3、... s_n并发送对 s_1 的确认。
3. 发送方认为 s_2 丢失,然后再次发送。它还发送了段 s_n+1 中包含的新数据。
4. 接收方然后看到s_2、s_n+1s_2数据包 s_2 被接收两次。
当发送方过早触发重新传输时,可能会发生这种情况。在正常情况下,即使使用窗口缩放,这种错误的重传也绝不会成为问题。接收方将只丢弃重复项。
#### 从旧数据到新数据
TCP 序列号最多可以为 4GB。如果它变得大于此值则该序列会回绕到 0然后再次增加。这本身不是问题但是如果这种问题发生得足够快则上述情况可能会造成歧义。
如果在正确的时刻发生回绕,则序列号 s_2重新发送的数据包可能已经大于 s_n+1。因此在最后的步骤4接收方可以将其解释为s_2、s_n+1、s_n+m即它可以将 “旧” 数据包 s_2 视为包含新数据。
通常,这不会发生,因为即使在高带宽链接上,“回绕”也只会每隔几秒钟或几分钟发生一次。原始数据包和不需要的重传的数据包之间的间隔将小得多。
例如,对于 50MB/s 的传输速度,重复项要迟到一分钟以上才会成为问题。序列号的回绕速度没有快到让小的延迟会导致这个问题。
一旦 TCP 达到 “GB/s” 的吞吐率,序列号的回绕速度就会非常快,以至于即使只有几毫秒的延迟也可能会造成 TCP 无法检测出的重复项。通过解决接收窗口太小的问题TCP 现在可以用于以前无法实现的网络速度,这会产生一个新的,尽管很少见的问题。为了在 RTT 非常低的环境中安全使用 GB/s 的速度,接收方必须能够检测到这些旧的重复项,而不必仅依赖序列号。
### TCP 时间戳
#### 最佳截止日期
用最简单的术语来说,[TCP 时间戳][3]只是在数据包上添加时间戳,以解决由非常快速的序列号回绕引起的歧义。如果一个段看起来包含新数据,但其时间戳早于上一个在接收窗口内的数据包,则该序列号已被重新回绕,而“新”数据包实际上是一个较旧的重复项。这解决了即使在极端情况下重传的歧义。
但是该扩展不仅仅是检测旧数据包。TCP 时间戳的另一个主要功能是更精确的往返时间测量RTTm
#### 需要准确的 RTT 估算
当两个对等方都支持时间戳时,每个 TCP 段都携带两个附加数字:时间戳值和回显时间戳。
```
TCP Timestamp option (TSopt): Kind: 8, Length: 10
+-------+----+----------------+-----------------+
|Kind=8 | 10 |TS Value (TSval)|EchoReply (TSecr)|
+-------+----+----------------+-----------------+
    1      1         4                4
```
准确的 RTT 估算对于 TCP 性能至关重要。TCP 会自动重新发送未确认的数据。重传由计时器触发:如果超时,则 TCP 会将尚未收到确认的一个或多个数据包视为丢失。然后再发送一次。
但是,“尚未得到确认” 并不意味着该段已丢失。也有可能是接收方到目前为止没有发送确认或者确认仍在传输中。这就造成了一个两难的困境TCP 必须等待足够长的时间,才能让这种轻微的延迟变得无关紧要,但它也不能等待太久。
**低网络延迟 VS 高网络延迟**
在延迟较高的网络中如果计时器触发过快TCP 经常会将时间和带宽浪费在不必要的重发上。
然而在延迟较低的网络中等待太长时间会导致真正发生数据包丢失时吞吐量降低。因此在低延迟网络中计时器应该比高延迟网络中更早到期。所以TCP 重传超时不能使用固定常量值作为超时。它需要根据其在网络中所经历的延迟来调整该值。
**往返时间的测量**
TCP 选择基于预期的往返时间RTT的重传超时。RTT 事先是未知的。它是通过测量发送的段与 TCP 接收到该段所承载数据的确认之间的增量来估算的。
由于多种因素使其而变得复杂。
* 出于性能原因TCP 不会为收到的每个数据包生成新的确认。它等待的时间非常短:如果有更多的数据段到达,则可以通过单个 ACK 数据包确认其接收。这称为<ruby>“累积确认”<rt>cumulative ACK</rt></ruby>
* 往返时间并不恒定。这是有多种因素造成的。例如,客户端可能是一部移动电话,随其移动而切换到不同的基站。也可能是当链路或 CPU 的利用率提高时,数据包交换花费了更长的时间。
* 必须重新发送的数据包在计算过程中必须被忽略。这是因为发送方无法判断重传数据段的 ACK 是在确认原来的传输数据(毕竟已到达)还是在确认重传数据。
最后一点很重要:当 TCP 忙于从丢失中恢复时,它可能仅接收到重传段的 ACK。这样它就无法在此恢复阶段测量更新RTT。所以它无法调整重传超时然后超时将以指数级增长。那是一种非常具体的情况它假设其他机制如快速重传或 SACK 不起作用)。但是,使用 TCP 时间戳,即使在这种情况下也会进行 RTT 评估。
如果使用了扩展,则对等方将从 TCP 段的扩展空间中读取时间戳值并将其存储在本地。然后,它将该值作为 “回显时间戳” 放入发回的所有数据段中。
因此,该选项带有两个时间戳:它的发送方自己的时间戳和它从对等方收到的最新时间戳。原始发送方使用 “回显时间戳” 来计算 RTT。它是当前时间戳时钟与 “回显时间戳” 中所反映的值之间的增量。
**时间戳的其他用途**
TCP 时间戳甚至还有除 PAWS<ruby>防止序列号回绕<rt>Protection Against Wrapped Sequences</rt></ruby> 和 RTT 测量以外的其他用途。例如,可以检测是否不需要重发。如果该确认携带较旧的回显时间戳,则该确认针对的是初始数据包,而不是重新发送的数据包。
TCP 时间戳的另一个更晦涩的用例与 TCP [syn cookie][4] 功能有关。
**在服务器端建立 TCP 连接**
当连接请求到达的速度快于服务器应用程序可以接受新的传入连接的速度时,连接积压最终将达到其极限。这可能是由于系统配置错误或应用程序中的错误引起的。当一个或多个客户端发送连接请求而不对 “SYN ACK” 响应做出反应时,也会发生这种情况。这将用不完整的连接填充连接队列。这些条目需要几秒钟才会超时。这被称为<ruby>“同步泛洪攻击”<rt>syn flood attack</rt></ruby>
**TCP 时间戳和 TCP Syn Cookie**
即使队列已满,某些 TCP 协议栈也允许继续接受新连接。发生这种情况时Linux 内核将在系统日志中打印一条突出的消息:
> 端口 P 上可能发生 SYN 泛洪。正在发送 Cookie。检查 SNMP 计数器。
此机制将完全绕过连接队列。通常存储在连接队列中的信息被编码到 SYN/ACK 响应 TCP 序列号中。当 ACK 返回时,可以根据序列号重建队列条目。
序列号只有有限的空间来存储信息。因此,使用 “TCP Syn Cookie” 机制建立的连接不能支持 TCP 选项。
但是,对两个对等点都通用的 TCP 选项可以存储在时间戳中。ACK 数据包在回显时间戳字段中反映了该值,这也允许恢复已达成共识的 TCP 选项。否则cookie 连接受标准的 64KB 接收窗口限制。
**常见误区 —— 时间戳不利于性能**
不幸的是,一些指南建议禁用 TCP 时间戳以减少内核访问时间戳时钟来获取当前时间所需的次数。这是不正确的。如前所述RTT 估算是 TCP 的必要部分。因此,内核在接收/发送数据包时总是采用微秒级的时间戳。
在包处理步骤的其余部分中Linux 会重用 RTT 估算所需的时钟时间戳。这还避免了将时间戳添加到传出 TCP 数据包的额外时钟访问。
整个时间戳选项在每个数据包中仅需要 10 个字节的 TCP 选项空间,这不会显著减少可用于数据包有效负载的空间。
**常见误区 —— 时间戳是个安全问题**
一些安全审计工具和(较旧的)博客文章建议禁用 TCP 时间戳,因为据称它们泄露了系统正常运行时间:这样一来,便可以估算系统/内核的补丁级别。这在过去是正确的:时间戳时钟基于不断增加的值,该值在每次系统引导时都以固定值开始。时间戳值可以估计机器已经运行了多长时间(正常运行时间 `uptime`)。
从 Linux 4.12 开始TCP 时间戳不再显示正常运行时间。发送的所有时间戳值都使用对等设备特定的偏移量。时间戳值也每 49 天回绕一次。
换句话说,从地址 “A” 出发,或者终到地址 “A” 的连接看到的时间戳与到远程地址 “B” 的连接看到的时间戳不同。
运行 `sysctl net.ipv4.tcp_timeamp=2` 以禁用随机化偏移。这使得分析由诸如 `wireshark``tcpdump` 之类的工具记录的数据包跟踪变得更容易 —— 从主机发送的数据包在其 TCP 选项时间戳中都具有相同的时钟基准。因此,对于正常操作,默认设置应保持不变。
### 选择性确认
如果同一数据窗口中的多个数据包丢失了TCP 将会出现问题。这是因为 TCP 确认是累积的,但仅适用于按顺序到达的数据包。例如:
* 发送方发送段 s_1、s_2、s_3、... s_n
* 发送方收到 s_2 的 ACK
* 这意味着 s_1 和 s_2 都已收到,并且发送方不再需要保留这些段。
* s_3 是否应该重新发送? s_4 呢? s_n
发送方等待 “重传超时” 或 “重复 ACK” 以使 s_2 到达。如果发生重传超时或到达了 s_2 的多个重复 ACK则发送方再次发送 s_3。
如果发送方收到对 s_n 的确认,则 s_3 是唯一丢失的数据包。这是理想的情况。仅发送单个丢失的数据包。
如果发送方收到的确认段小于 s_n例如 s_4则意味着丢失了多个数据包。发送方也需要重传下一个数据段。
**重传策略**
可能只是重复相同的序列:重新发送下一个数据包,直到接收方指示它已处理了直至 s_n 的所有数据包为止。这种方法的问题在于,它需要一个 RTT直到发送方知道接下来必须重新发送的数据包为止。尽管这种策略可以避免不必要的重传但要等到 TCP 重新发送整个数据窗口后,它可能要花几秒钟甚至更长的时间。
另一种方法是一次重新发送几个数据包。当丢失了几个数据包时,此方法可使 TCP 恢复更快。在上面的示例中TCP 重新发送了 s_3、s_4、s_5、...,但是只能确保已丢失 s_3。
从延迟的角度来看,这两种策略都不是最佳的。如果只有一个数据包需要重新发送,第一种策略是快速的,但是当多个数据包丢失时,它花费的时间太长。
即使必须重新发送多个数据包,第二个也是快速的,但是以浪费带宽为代价。此外,这样的 TCP 发送方在进行不必要的重传时可能已经发送了新数据。
通过可用信息TCP 无法知道丢失了哪些数据包。这就是 TCP [选择性确认][5]SACK的用武之地了。就像窗口缩放和时间戳一样它是另一个可选的但非常有用的 TCP 特性。
**SACK 选项**
```
   TCP Sack-Permitted Option: Kind: 4, Length 2
   +---------+---------+
   | Kind=4  | Length=2|
   +---------+---------+
```
支持此扩展的发送方在连接请求中包括 “允许 SACK” 选项。如果两个端点都支持该扩展,则检测到数据流中丢失数据包的对等方可以将此信息通知发送方。
```
   TCP SACK Option: Kind: 5, Length: Variable
                     +--------+--------+
                     | Kind=5 | Length |
   +--------+--------+--------+--------+
   |      Left Edge of 1st Block       |
   +--------+--------+--------+--------+
   |      Right Edge of 1st Block      |
   +--------+--------+--------+--------+
   |                                   |
   /            . . .                  /
   |                                   |
   +--------+--------+--------+--------+
   |      Left Edge of nth Block       |
   +--------+--------+--------+--------+
   |      Right Edge of nth Block      |
   +--------+--------+--------+--------+
```
接收方遇到 s_2 后跟 s_5 ... s_n则在发送对 s_2 的确认时将包括一个 SACK 块:
```
                +--------+-------+
                | Kind=5 |   10  |
+--------+------+--------+-------+
| Left edge: s_5                 |
+--------+--------+-------+------+
| Right edge: s_n                |
+--------+-------+-------+-------+
```
这告诉发送方到 s_2 的段都是按顺序到达的,但也让发送方知道段 s_5 至 s_n 也已收到。然后发送方可以重新发送那两个数据包s_3、s_4并继续发送新数据。
**神话般的无损网络**
从理论上讲,如果连接不会丢包,那么 SACK 就没有任何优势。或者连接具有如此低的延迟,甚至等待一个完整的 RTT 都无关紧要。
在实践中,无损行为几乎是不可能保证的。即使网络及其所有交换机和路由器具有足够的带宽和缓冲区空间,数据包仍然可能丢失:
* 主机操作系统可能面临内存压力并丢弃数据包。请记住,一台主机可能同时处理数万个数据包流。
* CPU 可能无法足够快地消耗掉来自网络接口的传入数据包。这会导致网络适配器本身中的数据包丢失。
* 如果 TCP 时间戳不可用,即使一个非常小的 RTT 的连接也可能在丢失恢复期间暂时停止。
使用 SACK 不会增加 TCP 数据包的大小,除非连接遇到数据包丢失。因此,几乎没有理由禁用此功能。几乎所有的 TCP 协议栈都支持 SACK —— 它通常只在不进行 TCP 批量数据传输的低功耗 IOT 类的设备上才不存在。
当 Linux 系统接受来自此类设备的连接时TCP 会自动为受影响的连接禁用 SACK。
### 总结
本文中研究的三个 TCP 扩展都与 TCP 性能有关,最好都保留其默认设置:启用。
TCP 握手可确保仅使用双方都可以理解的扩展,因此,永远不需因为对等方可能不支持而全局禁用该扩展。
关闭这些扩展会导致严重的性能损失,尤其是 TCP 窗口缩放和 SACK。可以禁用 TCP 时间戳而不会立即造成不利影响,但是现在没有令人信服的理由这样做了。启用它们还可以支持 TCP 选项,即使在 SYN cookie 生效时也是如此。
--------------------------------------------------------------------------------
via: https://fedoramagazine.org/tcp-window-scaling-timestamps-and-sack/
作者:[Florian Westphal][a]
选题:[lujun9972][b]
译者:[gxlct008](https://github.com/gxlct008)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://fedoramagazine.org/author/strlen/
[b]: https://github.com/lujun9972
[1]: https://fedoramagazine.org/wp-content/uploads/2020/08/tcp-window-scaling-816x346.png
[2]: https://en.wikipedia.org/wiki/Transmission_Control_Protocol#TCP_segment_structure
[3]: https://www.rfc-editor.org/info/rfc7323
[4]: https://en.wikipedia.org/wiki/SYN_cookies
[5]: https://www.rfc-editor.org/info/rfc2018

View File

@ -0,0 +1,266 @@
[#]: collector: (lujun9972)
[#]: translator: (robsean)
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-12732-1.html)
[#]: subject: (Learn the basics of programming with C)
[#]: via: (https://opensource.com/article/20/8/c-programming-cheat-sheet)
[#]: author: (Seth Kenlon https://opensource.com/users/seth)
C 语言简单编程速成
======
> 我们将所有的 C 语言要素放置到一份易读的备忘录上。
![](https://img.linux.net.cn/data/attachment/album/202010/18/213610t3do3u7oev2udoyn.png)
1972 年,<ruby>丹尼斯·里奇<rt>Dennis Ritchie</rt></ruby>任职于<ruby>贝尔实验室<rt>Bell Labs</rt></ruby>,在几年前,他和他的团队成员发明了 Unix 。在创建了一个经久不衰的操作系统(至今仍在使用)之后,他需要一种好的方法来对这些 Unix 计算机编程以便它们可用执行新的任务。在现在看来这很奇怪但在当时编程语言相对较少Fortran、Lisp、[Algol][2] 以及 B 语言都很流行,但是,对于贝尔实验室的研究员们想要做的事情来说,它们还是远远不够的。丹尼斯·里奇表现出一种后来被称为程序员的主要特征的特质:创造了他自己的解决方案。他称之为 C 语言,并且在近 50 年后,它仍在广泛的使用。
### 为什么你应该学习 C 语言
今天,有很多语言为程序员提供了比 C 语言更多的特性。最明显的是 C++ 语言,这是一种以相当露骨的方式命名的语言,它构建在 C 语言之上,创建了一种很好的面向对象语言。不过,许多其它语言的存在是有充分理由的。计算机擅长一致的重复,因此任何可预见的东西都可以构建在编程语言中,对程序员来说这意味着更少的工作量。为什么在 C++ 语言中用一行语句就可以将一个 `int` 转换为一个 `long` 时(`long x = long(n);`),还要在 C 语言用两行语句呢?
然而C 语言在今天仍然有用。
首先C 语言是一种相当简约和直接的语言。除了编程的基础知识之外,并没有很高级的概念,这很大程度上是因为 C 语言实际上就是现代编程语言的基础之一。例如C 语言的特性之一是数组,但是它不提供字典(除非你自己写一个)。当你学习 C 语言时,你会学习编程的基础组成部分,它可以帮助你认识到如今的编程语言的改进及其的精心设计。
因为 C 语言是一种最小化的编程语言,你的应用程序很可能会获得性能上的提升,这在其它许多编程语言中是看不到的。当你考虑你的代码可以执行多快的时候,很容易陷入锱铢必较的境地,因此,重要的是要问清楚你是否*需要*为某一特定任务提供更多的速度。与 Python 或 Java 相比,使用 C 语言你在每行代码中需要纠结的地方更少。C 语言程序运行很快。这是 Linux 内核使用 C 语言编写的一个很好的理由。
最后C 语言很容易入门,特别是,如果你正在运行 Linux就已经能运行 C 语言代码了,因为 Linux 系统包含 GNU C 库(`glibc`)。为了编写和构建 C 语言程序,你需要做的全部工作就是安装一个编译器,打开一个文本编辑器,开始编码。
### 开始学习 C 语言
如果你正在运行 Linux ,你可以使用你的软件包管理器安装一个 C 编译器。在 Fedora 或 RHEL 上:
```
$ sudo dnf install gcc
```
在 Debian 及其衍生系统上:
```
$ sudo apt install build-essential
```
在 macOS 上,你可以 [安装 Homebrew][3] ,并使用它来安装 [GCC][4]
```
$ brew install gcc
```
在 Windows 上, 你可以使用 [MinGW][5] 安装一套最小的包含 GCC 的 GNU 实用程序集。
在 Linux 或 macOS 上验证你已经安装的 GCC
```
$ gcc --version
gcc (GCC) x.y.z
Copyright (C) 20XX Free Software Foundation, Inc.
```
在 Windows 上,提供 EXE 文件的完整路径:
```
PS> C:\MinGW\bin\gcc.exe --version
gcc.exe (MinGW.org GCC Build-2) x.y.z
Copyright (C) 20XX Free Software Foundation, Inc.
```
### C 语法
C 语言不是一种脚本语言。它是一种编译型语言,这意味着它由 C 编译器处理来产生一个二进制可执行文件。这不同于脚本语言(如 [Bash][6])或混合型语言(如 [Python][7])。
在 C 语言中,你可以创建*函数*来执行你希望做到的任务。默认情况下,执行的是一个名为 `main` 的函数。
这里是一个使用 C 语言写的简单的 “hello world” 程序:
```
#include <stdio.h>
int main() {
printf("Hello world");
return 0;
}
```
第一行包含一个被称为 `stdio.h`(标准输入和输出)的 *头文件*,它基本上是自由使用的、非常初级的 C 语言代码,你可以在你自己的程序中重复使用它。然后创建了一个由一条基本的输出语句构成的名为 `main` 的函数。保存这些文本到一个被称为 `hello.c` 的文件中,然后使用 GCC 编译它:
```
$ gcc hello.c --output hello
```
尝试运行你的 C 语言程序:
```
$ ./hello
Hello world$
```
#### 返回值
这是 Unix 哲学的一部分,一个函数在执行后“返回”一些东西:在成功时不返回任何东西,在失败时返回其它的一些东西(例如,一个错误信息)。这些返回的内容通常使用数字(确切地说是整数)表示:`0` 表示没有错误,任何大于 `0` 的数字都表示一些不成功的状态。
Unix 和 Linux 被设计成在运行成功时保持沉默是很明智的。这是为了让你在执行一系列命令时,假设没有任何错误或警告会妨碍你的工作,从而可以始终为成功执行做准备。类似地,在 C 语言中的函数在设计上也预期不出现错误。
你可以通过一个小的修改,让你的程序看起来是失败的,就可以看到这一点:
```
include <stdio.h>
int main() {
printf("Hello world");
return 1;
}
```
编译它:
```
$ gcc hello.c --output failer
```
现在使用一个内置的 Linux 测试方式来运行它。仅在*成功*时,`&&` 操作符才会执行一个命令的第二部分。例如:
```
$ echo "success" && echo "it worked"
success
it worked
```
在*失败*时,`||` 测试会执行一个命令的第二部分。
```
$ ls blah || echo "it did not work"
ls: cannot access 'blah': No such file or directory
it did not work
```
现在,尝试你的程序,在成功时,它*不*返回 `0`;而是返回 `1`
```
$ ./failer && echo "it worked"
String is: hello
```
这个程序成功地执行了,但是没有触发第二个命令。
#### 变量和类型
在一些语言中,你可以创建变量而不具体指定变量所包含的数据的*类型*。这些语言如此设计使得解释器需要对一个变量运行一些测试来视图发现变量是什么样的数据类型。例如,`var=1` 定义了一个整型数,当你创建一个表达式将 `var` 与某些东西相加时Python 知道显然它是一个整型数。它同样知道当你连接 `hello``world` 时,单词 `world` 是一个字符串。
C 语言不会为你做任何这些识别和调查;你必须自己定义你的变量类型。这里有几种变量类型,包括整型(`int`),字符型(`char`),浮点型(`float`),布尔型(`boolean`)。
你可能也注意到这里没有字符串类型。与 Python 和 Java 和 Lua 以及其它的编程语言不同C 语言没有字符串类型,而是将字符串看作一个字符数组。
这里是一些简单的代码,它建立了一个 `char` 数组变量,然后使用 [printf][9] 将数组变量和一段简单的信息打印到你的屏幕上:
```
#include <stdio.h>
int main() {
char var[6] = "hello";
printf("Your string is: %s\r\n",var);
}
```
你可能会注意到,这个代码示例向一个由五个字母组成的单词提供了六个字符的空间。这是因为在字符串的结尾有处一个隐藏的终止符,它占用了数组中的一个字节。你可以通过编译和执行代码来运行它:
```
$ gcc hello.c --output hello
$ ./hello
hello
```
### 函数
和其它的编程语言一样C 函数也接受可选的参数。你可以通过定义你希望函数接受的数据类型,来将参数从一个函数传递到另一个函数:
```
#include <stdio.h>
int printmsg(char a[]) {
printf("String is: %s\r\n",a);
}
int main() {
char a[6] = "hello";
printmsg(a);
return 0;
}
```
简单地将一个函数分解为两个函数的这种方法并不是非常有用,但是它演示了默认运行 `main` 函数以及如何在函数之间传递数据。
### 条件语句
在真实的编程中,你通常希望你的代码根据数据做出判断。这是使用*条件*语句完成的,`if` 语句是其中最基础的一个语句。
为了使这个示例程序更具动态性,你可以包含 `string.h` 头文件,顾名思义,它包含用于检查字符串的代码。尝试使用来自 `string.h` 文件中的 `strlen` 函数测试传递给 `printmsg` 函数的字符串是否大于 `0`
```
#include <stdio.h>
#include <string.h>
int printmsg(char a[]) {
size_t len = strlen(a);
if ( len > 0) {
printf("String is: %s\r\n",a);
}
}
int main() {
char a[6] = "hello";
printmsg(a);
return 1;
}
```
正如在这个示例中所实现的,该条件永远都不会是非真的,因为所提供的字符串总是 `hello`,它的长度总是大于 `0`。这个不够认真的重新实现的 `echo` 命令的最后一点要做是接受来自用户的输入。
### 命令参数
`stdio.h` 文件包含的代码在每次程序启动时提供了两个参数: 一个是命令中包含多少项的计数(`argc`),一个是包含每个项的数组(`argv`)。例如, 假设你发出这个虚构的命令:
```
$ foo -i bar
```
`argc``3``argv` 的内容是:
* `argv[0] = foo`
* `argv[1] = -i`
* `argv[2] = bar`
你可以修改示例 C 语言程序来以字符串方式接受 `argv[2]`,而不是默认的 `hello` 吗?
### 命令式编程语言
C 语言是一种命令式编程语言。它不是面向对象的,也没有类结构。使用 C 语言的经验可以教你很多关于如何处理数据,以及如何更好地管理你的代码运行时生成的数据。多使用 C 语言,你最后能够编写出其它语言(例如 Python 和 Lua可以使用的库。
想要了解更多关于 C 的知识,你需要使用它。在 `/usr/include/` 中查找有用的 C 语言头文件,并且看看你可以做什么小任务来使 C 语言对你有用。在学习的过程中,使用来自 FreeDOS 的 [Jim Hall][12] 编写的 [C 语言忘备录][11]。它在一张双面纸忘备录上放置了所有的基本要素,所以在你练习时,可以立即访问 C 语言语法的所有要素。
--------------------------------------------------------------------------------
via: https://opensource.com/article/20/8/c-programming-cheat-sheet
作者:[Seth Kenlon][a]
选题:[lujun9972][b]
译者:[robsean](https://github.com/robsean)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://opensource.com/users/seth
[b]: https://github.com/lujun9972
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/coverimage_cheat_sheet.png?itok=lYkNKieP (Cheat Sheet cover image)
[2]: https://opensource.com/article/20/6/algol68
[3]: https://opensource.com/article/20/6/homebrew-mac
[4]: https://gcc.gnu.org/
[5]: https://opensource.com/article/20/8/gnu-windows-mingw
[6]: https://opensource.com/resources/what-bash
[7]: https://opensource.com/resources/python
[8]: http://www.opengroup.org/onlinepubs/009695399/functions/printf.html
[9]: https://opensource.com/article/20/8/printf
[10]: http://www.opengroup.org/onlinepubs/009695399/functions/strlen.html
[11]: https://opensource.com/downloads/c-programming-cheat-sheet
[12]: https://opensource.com/users/jim-hall

View File

@ -0,0 +1,95 @@
[#]: collector: (lujun9972)
[#]: translator: (wxy)
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-12688-1.html)
[#]: subject: (What is IPv6, and why arent we there yet?)
[#]: via: (https://www.networkworld.com/article/3254575/what-is-ipv6-and-why-aren-t-we-there-yet.html)
[#]: author: (Keith Shaw, Josh Fruhlinger )
什么是 IPv6为什么我们还未普及
======
> 自 1998 年以来IPv6 一直在努力解决 IPv4 可用 IP 地址的不足的问题,然而尽管 IPv6 在效率和安全方面具有优势,但其采用速度仍然缓慢。
![](https://images.idgesg.net/images/article/2017/11/ipv6newip-100740801-large.jpg)
在大多数情况下,已经没有人一再对互联网地址耗尽的可怕境况发出警告,因为,从互联网协议版本 4IPv4的世界到 IPv6 的迁移,虽然缓慢,但已经坚定地开始了,并且相关软件已经到位,以防止许多人预测的地址耗竭。
但在我们看到 IPv6 的现状和发展方向之前,让我们先回到互联网寻址的早期。
### 什么是 IPv6为什么它很重要
IPv6 是最新版本的<ruby>互联网协议<rt>Internet Protocol</rt></ruby>IP它可以跨互联网识别设备从而确定它们的位置。每一个使用互联网的设备都要通过自己的 IP 地址来识别,以便可以通过互联网通信。在这方面,它就像你需要知道街道地址和邮政编码一样,以便邮寄信件。
之前的版本 IPv4 采用 32 位寻址方案,可以支持 43 亿台设备,本以为已经足够。然而,互联网、个人电脑、智能手机以及现在物联网设备的发展证明,这个世界需要更多的地址。
幸运的是,<ruby>互联网工程任务组<rt>Internet Engineering Task Force</rt></ruby>IETF在 20 年前就认识到了这一点。1998 年,它创建了 IPv6使用 128 位寻址方式来支持大约 340 <ruby>亿亿亿<rt>trillion trillion</rt></ruby>(或者 2 的 128 次幂如果你喜欢用这种表示方式的话。IPv4 的地址可表示为四组一至三位十进制数IPv6 则使用八组四位十六进制数字,用冒号隔开。
### IPv6 的好处是什么?
IETF 在其工作中为 IPv6 加入了对 IPv4 增强的功能。IPv6 协议可以更有效地处理数据包提高性能和增加安全性。它使互联网服务提供商ISP能够通过使他们的路由表更有层次性来减少其大小。
### 网络地址转换NAT和 IPv6
IPv6 的采用被推迟,部分原因是<ruby>网络地址转换<rt>network address translation</rt></ruby>NAT导致的NAT 可以将私有 IP 地址转化为公共 IP 地址。这样一来,拥有私有 IP 地址的企业的机器就可以向位于私有网络之外拥有公共 IP 地址的机器发送和接收数据包。
如果没有 NAT拥有数千台或数万台计算机的大公司如果要与外界通信就会吞噬大量的公有 IPv4 地址。但是这些 IPv4 地址是有限的,而且接近枯竭,以至于不得不限制分配。
NAT 有助于缓解这个问题。有了 NAT成千上万的私有地址计算机可以通过防火墙或路由器等 NAT 设备呈现在公共互联网上。
NAT 的工作方式是,当一台拥有私有 IP 地址的企业计算机向企业网络外的公共 IP 地址发送数据包时,首先会进入 NAT 设备。NAT 在翻译表中记下数据包的源地址和目的地址。NAT 将数据包的源地址改为 NAT 设备面向公众的地址并将数据包一起发送到外部目的地。当数据包回复时NAT 将目的地址翻译成发起通信的计算机的私有 IP 地址。这样一来,一个公网 IP 地址可以代表多台私有地址的计算机。
### 谁在部署 IPv6
运营商网络和互联网服务供应商是最早开始在其网络上部署 IPv6 的群体其中移动网络处于领先地位。例如T-Mobile USA 有超过 90% 的流量通过 IPv6Verizon Wireless 紧随其后,占 82.25%。根据行业组织 [World Ipv6 Launch][3] 的数据Comcast 和 AT&T 的网络分别为 63% 和 65%。
主要网站则排在其后 —— World IPv6 Launch 称,目前 Alexa 前 1000 的网站中只有不到 30% 可以通过 IPv6 到达。
企业在部署方面比较落后,根据<ruby>互联网协会<rt>Internet Society</rt></ruby>的[《2017年 IPv6 部署状况》报告][4],只有不到四分之一的企业宣传其 IPv6 前缀。复杂性、成本和完成迁移所需时间都是他们给出的理由。此外,一些项目由于软件兼容性的问题而被推迟。例如,一份 [2017 年 1 月的报告][5]称Windows 10 中的一个 bug “破坏了微软在其西雅图总部推出纯 IPv6 网络的努力”。
### 何时会有更多部署?
互联网协会表示IPv4 地址的价格将在 2018 年达到顶峰,然后在 IPv6 部署通过 50% 大关后,价格会下降。目前,[根据 Google][6],全球的 IPv6 采用率为 20% 到 22%,但在美国约为 32%。
随着 IPv4 地址的价格开始下降,互联网协会建议企业出售现有的 IPv4 地址,以帮助资助其 IPv6 的部署。根据[一个发布在 GitHub 上的说明][7],麻省理工学院已经这样做了。这所大学得出的结论是,其有 800 万个 IPv4 地址是“过剩”的,可以在不影响当前或未来需求的情况下出售,因为它还持有 20 个<ruby>非亿级<rt>nonillion</rt></ruby> IPv6 地址。(非亿级地址是指数字 1 后面跟着 30 个零)。
此外,随着部署的增多,更多的公司将开始对 IPv4 地址的使用收费,而免费提供 IPv6 服务。[英国的 ISP Mythic Beasts][8] 表示“IPv6 连接是标配”,而 “IPv4 连接是可选的额外服务”。
### IPv4 何时会被“关闭”?
在 2011 年至 2018 年期间,世界上大部分地区[“用完”了新的 IPv4 地址][9] —— 但我们不会完全没有 IPv4 地址,因为 IPv4 地址会被出售和重新使用(如前所述),而剩余的地址将用于 IPv6 过渡。
目前还没有正式的 IPv4 关闭日期,所以人们不用担心有一天他们的互联网接入会突然消失。随着越来越多的网络过渡,越来越多的内容网站支持 IPv6以及越来越多的终端用户为 IPv6 功能升级设备,世界将慢慢远离 IPv4。
### 为什么没有 IPv5
曾经有一个 IPv5也被称为<ruby>互联网流协议<rt>Internet Stream Protocol</rt></ruby>,简称 ST。它被设计用于跨 IP 网络的面向连接的通信,目的是支持语音和视频。
它在这个任务上是成功的,并被实验性地使用。它的一个缺点是它的 32 位地址方案 —— 与 IPv4 使用的方案相同,从而影响了它的普及。因此,它存在着与 IPv4 相同的问题 —— 可用的 IP 地址数量有限。这导致了发展出了 IPv6 并和最终得到采用。尽管 IPv5 从未被公开采用,但它已经用掉了 IPv5 这个名字。
--------------------------------------------------------------------------------
via: https://www.networkworld.com/article/3254575/what-is-ipv6-and-why-aren-t-we-there-yet.html
作者:[Keith Shaw][a],[Josh Fruhlinger][c]
选题:[lujun9972][b]
译者:[wxy](https://github.com/wxy)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://www.networkworld.com/author/Keith-Shaw/
[c]: https://www.networkworld.com/author/Josh-Fruhlinger/
[b]: https://github.com/lujun9972
[1]: https://www.networkworld.com/article/3235805/lan-wan/ipv6-deployment-guide.html#tk.nww-fsb
[2]: https://www.networkworld.com/article/3214388/lan-wan/how-to-plan-your-migration-to-ipv6.html#tk.nww-fsb
[3]: http://www.worldipv6launch.org/measurements/
[4]: https://www.internetsociety.org/resources/doc/2017/state-of-ipv6-deployment-2017/
[5]: https://www.theregister.co.uk/2017/01/19/windows_10_bug_undercuts_ipv6_rollout/https://www.theregister.co.uk/2017/01/19/windows_10_bug_undercuts_ipv6_rollout/
[6]: https://www.google.com/intl/en/ipv6/statistics.html
[7]: https://gist.github.com/simonster/e22e50cd52b7dffcf5a4db2b8ea4cce0
[8]: https://www.mythic-beasts.com/sales/ipv6
[9]: https://ipv4.potaroo.net/
[10]: https://www.facebook.com/NetworkWorld/
[11]: https://www.linkedin.com/company/network-world

View File

@ -0,0 +1,245 @@
[#]: collector: (lujun9972)
[#]: translator: (gxlct008)
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-12693-1.html)
[#]: subject: (Create a mobile app with Flutter)
[#]: via: (https://opensource.com/article/20/9/mobile-app-flutter)
[#]: author: (Vitaly Kuprenko https://opensource.com/users/kooper)
使用 Flutter 创建 App
======
> 使用流行的 Flutter 框架开始你的跨平台开发之旅。
![](https://img.linux.net.cn/data/attachment/album/202010/07/112953m9g419z1gc2i07z1.jpg)
[Flutter][2] 是一个深受全球移动开发者欢迎的项目。该框架有一个庞大的、友好的爱好者社区,随着 Flutter 帮助程序员将他们的项目带入移动领域,这个社区还在继续增长。
本教程旨在帮助你开始使用 Flutter 进行移动开发。阅读之后,你将了解如何快速安装和设置框架,以便开始为智能手机、平板电脑和其他平台开发。
本操作指南假定你已在计算机上安装了 [Android Studio][3],并且具有一定的使用经验。
### 什么是 Flutter
Flutter 使得开发人员能够为多个平台构建应用程序,包括:
* Android
* iOS
* Web测试版
* macOS正在开发中
* Linux正在开发中
对 macOS 和 Linux 的支持还处于早期开发阶段,而 Web 支持预计很快就会发布。这意味着你可以立即试用其功能(如下所述)。
### 安装 Flutter
我使用的是 Ubuntu 18.04,但其他 Linux 发行版安装过程与之类似,比如 Arch 或 Mint。
#### 使用 snapd 安装
要使用 [Snapd][4] 在 Ubuntu 或类似发行版上安装 Flutter请在终端中输入以下内容
```
$ sudo snap install flutter --classic
$ sudo snap install flutter classic
flutter 0+git.142868f from flutter Team/ installed
```
然后使用 `flutter` 命令启动它。 首次启动时,该框架会下载到你的计算机上:
```
$ flutter
Initializing Flutter
Downloading https://storage.googleapis.com/flutter_infra[...]
```
下载完成后,你会看到一条消息,告诉你 Flutter 已初始化:
![Flutter initialized][5]
#### 手动安装
如果你没有安装 Snapd或者你的发行版不是 Ubuntu那么安装过程会略有不同。在这种情况下请[下载][7] 为你的操作系统推荐的 Flutter 版本。
![Install Flutter manually][8]
然后将其解压缩到你的主目录。
在你喜欢的文本编辑器中打开主目录中的 `.bashrc` 文件(如果你使用 [Z shell][9],则打开 `.zshc`)。因为它是隐藏文件,所以你必须首先在文件管理器中启用显示隐藏文件,或者使用以下命令从终端打开它:
```
$ gedit ~/.bashrc &
```
将以下行添加到文件末尾:
```
export PATH="$PATH:~/flutter/bin"
```
保存并关闭文件。 请记住,如果在你的主目录之外的其他位置解压 Flutter则 [Flutter SDK 的路径][10] 将有所不同。
关闭你的终端,然后再次打开,以便加载新配置。 或者,你可以通过以下命令使配置立即生效:
```
$ . ~/.bashrc
```
如果你没有看到错误,那说明一切都是正常的。
这种安装方法比使用 `snap` 命令稍微困难一些,但是它非常通用,可以让你在几乎所有的发行版上安装该框架。
#### 检查安装结果
要检查安装结果,请在终端中输入以下内容:
```
flutter doctor -v
```
你将看到有关已安装组件的信息。 如果看到错误,请不要担心。 你尚未安装任何用于 Flutter SDK 的 IDE 插件。
![Checking Flutter installation with the doctor command][11]
### 安装 IDE 插件
你应该在你的 [集成开发环境IDE][12] 中安装插件,以帮助它与 Flutter SDK 接口、与设备交互并构建代码。
Flutter 开发中常用的三个主要 IDE 工具是 IntelliJ IDEA社区版、Android Studio 和 VS Code或 [VSCodium][13])。我在本教程中使用的是 Android Studio但步骤与它们在 IntelliJ Idea社区版上的工作方式相似因为它们构建在相同的平台上。
首先,启动 Android Studio。打开 “Settings”进入 “Plugins” 窗格,选择 “Marketplace” 选项卡。在搜索行中输入 “Flutter”然后单击 “Install”。
![Flutter plugins][14]
你可能会看到一个安装 “Dart” 插件的选项;同意它。如果看不到 Dart 选项,请通过重复上述步骤手动安装它。我还建议使用 “Rainbow Brackets” 插件,它可以让代码导航更简单。
就这样!你已经安装了所需的所有插件。你可以在终端中输入一个熟悉的命令进行检查:
```
flutter doctor -v
```
![Checking Flutter plugins with the doctor command][15]
### 构建你的 “Hello World” 应用程序
要启动新项目,请创建一个 Flutter 项目:
1、选择 “New -> New Flutter project”。
![Creating a new Flutter plugin][16]
2、在窗口中选择所需的项目类型。 在这种情况下,你需要选择 “Flutter Application”。
3、命名你的项目为 `hello_world`。 请注意,你应该使用合并的名称,因此请使用下划线而不是空格。 你可能还需要指定 SDK 的路径。
![Naming a new Flutter plugin][17]
4、输入软件包名称。
你已经创建了一个项目!现在,你可以在设备上或使用模拟器启动它。
![Device options in Flutter][18]
选择你想要的设备,然后按 “Run”。稍后你将看到结果。
![Flutter demo on mobile device][19]
现在你可以在一个 [中间项目][20] 上开始工作了。
### 尝试 Flutter for web
在安装 Flutter 的 Web 组件之前,你应该知道 Flutter 目前对 Web 应用程序的支持还很原始。 因此,将其用于复杂的项目并不是一个好主意。
默认情况下,基本 SDK 中不启用 “Flutter for web”。 要打开它,请转到 beta 通道。 为此,请在终端中输入以下命令:
```
flutter channel beta
```
![flutter channel beta output][21]
接下来,使用以下命令根据 beta 分支升级 Flutter
```
flutter upgrade
```
![flutter upgrade output][22]
要使 “Flutter for web” 工作,请输入:
```
flutter config --enable-web
```
重新启动 IDE这有助于 Android Studio 索引新的 IDE 并重新加载设备列表。你应该会看到几个新设备:
![Flutter for web device options][23]
选择 “Chrome” 会在浏览器中启动一个应用程序, “Web Server” 会提供指向你的 Web 应用程序的链接,你可以在任何浏览器中打开它。
不过,现在还不是急于开发的时候,因为你当前的项目不支持 Web。要改进它请打开项目根目录下的终端然后输入
```
flutter create
```
此命令重新创建项目,并添加 Web 支持。 现有代码不会被删除。
请注意,目录树已更改,现在有了一个 `web` 目录:
![File tree with web directory][24]
现在你可以开始工作了。 选择 “Chrome”然后按 “Run”。 稍后,你会看到带有应用程序的浏览器窗口。
![Flutter web app demo][25]
恭喜你! 你刚刚为浏览器启动了一个项目,并且可以像其他任何网站一样继续使用它。
所有这些都来自同一代码库,因为 Flutter 使得几乎无需更改就可以为移动平台和 Web 编写代码。
### 用 Flutter 做更多的事情
Flutter 是用于移动开发的强大工具,而且它也是迈向跨平台开发的重要一步。 了解它,使用它,并将你的应用程序交付到所有平台!
--------------------------------------------------------------------------------
via: https://opensource.com/article/20/9/mobile-app-flutter
作者:[Vitaly Kuprenko][a]
选题:[lujun9972][b]
译者:[gxlct008](https://github.com/gxlct008)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://opensource.com/users/kooper
[b]: https://github.com/lujun9972
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/idea_innovation_mobile_phone.png?itok=RqVtvxkd (A person looking at a phone)
[2]: https://flutter.dev/
[3]: https://developer.android.com/studio
[4]: https://snapcraft.io/docs/getting-started
[5]: https://opensource.com/sites/default/files/uploads/flutter1_initialized.png (Flutter initialized)
[6]: https://creativecommons.org/licenses/by-sa/4.0/
[7]: https://flutter.dev/docs/get-started/install/linux
[8]: https://opensource.com/sites/default/files/uploads/flutter2_manual-install.png (Install Flutter manually)
[9]: https://opensource.com/article/19/9/getting-started-zsh
[10]: https://opensource.com/article/17/6/set-path-linux
[11]: https://opensource.com/sites/default/files/uploads/flutter3_doctor.png (Checking Flutter installation with the doctor command)
[12]: https://www.redhat.com/en/topics/middleware/what-is-ide
[13]: https://opensource.com/article/20/6/open-source-alternatives-vs-code
[14]: https://opensource.com/sites/default/files/uploads/flutter4_plugins.png (Flutter plugins)
[15]: https://opensource.com/sites/default/files/uploads/flutter5_plugincheck.png (Checking Flutter plugins with the doctor command)
[16]: https://opensource.com/sites/default/files/uploads/flutter6_newproject.png (Creating a new Flutter plugin)
[17]: https://opensource.com/sites/default/files/uploads/flutter7_projectname.png (Naming a new Flutter plugin)
[18]: https://opensource.com/sites/default/files/uploads/flutter8_launchflutter.png (Device options in Flutter)
[19]: https://opensource.com/sites/default/files/uploads/flutter9_demo.png (Flutter demo on mobile device)
[20]: https://opensource.com/article/18/6/flutter
[21]: https://opensource.com/sites/default/files/uploads/flutter10_beta.png (flutter channel beta output)
[22]: https://opensource.com/sites/default/files/uploads/flutter11_upgrade.png (flutter upgrade output)
[23]: https://opensource.com/sites/default/files/uploads/flutter12_new-devices.png (Flutter for web device options)
[24]: https://opensource.com/sites/default/files/uploads/flutter13_tree.png (File tree with web directory)
[25]: https://opensource.com/sites/default/files/uploads/flutter14_webapp.png (Flutter web app demo)

View File

@ -0,0 +1,142 @@
[#]: collector: (lujun9972)
[#]: translator: (HankChow)
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-12686-1.html)
[#]: subject: (A practical guide to learning awk)
[#]: via: (https://opensource.com/article/20/9/awk-ebook)
[#]: author: (Seth Kenlon https://opensource.com/users/seth)
awk 实用学习指南
======
> 下载我们的电子书,学习如何更好地使用 `awk`
![](https://img.linux.net.cn/data/attachment/album/202010/05/100648zcubcpww627627nw.jpg)
在众多 [Linux][2] 命令中,`sed`、`awk` 和 `grep` 恐怕是其中最经典的三个命令了。它们引人注目或许是由于名字发音与众不同,也可能是它们无处不在,甚至是因为它们存在已久,但无论如何,如果要问哪些命令很有 Linux 风格,这三个命令是当之无愧的。其中 `sed``grep` 已经有很多简洁的标准用法了,但 `awk` 的使用难度却相对突出。
在日常使用中,通过 `sed` 实现字符串替换、通过 `grep` 实现过滤,这些都是司空见惯的操作了,但 `awk` 命令相对来说是用得比较少的。在我看来,可能的原因是大多数人都只使用 `sed` 或者 `grep` 的一些变化实现某些功能,例如:
```
$ sed -e 's/foo/bar/g' file.txt
$ grep foo file.txt
```
因此,尽管你可能会觉得 `sed``grep` 使用起来更加顺手,但实际上它们还有更多更强大的作用没有发挥出来。当然,我们没有必要在这两个命令上钻研得很深入,但我有时会好奇自己“学习”命令的方式。很多时候我会记住一整串命令“咒语”,而不会去了解其中的运作过程,这就让我产生了一种很熟悉命令的错觉,我可以随口说出某个命令的好几个选项参数,但这些参数具体有什么作用,以及它们的相关语法,我都并不明确。
这大概就是很多人对 `awk` 缺乏了解的原因了。
### 为使用而学习 awk
`awk` 并不深奥。它是一种相对基础的编程语言,因此你可以把它当成一门新的编程语言来学习:使用一些基本命令来熟悉语法、了解语言中的关键字并实现更复杂的功能,然后再多加练习就可以了。
### awk 是如何解析输入内容的
`awk` 的本质是将输入的内容看作是一个数组。当 `awk` 扫描一个文本文件时,会把每一行作为一条<ruby>记录<rt>record</rt></ruby>,每一条记录中又分割为多个<ruby>字段<rt>field</rt></ruby>。`awk` 记录了各条记录各个字段的信息,并通过内置变量 `NR`(记录数) 和 `NF`(字段数) 来调用相关信息。例如一下这个命令可以查看文件的行数:
```
$ awk 'END { print NR;}' example.txt
36
```
从上面的命令可以看出 `awk` 的基本语法,无论是一个单行命令还是一整个脚本,语法都是这样的:
```
模式或关键字 { 操作 }
```
在上面的例子中,`END` 是一个关键字而不是模式,与此类似的另一个关键字是 `BEGIN`。使用 `BEGIN``END` 可以让 `awk` 在解析内容前或解析内容后执行大括号中指定的操作。
你可以使用<ruby>模式<rt>pattern</rt></ruby>作为过滤器或限定符,这样 `awk` 只会对匹配模式的对应记录执行指定的操作。以下这个例子就是使用 `awk` 实现 `grep` 命令在文件中查找“Linux”字符串的功能
```
$ awk '/Linux/ { print $0; }' os.txt
OS: CentOS Linux (10.1.1.8)
OS: CentOS Linux (10.1.1.9)
OS: Red Hat Enterprise Linux (RHEL) (10.1.1.11)
OS: Elementary Linux (10.1.2.4)
OS: Elementary Linux (10.1.2.5)
OS: Elementary Linux (10.1.2.6)
```
`awk` 会将文件中的每一行作为一条记录,将一条记录中的每个单词作为一个字段,默认情况下会以空格作为<ruby>字段分隔符<rt>field separator</rt></ruby>`FS`)切割出记录中的字段。如果想要使用其它内容作为分隔符,可以使用 `--field-separator` 选项指定分隔符:
```
$ awk --field-separator ':' '/Linux/ { print $2; }' os.txt
 CentOS Linux (10.1.1.8)
 CentOS Linux (10.1.1.9)
 Red Hat Enterprise Linux (RHEL) (10.1.1.11)
 Elementary Linux (10.1.2.4)
 Elementary Linux (10.1.2.5)
 Elementary Linux (10.1.2.6)
```
在上面的例子中,可以看到在 `awk` 处理后每一行的行首都有一个空格,那是因为在源文件中每个冒号(`:`)后面都带有一个空格。和 `cut` 有所不同的是,`awk` 可以指定一个字符串作为分隔符,就像这样:
```
$ awk --field-separator ': ' '/Linux/ { print $2; }' os.txt
CentOS Linux (10.1.1.8)
CentOS Linux (10.1.1.9)
Red Hat Enterprise Linux (RHEL) (10.1.1.11)
Elementary Linux (10.1.2.4)
Elementary Linux (10.1.2.5)
Elementary Linux (10.1.2.6)
```
### awk 中的函数
可以通过这样的语法在 `awk` 中自定义函数:
```
函数名称(参数) { 操作 }
```
函数的好处在于只需要编写一次就可以多次复用,因此函数在脚本中起到的作用会比在构造单行命令时大。同时 `awk` 自身也带有很多预定义的函数,并且工作原理和其它编程语言或电子表格一样。你只需要了解函数需要接受什么参数,就可以放心使用了。
`awk` 中提供了数学运算和字符串处理的相关函数。数学运算函数通常比较简单,传入一个数字,它就会传出一个结果:
```
$ awk 'BEGIN { print sqrt(1764); }'
42
```
而字符串处理函数则稍微复杂一点,但 [GNU awk 手册][3]中也有充足的文档。例如 `split()` 函数需要传入一个待分割的单一字段、一个用于存放分割结果的数组,以及用于分割的<ruby>定界符<rt>delimiter</rt></ruby>
例如前面示例中的输出内容,每条记录的末尾都包含了一个 IP 地址。由于变量 `NF` 代表的是每条记录的字段数量,刚好对应的是每条记录中最后一个字段的序号,因此可以通过引用 `NF` 将每条记录的最后一个字段传入 `split()` 函数:
```
$ awk --field-separator ': ' '/Linux/ { split($NF, IP, "."); print "subnet: " IP[3]; }' os.txt
subnet: 1
subnet: 1
subnet: 1
subnet: 2
subnet: 2
subnet: 2
```
还有更多的函数,没有理由将自己限制在每个 `awk` 代码块中。你可以在终端中使用 `awk` 构建复杂的管道,也可以编写 `awk` 脚本来定义和使用你自己的函数。
### 下载电子书
使用 `awk` 本身就是一个学习 `awk` 的过程,即使某些操作使用 `sed`、`grep`、`cut`、`tr` 命令已经完全足够了,也可以尝试使用 `awk` 来实现。只要熟悉了 `awk`,就可以在 Bash 中自定义一些 `awk` 函数,进而解析复杂的数据。
[下载我们的这本电子书][4](需注册)学习并开始使用 `awk` 吧!
--------------------------------------------------------------------------------
via: https://opensource.com/article/20/9/awk-ebook
作者:[Seth Kenlon][a]
选题:[lujun9972][b]
译者:[HankChow](https://github.com/hankchow)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://opensource.com/users/seth
[b]: https://github.com/lujun9972
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/computer_code_programming_laptop.jpg?itok=ormv35tV (Person programming on a laptop on a building)
[2]: https://opensource.com/resources/linux
[3]: https://www.gnu.org/software/gawk/manual/gawk.html
[4]: https://opensource.com/downloads/awk-ebook

View File

@ -0,0 +1,215 @@
[#]: collector: (lujun9972)
[#]: translator: (MjSeven)
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-12703-1.html)
[#]: subject: (How to install software with Ansible)
[#]: via: (https://opensource.com/article/20/9/install-packages-ansible)
[#]: author: (Seth Kenlon https://opensource.com/users/seth)
如何使用 Ansible 安装软件
======
> 使用 Ansible 剧本自动安装和更新设备上的软件。
![](https://img.linux.net.cn/data/attachment/album/202010/10/095024hh65atkh6cc8ntn9.jpg)
Ansible 是系统管理员和开发人员用来保持计算机系统处于最佳状态的一种流行的自动化工具。与可扩展框架一样,[Ansible][2] 本身功能有限它真正的功能体现在许多模块中。在某种程度上Ansible 模块就是 [Linux][3] 系统的命令。它们针对特定问题提供解决方案,而维护计算机时的一项常见任务是使所有计算机的更新和一致。
我曾经使用软件包的文本列表来保持系统或多或少的同步:我会列出笔记本电脑上安装的软件包,然后将其与台式机或另一台服务器之间进行交叉参考,手动弥补差异。当然,在 Linux 机器上安装和维护应用程序是 Ansible 的一项基本功能,这意味着你可以在自己关心的计算机上列出所需的内容。
### 寻找正确的 Ansible 模块
Ansible 模块的数量非常庞大,如何找到能完成你任务的模块?在 Linux 中,你可以在应用程序菜单或 `/usr/bin` 中查找要运行的应用程序。使用 Ansible 时,你可以参考 [Ansible 模块索引][4]。
这个索引按照类别列出。稍加搜索,你就很可能找到所需的模块。对于包管理,[Packaging 模块][5]几乎适用于所有带包管理器的系统。
### 动手写一个 Ansible 剧本
首先,选择本地计算机上的包管理器。例如,如果你打算在运行 Fedora 的笔记本电脑上编写 Ansible 指令(在 Ansible 中称为“<ruby>剧本<rt>playbook</rt></ruby>”),那么从 `dnf` 模块开始。如果你在 Elementary OS 上编写,使用 `apt` 模块,以此类推。这样你就可以开始进行测试和验证,并可以在以后扩展到其它计算机。
第一步是创建一个代表你的剧本的目录。这不是绝对必要的但这是一个好习惯。Ansible 只需要一个配置文件就可以运行在 YAML 中,但是如果你以后想要扩展剧本,你就可以通过改变目录和文件的方式来控制 Ansible。现在只需创建一个名为 `install_packages` 或类似的目录:
```
$ mkdir ~/install_packages
```
你可以根据自己的喜好来命名 Ansible 的剧本,但通常将其命名为 `site.yml`
```
$ touch ~/install_packages/site.yml
```
在你最喜欢的文本编辑器中打开 `site.yml`,添加以下内容:
```
---
- hosts: localhost
tasks:
- name: install packages
become: true
become_user: root
dnf:
state: present
name:
- tcsh
- htop
```
你必须调整使用的模块名称以匹配你使用的发行版。在此示例中,我使用 `dnf` 是因为我在 Fedora Linux 上编写剧本。
就像 Linux 终端中的命令一样,知道 **如何** 来调用 Ansible 模块就已经成功了一半。这个示例剧本遵循标准剧本格式:
* `hosts` 是一台或多台计算机。在本示例中,目标计算机是 `localhost`,即你当前正在使用的计算机(而不是你希望 Ansible 连接的远程系统)。
* `tasks` 是你要在主机上执行的任务列表。
* `name` 是任务的人性化名称。在这种情况下,我使用 `install packages`,因为这就是该任务正在做的事情。
* `become` 允许 Ansible 更改运行此任务的用户。
* `become_user` 允许 Ansible 成为 `root` 用户来运行此任务。这是必须的,因为只有 root 用户才能使用 `dnf` 安装应用程序。
* `dnf` 是模块名称,你可以在 Ansible 网站上的模块索引中找到。
`dnf` 下的节点是 `dnf` 模块专用的。这是模块文档的关键所在。就像 Linux 命令的手册页一样,模块文档会告诉你可用的选项和所需的参数。
![Ansible 文档][6]
安装软件包是一个相对简单的任务,仅需要两个元素。`state` 选项指示 Ansible 检查系统上是否存在 **软件包**,而 `name` 选项列出要查找的软件包。Ansible 会针对机器的 **状态** 进行调整,因此模块指令始终意味着更改。假如 Ansible 扫描了系统状态,发现剧本里描述的系统(在本例中,`tcsh` 和 `htop` 存在)与实际状态存在冲突,那么 Ansible 的任务是进行必要的更改来使系统与剧本匹配。Ansible 可以通过 `dnf`(或 `apt` 或者其它任何包管理器)模块进行更改。
每个模块可能都有一组不同的选项,所以在编写剧本时,要经常参考模块文档。除非你对模块非常熟悉,否则这是期望模块完成工作的唯一合理方法。
### 验证 YAML
剧本是用 YAML 编写的。因为 YAML 遵循严格的语法,所以安装 `yamllint` 来检查剧本是很有帮助的。更妙的是,有一个专门针对 Ansible 的检查工具称为 `ansible-lint`,它专门为剧本而生。在继续之前,安装它。
在 Fedora 或 CentOs 上:
```
$ sudo dnf ins tall yamllint python3-ansible-lint
```
在 Debian、Elementary 或 Ubuntu 上,同样的:
```
$ sudo apt install yamllint ansible-lint
```
使用 `ansible-link` 来验证你的剧本。如果你无法使用 `ansible-lint`,你可以使用 `yamllint`
```
$ ansible-lint ~/install_packages/site.yml
```
成功则不返回任何内容,但如果文件中有错误,则必须先修复它们,然后再继续。复制和粘贴过程中的常见错误包括在最后一行的末尾省略换行符、使用制表符而不是空格来缩进。在文本编辑器中修复它们,重新运行 `ansible-lint`,重复这个过程,直到 `ansible-lint``yamllint` 没有返回为止。
### 使用 Ansible 安装一个应用
现在你有了一个可验证的有效剧本,你终于可以在本地计算机上运行它了,因为你碰巧知道该剧本定义的任务需要 root 权限,所以在调用 Ansible 时必须使用 `--ask-become-pass` 选项,因此系统会提示你输入管理员密码。
开始安装:
```
$ ansible-playbook --ask-become-pass ~/install_packages/site.yml
BECOME password:
PLAY [localhost] ******************************
TASK [Gathering Facts] ******************************
ok: [localhost]
TASK [install packages] ******************************
ok: [localhost]
PLAY RECAP ******************************
localhost: ok=0 changed=2 unreachable=0 failed=0 [...]
```
这些命令被执行后,目标系统将处于与剧本中描述的相同的状态。
### 在远程系统上安装应用程序
通过这么多操作来替换一个简单的命令可能会适得其反,但是 Ansible 的优势是它可以在你的所有系统中实现自动化。你可以使用条件语句使 Ansible 在不同的系统上使用特定的模块,但是现在,假定所有计算机都使用相同的包管理器。
要连接到远程系统,你必须在 `/etc/ansible/hosts` 文件中定义远程系统,该文件与 Ansible 是一起安装的,所以它已经存在了,但它可能是空的,除了一些解释性注释之外。使用 `sudo` 在你喜欢的文本编辑器中打开它。
你可以通过其 IP 地址或主机名(只要主机名可以解析)定义主机。例如,如果你已经在 `/etc/hosts` 中定义了 `liavara` 并可以成功 `ping` 通,那么你可以在 `/etc/ansible/hosts` 中将 `liavara` 设置为主机。或者,如果你正在运行一个域名服务器或 Avahi 服务器并且可以 `ping``liavara`,那么你就可以在 `/etc/ansible/hosts` 中定义它。否则,你必须使用它的 IP 地址。
你还必须成功地建立与目标主机的安全 shellSSH连接。最简单的方法是使用 `ssh-copy-id` 命令,但是如果你以前从未与主机建立 SSH 连接,[阅读我关于如何创建自动 SSH 连接的文章][8]。
一旦你在 `/etc/ansible/hosts` 文件中输入了主机名或 IP 地址后,你就可以在剧本中更改 `hosts` 定义:
```
---
- hosts: all
  tasks:
    - name: install packages
      become: true
      become_user: root
      dnf:
        state: present
        name:
         - tcsh
         - htop
```
再次运行 `ansible-playbook`
```
$ ansible-playbook --ask-become-pass ~/install_packages/site.yml
```
这次,剧本会在你的远程系统上运行。
如果你添加更多主机,则有许多方法可以过滤哪个主机执行哪个任务。例如,你可以创建主机组(服务器的 `webserves`,台式机的 `workstations`等)。
### 适用于混合环境的 Ansible
到目前为止,我们一直假定 Ansible 配置的所有主机都运行相同的操作系统(都是是使用 `dnf` 命令进行程序包管理的操作系统)。那么,如果你要管理不同发行版的主机,例如 Ubuntu使用 `apt`)或 Arch使用 `pacman`),或者其它的操作系统时,该怎么办?
只要目标操作系统具有程序包管理器([MacOs 有 Homebrew][9][Windows 有 Chocolatey][10]Ansible 就能派上用场。
这就是 Ansible 优势最明显的地方。在 shell 脚本中,你必须检查目标主机上有哪些可用的包管理器,即使使用纯 Python也必须检查操作系统。Ansible 不仅内置了这些功能,而且还具有在剧本中使用命令结果的机制。你可以使用 `action` 关键字来执行由 Ansible 事实收集子系统提供的变量定义的任务,而不是使用 `dnf` 模块。
```
---
- hosts: all
  tasks:
    - name: install packages
      become: true
      become_user: root
      action: >
       {{ ansible_pkg_mgr }} name=htop,transmission state=present update_cache=yes
```
`action` 关键字会加载目标插件。在本例中,它使用了 `ansible_pkg_mgr` 变量,该变量由 Ansible 在初始 **收集信息** 期间填充。你不需要告诉 Ansible 收集有关其运行操作系统的事实,所以很容易忽略这一点,但是当你运行一个剧本时,你会在默认输出中看到它:
```
TASK [Gathering Facts] *****************************************
ok: [localhost]
```
`action` 插件使用来自这个探针的信息,使用相关的包管理器命令填充 `ansible_pkg_mgr`,以安装在 `name` 参数之后列出的程序包。使用 8 行代码,你可以克服在其它脚本选项中很少允许的复杂跨平台难题。
### 使用 Ansible
现在是 21 世纪,我们都希望我们的计算机设备能够互联并且相对一致。无论你维护的是两台还是 200 台计算机,你都不必一次又一次地执行相同的维护任务。使用 Ansible 来同步生活中的计算机设备,看看 Ansible 还能为你做些什么。
--------------------------------------------------------------------------------
via: https://opensource.com/article/20/9/install-packages-ansible
作者:[Seth Kenlon][a]
选题:[lujun9972][b]
译者:[MjSeven](https://github.com/MjSeven)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://opensource.com/users/seth
[b]: https://github.com/lujun9972
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/puzzle_computer_solve_fix_tool.png?itok=U0pH1uwj (Puzzle pieces coming together to form a computer screen)
[2]: https://opensource.com/resources/what-ansible
[3]: https://opensource.com/resources/linux
[4]: https://docs.ansible.com/ansible/latest/modules/modules_by_category.html
[5]: https://docs.ansible.com/ansible/latest/modules/list_of_packaging_modules.html
[6]: https://opensource.com/sites/default/files/uploads/ansible-module.png (Ansible documentation)
[7]: https://creativecommons.org/licenses/by-sa/4.0/
[8]: https://opensource.com/article/20/8/how-ssh
[9]: https://opensource.com/article/20/6/homebrew-mac
[10]: https://opensource.com/article/20/3/chocolatey

View File

@ -0,0 +1,252 @@
[#]: collector: (lujun9972)
[#]: translator: (HankChow)
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-12766-1.html)
[#]: subject: (Automate your container orchestration with Ansible modules for Kubernetes)
[#]: via: (https://opensource.com/article/20/9/ansible-modules-kubernetes)
[#]: author: (Seth Kenlon https://opensource.com/users/seth)
使用 Ansible 的 Kubernetes 模块实现容器编排自动化
======
> 将 Kubernetes 与 Ansible 结合实现云端自动化。此外,还可以参照我们的 Ansible 的 k8s 模块速查表。
![](https://img.linux.net.cn/data/attachment/album/202010/28/211747jhlttlf3f81xrffi.jpg)
[Ansible][2] 是实现自动化工作的优秀工具,而 [Kubernetes][3] 则是容器编排方面的利器要是把两者结合起来会有怎样的效果呢正如你所猜测的Ansible + Kubernetes 的确可以实现容器编排自动化。
### Ansible 模块
实际上Ansible 本身只是一个用于解释 YAML 文件的框架。它真正强大之处在于它[丰富的模块][4],所谓<ruby>模块<rt>module</rt></ruby>,就是在 Ansible <ruby>剧本<rt>playbook</rt></ruby> 中让你得以通过简单配置就能调用外部应用程序的一些工具。
Ansible 中有模块可以直接操作 Kubernetes也有对一些相关组件例如 [Docker][5] 和 [Podman][6]实现操作的模块。学习使用一个新模块的过程和学习新的终端命令、API 一样,可以先从文档中了解这个模块在调用的时候需要接受哪些参数,以及这些参数在外部应用程序中产生的具体作用。
### 访问 Kubernetes 集群
在使用 Ansible Kubernetes 模块之前,先要有能够访问 Kubernetes 集群的权限。在没有权限的情况下,可以尝试使用一个短期在线试用账号,但我们更推荐的是按照 Kubernetes 官网上的指引,或是参考 Braynt Son 《[入门 Kubernetes][8]》的教程安装 [Minikube][7]。Minikube 提供了一个单节点 Kubernetes 实例的安装过程,你可以像使用一个完整集群一样对其进行配置和交互。
- 下载 [Ansible k8s 速记表][9](需注册)
在安装 Minikube 之前,你需要确保你的环境支持虚拟化并安装 `libvirt`,然后对 `libvirt` 用户组授权:
```
$ sudo dnf install libvirt
$ sudo systemctl start libvirtd
$ sudo usermod --append --groups libvirt `whoami`
$ newgrp libvirt
```
#### 安装 Python 模块
为了能够在 Ansible 中使用 Kubernetes 相关的模块,你需要安装以下这些 Python 模块:
```
$ pip3.6 install kubernetes --user
$ pip3.6 install openshift --user
```
#### 启动 Kubernetes
如果你使用的是 Minikube 而不是完整的 Kubernetes 集群,请使用 `minikube` 命令在本地创建一个最精简化的 Kubernetes 实例:
```
$ minikube start --driver=kvm2 --kvm-network default
```
然后等待 Minikube 完成初始化,这个过程所需的时间会因实际情况而异。
### 获取集群信息
集群启动以后,通过 `cluster-info` 选项就可以获取到集群相关信息了:
```
$ kubectl cluster-info
Kubernetes master is running at https://192.168.39.190:8443
KubeDNS is running at https://192.168.39.190:8443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
```
### 使用 k8s 模块
Ansible 使用 `k8s` 这个模块来实现对 Kubernetes 的操作,在剧本中使用 `k8s` 模块就可以对 Kuvernetes 对象进行管理。这个模块描述了 `kubectl` 命令的最终状态,例如对于以下这个使用 `kubectl` 创建新的[命名空间][10]的操作:
```
$ kubectl create namespace my-namespace
```
这是一个很简单的操作,而对这个操作的最终状态用 YAML 文件来描述是这样的:
```
- hosts: localhost
  tasks:
    - name: create namespace
      k8s:
        name: my-namespace
        api_version: v1
        kind: Namespace
        state: present
```
如果你使用的是 Minikube那么主机名`hosts`)应该定义为 `localhost`。需要注意的是,所使用的模块也定义了可用参数的语法(例如 `api_version``kind` 参数)。
在运行这个剧本之前,先通过 `yamllint` 命令验证是否有错误:
```
$ yamllint example.yaml
```
确保没有错误之后,运行剧本:
```
$ ansible-playbook ./example.yaml
```
可以验证新的命名空间是否已经被创建出来:
```
$ kubectl get namespaces
NAME              STATUS   AGE
default           Active   37h
kube-node-lease   Active   37h
kube-public       Active   37h
kube-system       Active   37h
demo              Active   11h
my-namespace      Active   3s
```
### 使用 Podman 拉取容器镜像
容器是个 Linux 系统,几乎是最小化的,可以由 Kubernetes 管理。[LXC 项目][11]和 Docker 定义了大部分的容器规范。最近加入容器工具集的是 Podman它不需要守护进程就可以运行为此受到了很多用户的欢迎。
通过 Podman 可以从 Docker Hub 或者 Quay.io 等存储库拉取容器镜像。这一操作对应的 Ansible 语法也很简单,只需要将存储库网站提供的镜像路径写在剧本中的相应位置就可以了:
```
   - name: pull an image
      podman_image:
        name: quay.io/jitesoft/nginx
```
使用 `yamllint` 验证:
```
$ yamllint example.yaml
```
运行剧本:
```
$ ansible-playbook ./example.yaml
[WARNING]: provided hosts list is empty, only localhost is available.
Note that the implicit localhost does not match 'all'
PLAY [localhost] ************************
TASK [Gathering Facts] ************************
ok: [localhost]
TASK [create k8s namespace] ************************
ok: [localhost]
TASK [pull an image] ************************
changed: [localhost]
PLAY RECAP ************************
localhost: ok=3 changed=1 unreachable=0 failed=0
           skipped=0 rescued=0 ignored=0
```
### 使用 Ansible 实现部署
Ansible 除了可以执行小型维护任务以外,还可以通过剧本实现其它由 `kubectl` 实现的功能,因为两者的 YAML 文件之间只有少量的差异。在 Kubernetes 中使用的 YAML 文件只需要稍加改动,就可以在 Ansible 剧本中使用。例如下面这个用于使用 `kubectl` 命令部署 Web 服务器的 YAML 文件:
```
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-webserver
spec:
  selector:
    matchLabels:
      run: my-webserver
  replicas: 1
  template:
    metadata:
      labels:
        run: my-webserver
    spec:
      containers:
      - name: my-webserver
        image: nginx
        ports:
        - containerPort: 80
```
如果你对其中的参数比较熟悉,你只要把 YAML 文件中的大部分内容放到剧本中的 `definition` 部分,就可以在 Ansible 中使用了:
```
   - name: deploy a web server
      k8s:
        api_version: v1
        namespace: my-namespace
        definition:
          kind: Deployment
          metadata:
            labels:
              app: nginx
            name: nginx-deploy
          spec:
            replicas: 1
            selector:
              matchLabels:
                app: nginx
            template:
              metadata:
                labels:
                  app: nginx
              spec:
                containers:
                  - name: my-webserver
                    image: quay.io/jitesoft/nginx
                    ports:
                      - containerPort: 80
                        protocol: TCP
```
执行完成后,使用 `kubectl` 命令可以看到预期中的的<ruby>部署<rt>deployment</rt></ruby>
```
$ kubectl -n my-namespace get pods
NAME                      READY  STATUS
nginx-deploy-7fdc9-t9wc2  1/1    Running
```
### 在云上使用模块
随着现在越来越多的开发和部署工作往云上转移的趋势,我们必须了解如何在云上实现自动化。其中 `k8s``podman_image` 这两个模块只是云开发中的其中一小部分。你可以在你的工作流程中寻找一些需要自动化的任务,并学习如何使用 Ansible 让你在这些任务上事半功倍。
--------------------------------------------------------------------------------
via: https://opensource.com/article/20/9/ansible-modules-kubernetes
作者:[Seth Kenlon][a]
选题:[lujun9972][b]
译者:[HankChow](https://github.com/HankChow)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://opensource.com/users/seth
[b]: https://github.com/lujun9972
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/ship_captain_devops_kubernetes_steer.png?itok=LAHfIpek (Ship captain sailing the Kubernetes seas)
[2]: https://opensource.com/resources/what-ansible
[3]: https://opensource.com/resources/what-is-kubernetes
[4]: https://docs.ansible.com/ansible/latest/modules/modules_by_category.html
[5]: https://opensource.com/resources/what-docker
[6]: http://podman.io
[7]: https://kubernetes.io/docs/tasks/tools/install-minikube
[8]: https://opensource.com/article/18/10/getting-started-minikube
[9]: https://opensource.com/downloads/ansible-k8s-cheat-sheet
[10]: https://opensource.com/article/19/10/namespaces-and-containers-linux
[11]: https://www.redhat.com/sysadmin/exploring-containers-lxc

View File

@ -0,0 +1,64 @@
[#]: collector: (lujun9972)
[#]: translator: (chenmu-kk)
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-12735-1.html)
[#]: subject: (NFC vs. Bluetooth LE: When to use which)
[#]: via: (https://www.networkworld.com/article/3574932/nfc-vs-bluetooth-le-when-to-use-which.html)
[#]: author: (Jon Gold https://www.networkworld.com/author/Jon-Gold/)
近场通信 vs. 低功耗蓝牙:如何抉择
======
> 近场通信NFC和低功耗蓝牙BLE是适合企业不同用途的低功耗无线技术。
![](https://images.idgesg.net/images/article/2020/08/distributed_network_of_wifi_wi-fi_internet_connections_across_cityscape_by_metamorworks_gettyimages-926502948_2400x1600-100855926-large.jpg)
在低功率、相对短距离连接的众多选择中有两种技术脱颖而出——近场通信NFC和低功耗蓝牙BLE。两者都具有相对低廉的部署成本且易于使用。
NFC 作为许多现代智能卡片的背后技术而为大众所熟知。NFC 芯片必须十分接近(在几厘米内)读卡器来实现连接,但这是它主要企业用例(安全性和访问控制)的一个优势。
BLE 是主要蓝牙标准的低功耗衍生品,以较低的潜在吞吐量换来了能耗的显著降低,从而能够适应更广泛的潜在用例。
接下来,我们将对每种技术及其主要用例进行更深入的描述。
### NFC 的未来
NFC 在近距离接触范围内工作(设备间必须靠近到几厘米范围内来进行连接),一个可读的无源 NFC “标签”根本不需要任何独立电源,它会从读卡器的信号中汲取能量,工作频率约为 13.5MHz,在主动读取芯片时需要 100-700µA 的电量。
“短距离实际上是它的优势。”Gartner 研究高级总监兼分析师说, “NFC 的一大优点是它不仅仅是无线电,还内置了一个庞大的安全协议。”也就是说,潜在的不良行为者必须非常接近——使用专用设备、在几米的范围内——才能检测到正在发生的 NFC 连接。NFC 还可以施行在 SSL 技术上面一层以提高安全性。
考虑到 NFC 本就起源于非接触式支付技术,这不足为奇。它在这一领域的根基在于对零售商的吸引力,零售商可以利用 NFC 让客户在购买商品前获取相关的信息、获得优惠券或者向店员寻求帮助,只需将手机接触到 NFC 热点即可。
尽管 NFC 只能在一个很近的范围内使用,这限制了使用 NFC 技术用例场景但它不仅仅是为了开门和买一杯拿铁。NFC 可以用于引导连接,便于设备间轻松快速的配对,因此用户只需在会议室中将手机贴近配备好的投影仪,即可创建一个 NFC 连接,并验证智能手机是否是一个可连接的授权设备,并进行演示。演示文稿或者视频数据本身不会通过 NFC 来传输,但是 NFC 握手可作为另外的无线协议(例如 Wi-Fi 网络或者任何其他更高带宽可以传输数据的网络)间的验证,从而无需用户登录。
### BLE 的特点
相较之下BLE 的工作距离要远的多(长达几十米),其最大带宽 1 Mbit/s 约为 NFC 连接的两倍。它是著名的蓝牙技术的产物,相较于主线标准的更低功耗,它为机器到机器的连接做了优化。在连接两端的耗电量均小于 15 mA实用范围约为 10米可通过 AES 加密保护连接。
然而,根据 Forrester 首席分析师 Andre Kindness 的说法,它远非 NFC 的替代品。
他说:“从信息传递角度来看, [NFC] 比 BLE 快得多。”BLE 通常需要几分之一秒或更长时间的验证并安全连接,而 NFC 几乎在瞬间完成连接。
不过,根据 IDC 高级研究分析师 Patrick Filkins 的说法,相较于 NFCBLE 由于范围更广而有着更多的通用性。
他说:“我认为 BLE 比较适合企业”。而类似于资产追踪、室内导航和目标广告的用例只是冰山一角。
对于企业结果是相当直接的——NFC 用例大多与公司使用蓝牙的用例是分开的对于少有的可以选择的重叠相对的优势和劣势显而易见。NFC 距离很短、价格便宜、可即时连接以及数据转换率较低。BLE 的工作距离更远、传输速率更高,成本也更高,连接时还需要一点时间来进行“握手”。
--------------------------------------------------------------------------------
via: https://www.networkworld.com/article/3574932/nfc-vs-bluetooth-le-when-to-use-which.html
作者:[Jon Gold][a]
选题:[lujun9972][b]
译者:[chenmu-kk](https://github.com/chenmu-kk)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://www.networkworld.com/author/Jon-Gold/
[b]: https://github.com/lujun9972
[1]: https://www.networkworld.com/newsletters/signup.html
[2]: https://www.facebook.com/NetworkWorld/
[3]: https://www.linkedin.com/company/network-world

View File

@ -0,0 +1,325 @@
[#]: collector: (lujun9972)
[#]: translator: (geekpi)
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-12670-1.html)
[#]: subject: (How to Create/Configure LVM in Linux)
[#]: via: (https://www.2daygeek.com/create-lvm-storage-logical-volume-manager-in-linux/)
[#]: author: (Magesh Maruthamuthu https://www.2daygeek.com/author/magesh/)
如何在 Linux 中创建/配置 LVM逻辑卷管理
======
![](https://img.linux.net.cn/data/attachment/album/202010/01/111414m2y0mdhgvd9j1bgv.jpg)
<ruby>逻辑卷管理<rt>Logical Volume Management</rt></ruby>LVM在 Linux 系统中扮演着重要的角色,它可以提高可用性、磁盘 I/O、性能和磁盘管理的能力。
LVM 是一种被广泛使用的技术,对于磁盘管理来说,它是非常灵活的。
它在物理磁盘和文件系统之间增加了一个额外的层,允许你创建一个逻辑卷而不是物理磁盘。
LVM 允许你在需要的时候轻松地调整、扩展和减少逻辑卷的大小。
![](https://img.linux.net.cn/data/attachment/album/202010/01/111230el14fubc4ku55o3k.jpeg)
### 如何创建 LVM 物理卷?
你可以使用任何磁盘、RAID 阵列、SAN 磁盘或分区作为 LVM <ruby>物理卷<rt>Physical Volume</rt></ruby>PV
让我们想象一下,你已经添加了三个磁盘,它们是 `/dev/sdb`、`/dev/sdc` 和 `/dev/sdd`
运行以下命令来[发现 Linux 中新添加的 LUN 或磁盘][2]
```
# ls /sys/class/scsi_host
host0
```
```
# echo "- - -" > /sys/class/scsi_host/host0/scan
```
```
# fdisk -l
```
**创建物理卷 `pvcreate` 的一般语法:**
```
pvcreate [物理卷名]
```
当在系统中检测到磁盘,使用 `pvcreate` 命令初始化 LVM PV
```
# pvcreate /dev/sdb /dev/sdc /dev/sdd
Physical volume "/dev/sdb" successfully created
Physical volume "/dev/sdc" successfully created
Physical volume "/dev/sdd" successfully created
```
**请注意:**
* 上面的命令将删除给定磁盘 `/dev/sdb`、`/dev/sdc` 和 `/dev/sdd` 上的所有数据。
* 物理磁盘可以直接添加到 LVM PV 中,而不必是磁盘分区。
使用 `pvdisplay``pvs` 命令来显示你创建的 PV。`pvs` 命令显示的是摘要输出,`pvdisplay` 显示的是 PV 的详细输出:
```
# pvs
PV VG Fmt Attr PSize PFree
/dev/sdb lvm2 a-- 15.00g 15.00g
/dev/sdc lvm2 a-- 15.00g 15.00g
/dev/sdd lvm2 a-- 15.00g 15.00g
```
```
# pvdisplay
"/dev/sdb" is a new physical volume of "15.00 GiB"
--- NEW Physical volume ---
PV Name /dev/sdb
VG Name
PV Size 15.00 GiB
Allocatable NO
PE Size 0
Total PE 0
Free PE 0
Allocated PE 0
PV UUID 69d9dd18-36be-4631-9ebb-78f05fe3217f
"/dev/sdc" is a new physical volume of "15.00 GiB"
--- NEW Physical volume ---
PV Name /dev/sdc
VG Name
PV Size 15.00 GiB
Allocatable NO
PE Size 0
Total PE 0
Free PE 0
Allocated PE 0
PV UUID a2092b92-af29-4760-8e68-7a201922573b
"/dev/sdd" is a new physical volume of "15.00 GiB"
--- NEW Physical volume ---
PV Name /dev/sdd
VG Name
PV Size 15.00 GiB
Allocatable NO
PE Size 0
Total PE 0
Free PE 0
Allocated PE 0
PV UUID d92fa769-e00f-4fd7-b6ed-ecf7224af7faS
```
### 如何创建一个卷组
<ruby>卷组<rt>Volume Group</rt></ruby>VG是 LVM 结构中的另一层。基本上,卷组由你创建的 LVM 物理卷组成,你可以将物理卷添加到现有的卷组中,或者根据需要为物理卷创建新的卷组。
**创建卷组 `vgcreate` 的一般语法:**
```
vgcreate [卷组名] [物理卷名]
```
使用以下命令将一个新的物理卷添加到新的卷组中:
```
# vgcreate vg01 /dev/sdb /dev/sdc /dev/sdd
Volume group "vg01" successfully created
```
**请注意:**默认情况下,它使用 4MB 的<ruby>物理范围<rt>Physical Extent</rt></ruby>PE但你可以根据你的需要改变它。
使用 `vgs``vgdisplay` 命令来显示你创建的 VG 的信息:
```
# vgs vg01
VG #PV #LV #SN Attr VSize VFree
vg01 3 0 0 wz--n- 44.99g 44.99g
```
```
# vgdisplay vg01
--- Volume group ---
VG Name vg01
System ID
Format lvm2
Metadata Areas 3
Metadata Sequence No 1
VG Access read/write
VG Status resizable
MAX LV 0
Cur LV 0
Open LV 0
Max PV 0
Cur PV 3
Act PV 3
VG Size 44.99 GiB
PE Size 4.00 MiB
Total PE 11511
Alloc PE / Size 0 / 0
Free PE / Size 11511 / 44.99 GiB
VG UUID d17e3c31-e2c9-4f11-809c-94a549bc43b7
```
### 如何扩展卷组
如果 VG 没有空间,请使用以下命令将新的物理卷添加到现有卷组中。
**卷组扩展 `vgextend`)的一般语法:**
```
vgextend [已有卷组名] [物理卷名]
```
```
# vgextend vg01 /dev/sde
Volume group "vg01" successfully extended
```
### 如何以 GB 为单位创建逻辑卷?
<ruby>逻辑卷<rt>Logical Volume</rt></ruby>LV是 LVM 结构中的顶层。逻辑卷是由卷组创建的块设备。它作为一个虚拟磁盘分区,可以使用 LVM 命令轻松管理。
你可以使用 `lvcreate` 命令创建一个新的逻辑卷。
**创建逻辑卷(`lvcreate` 的一般语法:**
```
lvcreate n [逻辑卷名] L [逻辑卷大小] [要创建的 LV 所在的卷组名称]
```
运行下面的命令,创建一个大小为 10GB 的逻辑卷 `lv001`
```
# lvcreate -n lv001 -L 10G vg01
Logical volume "lv001" created
```
使用 `lvs``lvdisplay` 命令来显示你所创建的 LV 的信息:
```
# lvs /dev/vg01/lvol01
LV VG Attr LSize Pool Origin Data% Move Log Cpy%Sync Convert
lv001 vg01 mwi-a-m-- 10.00g lv001_mlog 100.00
```
```
# lvdisplay /dev/vg01/lv001
--- Logical volume ---
LV Path /dev/vg01/lv001
LV Name lv001
VG Name vg01
LV UUID ca307aa4-0866-49b1-8184-004025789e63
LV Write Access read/write
LV Creation host, time localhost.localdomain, 2020-09-10 11:43:05 -0700
LV Status available
# open 0
LV Size 10.00 GiB
Current LE 2560
Segments 1
Allocation inherit
Read ahead sectors auto
- currently set to 256
Block device 253:4
```
### 如何以 PE 大小创建逻辑卷?
或者你可以使用物理范围PE大小创建逻辑卷。
### 如何计算 PE 值?
很简单,例如,如果你有一个 10GB 的卷组,那么 PE 大小是多少?
默认情况下,它使用 4MB 的物理范围,但可以通过运行 `vgdisplay` 命令来检查正确的 PE 大小,因为这可以根据需求进行更改。
```
10GB = 10240MB / 4MB PE 大小) = 2560 PE
```
**用 PE 大小创建逻辑卷 `lvcreate` 的一般语法:**
```
lvcreate n [逻辑卷名] l [物理扩展 PE 大小] [要创建的 LV 所在的卷组名称]
```
要使用 PE 大小创建 10GB 的逻辑卷,命令如下:
```
# lvcreate -n lv001 -l 2560 vg01
```
### 如何创建文件系统
在创建有效的文件系统之前,你不能使用逻辑卷。
**创建文件系统的一般语法:**
```
mkfs t [文件系统类型] /dev/[LV 所在的卷组名称]/[LV 名称]
```
使用以下命令将逻辑卷 `lv001` 格式化为 ext4 文件系统:
```
# mkfs -t ext4 /dev/vg01/lv001
```
对于 xfs 文件系统:
```
# mkfs -t xfs /dev/vg01/lv001
```
### 挂载逻辑卷
最后,你需要挂载逻辑卷来使用它。确保在 `/etc/fstab` 中添加一个条目,以便系统启动时自动加载。
创建一个目录来挂载逻辑卷:
```
# mkdir /lvmtest
```
使用挂载命令[挂载逻辑卷][3]
```
# mount /dev/vg01/lv001 /lvmtest
```
在 [/etc/fstab 文件][4]中添加新的逻辑卷详细信息,以便系统启动时自动挂载:
```
# vi /etc/fstab
/dev/vg01/lv001 /lvmtest xfs defaults 0 0
```
使用 [df 命令][5]检查新挂载的卷:
```
# df -h /lvmtest
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/vg01-lv001 15360M 34M 15326M 4% /lvmtest
```
--------------------------------------------------------------------------------
via: https://www.2daygeek.com/create-lvm-storage-logical-volume-manager-in-linux/
作者:[Magesh Maruthamuthu][a]
选题:[lujun9972][b]
译者:[geekpi](https://github.com/geekpi)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://www.2daygeek.com/author/magesh/
[b]: https://github.com/lujun9972
[1]: https://www.2daygeek.com/wp-content/uploads/2020/09/create-lvm-storage-logical-volume-manager-in-linux-2.png
[2]: https://www.2daygeek.com/scan-detect-luns-scsi-disks-on-redhat-centos-oracle-linux/
[3]: https://www.2daygeek.com/mount-unmount-file-system-partition-in-linux/
[4]: https://www.2daygeek.com/understanding-linux-etc-fstab-file/
[5]: https://www.2daygeek.com/linux-check-disk-space-usage-df-command/

View File

@ -0,0 +1,121 @@
[#]: collector: (lujun9972)
[#]: translator: (robsean)
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-12726-1.html)
[#]: subject: (GNOME 3.38 is Here With Customizable App Grid, Performance Improvements and Tons of Other Changes)
[#]: via: (https://itsfoss.com/gnome-3-38-release/)
[#]: author: (Ankush Das https://itsfoss.com/author/ankush/)
GNOME 3.38:可定制应用程序网格、性能改善
======
![](https://img.linux.net.cn/data/attachment/album/202010/16/203906xys0py0nvi1d01ss.jpg)
[GNOME 3.36][1] 带来大量亟需的改进,同时也带来性能的重大提升。现在,在 6 个月后,我们终于引来了 GNOME 3.38,并带来了一系列重大的变化。
### GNOME 3.38 主要特色
这里是 GNOME 3.38 (代码名称Orbis) 的主要亮点:
- [video](https://www.youtube.com/embed/DZ_P5W9r2JY)
#### 可定制应用程序菜单
作为 GNOME 3.38 重大更改中的一部分,应用程序网格(或称应用菜单)现在是可以可定制的。
现在,你可以通过拖拽每个应用程序图标来创建文件夹,将它们移到文件夹,或移出文件夹并将其设置回应用网格。你也可以在应用网格中随心所欲地调整图标的位置。
![][3]
此外,这些变化是一些即将到来的设计更改的基本组成部分,因此,看到我们可以期待的东西会很令人兴奋。
#### 日历菜单更新
![][4]
随着最近一次的 GNOME 更新,通知区整洁了很多,但是现在随着 GNOME 3.38 的到来,你终于可以通过日历区域的正下方访问日历事件,使事情变得方便且容易访问。
它不是一个重大的视觉改造,但也是一些改善。
#### 家长控制改善
作为 GNOME 3.38 一部分你将会注意家长控制服务。它支持与桌面、shell、设置以及其它各种各样组件的集成来帮助你限制用户可以访问的内容。
#### 重新启动按钮
一些细微的改善导致了巨大的变化,重新启动按钮正是其中的一个变化。先单击 “关闭电源” / “关机” 按钮,再单击 “重新启动” 按钮的操作来重新启动系统总是让人很烦。
因此,随着 GNOME 3.38 的到来,你将最终会注意到一个作为单独按钮的 “重新启动” ,这将节省你的单击次数,平复你烦闷的心情。
#### 屏幕录制改善
[GNOME shell 内置的屏幕录制][5] 现在是一项独立的系统服务,这可能会使录制屏幕成为一种平滑流畅的体验。
另外,窗口截屏也有一些改善,并修复了一些错误:
- [video](https://www.youtube.com/embed/c29ge3KwBk8)
#### GNOME 应用程序更新
GNOME 计算器也收到很多的错误修复。除此之外,你也将发现 [epiphany GNOME 浏览器][6] 的一些重大改变。
GNOME Boxes 现在允许你从一个操作系统列表中选择将要运行的操作系统GNOME 地图也有一些图像用户界面上的更改。
当然,不仅限于这些,你页将注意到 GNOME 控制中心、联系人、照片、Nautilus以及其它一些软件包的细微更新和修复。
#### 性能和多显示器支持改善
这里有一大堆底层的改进来全面地改善 GNOME 3.38 。例如,[Mutter][7] 有一些重要的修正,它现在允许在两个显示器中使用不同的刷新频率。
![][8]
先前,如果一台显示器的刷新频率为 60 Hz而另一台的刷新频率为 144 Hz ,那么刷新频率较慢的显示器将限制另外一台显示器的刷新频率。但是,随着在 GNOME 3.38 中的改善,它将能够处理多个显示器,而不会使显示器相互限制。
另外,[Phoronix][9] 报告的一些更改指出,在一些情况下,缩短大约 10% 的渲染时间。因此,这绝对是一个很棒的性能优化。
#### 各种各样的其它更改
* 电池百分比指示器
* 电源菜单中的重新启动选项
* 新的欢迎指引
* 指纹登录
* 二维码扫描以共享 Wi-Fi 热点
* GNOME 浏览器的隐私和其它改善
* GNOME 地图现在反应敏捷并能根据屏幕大小改变其大小
* 重新修订的图标
你可以在它们的官方 [更改日志][10] 中找到一个详细的更改列表。
### 总结
GNOME 3.38 确实是一个令人赞叹的更新,它改善了 GNOME 用户体验。尽管 GNOME 3.36 带来了性能的很大改善,但是针对 GNOME 3.38 的更多优化仍然是一件非常好的事.
GNOME 3.38 将在 Ubuntu 20.10 和 [Fedora 33][11] 中可用。Arch 和 Manjaro 用户应该很快就能获得。
我认为有很多变化是朝着正确的方向发展的。你觉得呢?
--------------------------------------------------------------------------------
via: https://itsfoss.com/gnome-3-38-release/
作者:[Ankush Das][a]
选题:[lujun9972][b]
译者:[robsean](https://github.com/robsean)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://itsfoss.com/author/ankush/
[b]: https://github.com/lujun9972
[1]: https://itsfoss.com/gnome-3-36-release/
[2]: https://www.youtube.com/c/itsfoss?sub_confirmation=1
[3]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/09/gnome-app-arranger.jpg?resize=799%2C450&ssl=1
[4]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/09/gnome-3-38-calendar-menu.png?resize=800%2C721&ssl=1
[5]: https://itsfoss.com/gnome-screen-recorder/
[6]: https://en.wikipedia.org/wiki/GNOME_Web
[7]: https://en.wikipedia.org/wiki/Mutter_(software)
[8]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/09/gnome-multi-monitor-refresh-rate.jpg?resize=800%2C369&ssl=1
[9]: https://www.phoronix.com/scan.php?page=news_item&px=GNOME-3.38-Last-Min-Mutter
[10]: https://help.gnome.org/misc/release-notes/3.38
[11]: https://itsfoss.com/fedora-33/

View File

@ -0,0 +1,173 @@
[#]: collector: (lujun9972)
[#]: translator: (geekpi)
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-12673-1.html)
[#]: subject: (How to Extend/Increase LVMs in Linux)
[#]: via: (https://www.2daygeek.com/extend-increase-resize-lvm-logical-volume-in-linux/)
[#]: author: (Magesh Maruthamuthu https://www.2daygeek.com/author/magesh/)
如何在 Linux 中扩展/增加 LVM 大小(逻辑卷调整)
======
![](https://img.linux.net.cn/data/attachment/album/202010/01/234018qgnwilmmzom8xarb.jpg)
扩展逻辑卷非常简单,只需要很少的步骤,而且不需要卸载某个逻辑卷就可以在线完成。
LVM 的主要目的是灵活的磁盘管理,当你需要的时候,可以很方便地调整、扩展和缩小逻辑卷的大小。
如果你是逻辑卷管理LVM 新手,我建议你从我们之前的文章开始学习。
* **第一部分:[如何在 Linux 中创建/配置 LVM逻辑卷管理][1]**
![](https://img.linux.net.cn/data/attachment/album/202010/01/233946ybwbnw4zanjbn00e.jpeg)
扩展逻辑卷涉及到以下步骤:
* 检查逻辑卷LV所在的卷组中是否有足够的未分配磁盘空间
* 如果有,你可以使用这些空间来扩展逻辑卷
* 如果没有,请向系统中添加新的磁盘或 LUN
* 将物理磁盘转换为物理卷PV
* 扩展卷组
* 增加逻辑卷大小
* 扩大文件系统
* 检查扩展的文件系统大小
### 如何创建 LVM 物理卷?
使用 `pvcreate` 命令创建 LVM 物理卷。
当在操作系统中检测到磁盘,使用 `pvcreate` 命令初始化 LVM 物理卷:
```
# pvcreate /dev/sdc
Physical volume "/dev/sdc" successfully created
```
**请注意:**
* 上面的命令将删除磁盘 `/dev/sdc` 上的所有数据。
* 物理磁盘可以直接添加到 LVM 物理卷中,而不是磁盘分区。
使用 `pvdisplay` 命令来显示你所创建的物理卷:
```
# pvdisplay /dev/sdc
"/dev/sdc" is a new physical volume of "10.00 GiB"
--- NEW Physical volume ---
PV Name /dev/sdc
VG Name
PV Size 10.00 GiB
Allocatable NO
PE Size 0
Total PE 0
Free PE 0
Allocated PE 0
PV UUID 69d9dd18-36be-4631-9ebb-78f05fe3217f
```
### 如何扩展卷组
使用以下命令在现有的卷组VG中添加一个新的物理卷
```
# vgextend vg01 /dev/sdc
Volume group "vg01" successfully extended
```
使用 `vgdisplay` 命令来显示你所创建的物理卷:
```
# vgdisplay vg01
--- Volume group ---
VG Name vg01
System ID
Format lvm2
Metadata Areas 2
Metadata Sequence No 1
VG Access read/write
VG Status resizable
MAX LV 0
Cur LV 0
Open LV 0
Max PV 0
Cur PV 2
Act PV 2
VG Size 14.99 GiB
PE Size 4.00 MiB
Total PE 3840
Alloc PE / Size 1280 / 4.99
Free PE / Size 2560 / 9.99 GiB
VG UUID d17e3c31-e2c9-4f11-809c-94a549bc43b7
```
### 如何扩展逻辑卷?
使用以下命令增加现有逻辑卷大小。
**逻辑卷扩展(`lvextend`)的常用语法:**
```
lvextend [要增加的额外空间] [现有逻辑卷名称]
```
使用下面的命令将现有的逻辑卷增加 10GB
```
# lvextend -L +10G /dev/mapper/vg01-lv002
Rounding size to boundary between physical extents: 5.90 GiB
Size of logical volume vg01/lv002 changed from 5.00 GiB (1280 extents) to 15.00 GiB (3840 extents).
Logical volume var successfully resized
```
使用 PE 大小来扩展逻辑卷:
```
# lvextend -l +2560 /dev/mapper/vg01-lv002
```
要使用百分比(%)扩展逻辑卷,请使用以下命令:
```
# lvextend -l +40%FREE /dev/mapper/vg01-lv002
```
现在,逻辑卷已经扩展,你需要调整文件系统的大小以扩展逻辑卷内的空间:
对于基于 ext3 和 ext4 的文件系统,运行以下命令:
```
# resize2fs /dev/mapper/vg01-lv002
```
对于 xfs 文件系统,使用以下命令:
```
# xfs_growfs /dev/mapper/vg01-lv002
```
使用 [df 命令][3]查看文件系统大小:
```
# df -h /lvmtest1
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/vg01-lv002 15360M 34M 15326M 4% /lvmtest1
```
--------------------------------------------------------------------------------
via: https://www.2daygeek.com/extend-increase-resize-lvm-logical-volume-in-linux/
作者:[Magesh Maruthamuthu][a]
选题:[lujun9972][b]
译者:[geekpi](https://github.com/geekpi)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://www.2daygeek.com/author/magesh/
[b]: https://github.com/lujun9972
[1]: https://linux.cn/article-12670-1.html
[2]: https://www.2daygeek.com/wp-content/uploads/2020/09/extend-increase-resize-lvm-logical-volume-in-linux-3.png
[3]: https://www.2daygeek.com/linux-check-disk-space-usage-df-command/

View File

@ -0,0 +1,153 @@
[#]: collector: (lujun9972)
[#]: translator: (geekpi)
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-12676-1.html)
[#]: subject: (Installing and running Vagrant using qemu-kvm)
[#]: via: (https://fedoramagazine.org/vagrant-qemukvm-fedora-devops-sysadmin/)
[#]: author: (Andy Mott https://fedoramagazine.org/author/amott/)
使用 qemu-kvm 安装和运行 Vagrant
======
![][1]
Vagrant 是一个出色的工具DevOps 专业人员、程序员、系统管理员和普通极客来使用它来建立可重复的基础架构来进行开发和测试。引用自它的网站:
> Vagrant 是用于在单工作流程中构建和管理虚拟机环境的工具。凭借简单易用的工作流程并专注于自动化Vagrant 降低了开发环境的设置时间,提高了生产效率,并使“在我的机器上可以工作”的借口成为过去。
>
> 如果你已经熟悉 Vagrant 的基础知识,那么该文档为所有的功能和内部结构提供了更好的参考。
>
> Vagrant 提供了基于行业标准技术构建的、易于配置、可复制、可移植的工作环境,并由一个一致的工作流程控制,帮助你和你的团队最大限度地提高生产力和灵活性。
>
> <https://www.vagrantup.com/intro>
本指南将逐步介绍使 Vagrant 在基于 Fedora 的计算机上工作所需的步骤。
我从最小化安装 Fedora 服务器开始,因为这样可以减少宿主机操作系统的内存占用,但如果你已经有一台可以使用的 Fedora 机器,无论是服务器还是工作站版本,那么也没问题。
### 检查机器是否支持虚拟化
```
$ sudo lscpu | grep Virtualization
```
```
Virtualization: VT-x
Virtualization type: full
```
### 安装 qemu-kvm
```
sudo dnf install qemu-kvm libvirt libguestfs-tools virt-install rsync
```
### 启用并启动 libvirt 守护进程
```
sudo systemctl enable --now libvirtd
```
### 安装 Vagrant
```
sudo dnf install vagrant
```
### 安装 Vagrant libvirtd 插件
```
sudo vagrant plugin install vagrant-libvirt
```
### 添加一个 box
```
vagrant box add fedora/32-cloud-base --provider=libvirt
```
LCTT 译注以防你不知道box 是 Vagrant 中的一种包格式Vagrant 支持的任何平台上的任何人都可以使用盒子来建立相同的工作环境。)
### 创建一个最小化的 Vagrantfile 来测试
```
$ mkdir vagrant-test
$ cd vagrant-test
$ vi Vagrantfile
```
```
Vagrant.configure("2") do |config|
config.vm.box = "fedora/32-cloud-base"
end
```
**注意文件名和文件内容的大小写。**
### 检查文件
```
vagrant status
```
```
Current machine states:
default not created (libvirt)
The Libvirt domain is not created. Run 'vagrant up' to create it.
```
### 启动 box
```
vagrant up
```
### 连接到你的新机器
```
vagrant ssh
```
完成了。现在你的 Fedora 机器上 Vagrant 可以工作了。
要停止该机器,请使用 `vagrant halt`。这只是简单地停止机器,但保留虚拟机和磁盘。
要关闭并删除它,请使用 `vagrant destroy`。这将删除整个机器和你在其中所做的任何更改。
### 接下来的步骤
在运行 `vagrant up` 命令之前,你不需要下载 box。你可以直接在 Vagrantfile 中指定 box 和提供者如果还没有的话Vagrant 会下载它。下面是一个例子,它还设置了内存量和 CPU 数量:
```
# -*- mode: ruby -*-
# vi: set ft=ruby :
Vagrant.configure("2") do |config|
config.vm.box = "fedora/32-cloud-base"
config.vm.provider :libvirt do |libvirt|
libvirt.cpus = 1
libvirt.memory = 1024
end
end
```
关于使用 Vagrant、创建你自己的机器和使用不同 box 的更多信息,请参见官方文档 <https://www.vagrantup.com/docs>
有一个庞大的仓库,你可以随时下载使用这些 box它们的的官方仓库是 Vagrant Cloud - <https://app.vagrantup.com/boxes/search>。这里有些是基本的操作系统,有些提供完整的功能,如数据库、网络服务器等。
--------------------------------------------------------------------------------
via: https://fedoramagazine.org/vagrant-qemukvm-fedora-devops-sysadmin/
作者:[Andy Mott][a]
选题:[lujun9972][b]
译者:[geekpi](https://github.com/geekpi)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://fedoramagazine.org/author/amott/
[b]: https://github.com/lujun9972
[1]: https://fedoramagazine.org/wp-content/uploads/2020/09/vagrant-beginner-howto-816x346.png

View File

@ -0,0 +1,169 @@
[#]: collector: (lujun9972)
[#]: translator: (geekpi)
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-12740-1.html)
[#]: subject: (How to Reduce/Shrink LVMs \(Logical Volume Resize\) in Linux)
[#]: via: (https://www.2daygeek.com/reduce-shrink-decrease-resize-lvm-logical-volume-in-linux/)
[#]: author: (Magesh Maruthamuthu https://www.2daygeek.com/author/magesh/)
如何在 Linux 中减少/缩小 LVM 大小(逻辑卷调整)
======
![](https://img.linux.net.cn/data/attachment/album/202010/21/210459ydp5an23nfzgglyy.jpg)
减少/缩小逻辑卷是数据损坏的最高风险。
所以,如果可能的话,尽量避免这种情况,但如果没有其他选择的话,那就继续。
缩减 LVM 之前,建议先做一个备份。
当你在 LVM 中的磁盘空间耗尽时,你可以通过缩小现有的没有使用全部空间的 LVM而不是增加一个新的物理磁盘在卷组上腾出一些空闲空间。
**需要注意的是:** 在 GFS2 或者 XFS 文件系统上不支持缩小。
如果你是逻辑卷管理 LVM 的新手,我建议你从我们之前的文章开始学习。
* **第一部分:[如何在 Linux 中创建/配置 LVM逻辑卷管理][1]**
* **第二部分:[如何在 Linux 中扩展/增加 LVM逻辑卷调整][2]**
![](https://img.linux.net.cn/data/attachment/album/202010/21/210610kikq1xynfje7hjaa.jpeg)
减少逻辑卷涉及以下步骤:
* 卸载文件系统
* 检查文件系统是否有任何错误
* 缩小文件系统的大小
* 缩小逻辑卷的大小
* 重新检查文件系统是否存在错误(可选)
* 挂载文件系统
* 检查减少后的文件系统大小
**比如:** 你有一个 **100GB** 的没有使用全部空间的 LVM你想把它减少到 **80GB**,这样 **20GB** 可以用于其他用途。
```
# df -h /testlvm1
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/vg01-lv002 100G 15G 85G 12% /testlvm1
```
### 卸载文件系统
使用 `umount` 命令卸载文件系统:
```
# umount /testlvm1
```
### 检查文件系统是否有任何错误
使用 `e2fsck` 命令检查文件系统是否有错误:
```
# e2fsck -f /dev/mapper/vg01-lv002
e2fsck 1.42.9 (28-Dec-2013)
Pass 1: Checking inodes, blocks, and sizes
Pass 2: Checking directory structure
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts
Pass 5: Checking group summary information
/dev/mapper/vg01-lv002: 13/6553600 files (0.0% non-contiguous), 12231854/26212352 blocks
```
### 缩小文件系统
下面的命令将把 `testlvm1` 文件系统从 **100GB** 缩小到 **80GB**
**文件系统大小调整的常用语法(`resize2fs`**
```
resize2fs [现有逻辑卷名] [新的文件系统大小]
```
实际命令如下:
```
# resize2fs /dev/mapper/vg01-lv002 80G
resize2fs 1.42.9 (28-Dec-2013)
Resizing the filesystem on /dev/mapper/vg01-lv002 to 28321400 (4k) blocks.
The filesystem on /dev/mapper/vg01-lv002 is now 28321400 blocks long.
```
### 减少逻辑卷 LVM 容量
现在使用 `lvreduce` 命令缩小逻辑卷LVM 的大小。通过下面的命令, `/dev/mapper/vg01-lv002` 将把逻辑卷 LVM 从 100GB 缩小到 80GB。
**LVM 缩减 `lvreduce` 的常用语法**
```
lvreduce [新的 LVM 大小] [现有逻辑卷名称]
```
实际命令如下:
```
# lvreduce -L 80G /dev/mapper/vg01-lv002
WARNING: Reducing active logical volume to 80.00 GiB
THIS MAY DESTROY YOUR DATA (filesystem etc.)
Do you really want to reduce lv002? [y/n]: y
Reducing logical volume lv002 to 80.00 GiB
Logical volume lv002 successfully resized
```
### 可选:检查文件系统是否有错误
缩减 LVM 后再次检查文件系统是否有错误:
```
# e2fsck -f /dev/mapper/vg01-lv002
e2fsck 1.42.9 (28-Dec-2013)
Pass 1: Checking inodes, blocks, and sizes
Pass 2: Checking directory structure
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts
Pass 5: Checking group summary information
/dev/mapper/vg01-lv002: 13/4853600 files (0.0% non-contiguous), 1023185/2021235 blocks
```
### 挂载文件系统并检查缩小后的大小
最后挂载文件系统,并检查缩小后的文件系统大小。
使用 `mount` 命令[挂载逻辑卷][4]
```
# mount /testlvm1
```
使用 [df 命令][5]检查挂载的卷。
```
# df -h /testlvm1
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/vg01-lv002 80G 15G 65G 18% /testlvm1
```
--------------------------------------------------------------------------------
via: https://www.2daygeek.com/reduce-shrink-decrease-resize-lvm-logical-volume-in-linux/
作者:[Magesh Maruthamuthu][a]
选题:[lujun9972][b]
译者:[geekpi](https://github.com/geekpi)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://www.2daygeek.com/author/magesh/
[b]: https://github.com/lujun9972
[1]: https://linux.cn/article-12670-1.html
[2]: https://linux.cn/article-12673-1.html
[3]: https://www.2daygeek.com/wp-content/uploads/2020/09/reduce-shrink-decrease-resize-lvm-logical-volume-in-linux-1.png
[4]: https://www.2daygeek.com/mount-unmount-file-system-partition-in-linux/
[5]: https://www.2daygeek.com/linux-check-disk-space-usage-df-command/

View File

@ -0,0 +1,378 @@
[#]: collector: "lujun9972"
[#]: translator: "lxbwolf"
[#]: reviewer: "wxy"
[#]: publisher: "wxy"
[#]: url: "https://linux.cn/article-12681-1.html"
[#]: subject: "Find security issues in Go code using gosec"
[#]: via: "https://opensource.com/article/20/9/gosec"
[#]: author: "Gaurav Kamathe https://opensource.com/users/gkamathe"
使用 gosec 检查 Go 代码中的安全问题
======
> 来学习下 Go 语言的安全检查工具 gosec。
![](https://img.linux.net.cn/data/attachment/album/202010/04/125129bh4qxxsyqpvqjtx4.jpg)
[Go 语言][2]写的代码越来越常见尤其是在容器、Kubernetes 或云生态相关的开发中。Docker 是最早采用 Golang 的项目之一,随后是 Kubernetes之后大量的新项目在众多编程语言中选择了 Go。
像其他语言一样Go 也有它的长处和短处如安全缺陷。这些缺陷可能会因为语言本身的缺陷加上程序员编码不当而产生例如C 代码中的内存安全问题。
无论它们出现的原因是什么,安全问题都应该在开发过程的早期修复,以免在封装好的软件中出现。幸运的是,静态分析工具可以帮你以更可重复的方式处理这些问题。静态分析工具通过解析用某种编程语言写的代码来找到问题。
这类工具中很多被称为 linter。传统意义上linter 更注重的是检查代码中编码问题、bug、代码风格之类的问题它们可能不会发现代码中的安全问题。例如[Coverity][3] 是一个很流行的工具,它可以帮助寻找 C/C++ 代码中的问题。然而,也有一些工具专门用来检查源码中的安全问题。例如,[Bandit][4] 可以检查 Python 代码中的安全缺陷。而 [gosec][5] 则用来搜寻 Go 源码中的安全缺陷。`gosec` 通过扫描 Go 的 AST<ruby>抽象语法树<rt>abstract syntax tree</rt></ruby>)来检查源码中的安全问题。
### 开始使用 gosec
在开始学习和使用 `gosec` 之前,你需要准备一个 Go 语言写的项目。有这么多开源软件,我相信这不是问题。你可以在 GitHub 的 [热门 Golang 仓库][6]中找一个。
本文中,我随机选了 [Docker CE][7] 项目,但你可以选择任意的 Go 项目。
#### 安装 Go 和 gosec
如果你还没安装 Go你可以先从仓库中拉取下来。如果你用的是 Fedora 或其他基于 RPM 的 Linux 发行版本:
```
$ dnf install golang.x86_64
```
如果你用的是其他操作系统,请参照 [Golang 安装][8]页面。
使用 `version` 参数来验证 Go 是否安装成功:
```
$ go version
go version go1.14.6 linux/amd64
```
运行 `go get` 命令就可以轻松地安装 `gosec`
```
$ go get github.com/securego/gosec/cmd/gosec
```
上面这行命令会从 GitHub 下载 `gosec` 的源码,编译并安装到指定位置。在仓库的 `README` 中你还可以看到[安装该工具的其他方法][9]。
`gosec` 的源码会被下载到 `$GOPATH` 的位置,编译出的二进制文件会被安装到你系统上设置的 `bin` 目录下。你可以运行下面的命令来查看 `$GOPATH``$GOBIN` 目录:
```
$ go env | grep GOBIN
GOBIN="/root/go/gobin"
$ go env | grep GOPATH
GOPATH="/root/go"
```
如果 `go get` 命令执行成功,那么 `gosec` 二进制应该就可以使用了:
```
$ ls -l ~/go/bin/
total 9260
-rwxr-xr-x. 1 root root 9482175 Aug 20 04:17 gosec
```
你可以把 `$GOPATH` 下的 `bin` 目录添加到 `$PATH` 中。这样你就可以像使用系统上的其他命令一样来使用 `gosec` 命令行工具CLI了。
```
$ which gosec
/root/go/bin/gosec
$
```
使用 `gosec` 命令行工具的 `-help` 选项来看看运行是否符合预期:
```
$ gosec -help
gosec - Golang security checker
gosec analyzes Go source code to look for common programming mistakes that
can lead to security problems.
VERSION: dev
GIT TAG:
BUILD DATE:
USAGE:
```
之后,创建一个目录,把源码下载到这个目录作为实例项目(本例中,我用的是 Docker CE
```
$ mkdir gosec-demo
$ cd gosec-demo/
$ pwd
/root/gosec-demo
$ git clone https://github.com/docker/docker-ce.git
Cloning into 'docker-ce'...
remote: Enumerating objects: 1271, done.
remote: Counting objects: 100% (1271/1271), done.
remote: Compressing objects: 100% (722/722), done.
remote: Total 431003 (delta 384), reused 981 (delta 318), pack-reused 429732
Receiving objects: 100% (431003/431003), 166.84 MiB | 28.94 MiB/s, done.
Resolving deltas: 100% (221338/221338), done.
Updating files: 100% (10861/10861), done.
```
代码统计工具(本例中用的是 `cloc`)显示这个项目大部分是用 Go 写的,恰好迎合了 `gosec` 的功能。
```
$ ./cloc /root/gosec-demo/docker-ce/
10771 text files.
8724 unique files.
2560 files ignored.
-----------------------------------------------------------------------------------
Language files blank comment code
-----------------------------------------------------------------------------------
Go 7222 190785 230478 1574580
YAML 37 4831 817 156762
Markdown 529 21422 0 67893
Protocol Buffers 149 5014 16562 10071
```
### 使用默认选项运行 gosec
在 Docker CE 项目中使用默认选项运行 `gosec`,执行 `gosec ./...` 命令。屏幕上会有很多输出内容。在末尾你会看到一个简短的 “Summary”列出了浏览的文件数、所有文件的总行数以及源码中发现的问题数。
```
$ pwd
/root/gosec-demo/docker-ce
$ time gosec ./...
[gosec] 2020/08/20 04:44:15 Including rules: default
[gosec] 2020/08/20 04:44:15 Excluding rules: default
[gosec] 2020/08/20 04:44:15 Import directory: /root/gosec-demo/docker-ce/components/engine/opts
[gosec] 2020/08/20 04:44:17 Checking package: opts
[gosec] 2020/08/20 04:44:17 Checking file: /root/gosec-demo/docker-ce/components/engine/opts/address_pools.go
[gosec] 2020/08/20 04:44:17 Checking file: /root/gosec-demo/docker-ce/components/engine/opts/env.go
[gosec] 2020/08/20 04:44:17 Checking file: /root/gosec-demo/docker-ce/components/engine/opts/hosts.go
# End of gosec run
Summary:
Files: 1278
Lines: 173979
Nosec: 4
Issues: 644
real 0m52.019s
user 0m37.284s
sys 0m12.734s
$
```
滚动屏幕你会看到不同颜色高亮的行:红色表示需要尽快查看的高优先级问题,黄色表示中优先级的问题。
#### 关于误判
在开始检查代码之前,我想先分享几条基本原则。默认情况下,静态检查工具会基于一系列的规则对测试代码进行分析,并报告出它们发现的*所有*问题。这是否意味着工具报出来的每一个问题都需要修复?非也。这个问题最好的解答者是设计和开发这个软件的人。他们最熟悉代码,更重要的是,他们了解软件会在什么环境下部署以及会被怎样使用。
这个知识点对于判定工具标记出来的某段代码到底是不是安全缺陷至关重要。随着工作时间和经验的积累,你会慢慢学会怎样让静态分析工具忽略非安全缺陷,使报告内容的可执行性更高。因此,要判定 `gosec` 报出来的某个问题是否需要修复,让一名有经验的开发者对源码做人工审计会是比较好的办法。
#### 高优先级问题
从输出内容看,`gosec` 发现了 Docker CE 的一个高优先级问题,它使用的是低版本的 TLS<ruby>传输层安全<rt>Transport Layer Security<rt></ruby>)。无论什么时候,使用软件和库的最新版本都是确保它更新及时、没有安全问题的最好的方法。
```
[/root/gosec-demo/docker-ce/components/engine/daemon/logger/splunk/splunk.go:173] - G402 (CWE-295): TLS MinVersion too low. (Confidence: HIGH, Severity: HIGH)
172:
> 173: tlsConfig := &tls.Config{}
174:
```
它还发现了一个弱随机数生成器。它是不是一个安全缺陷,取决于生成的随机数的使用方式。
```
[/root/gosec-demo/docker-ce/components/engine/pkg/namesgenerator/names-generator.go:843] - G404 (CWE-338): Use of weak random number generator (math/rand instead of crypto/rand) (Confidence: MEDIUM, Severity: HIGH)
842: begin:
> 843: name := fmt.Sprintf("%s_%s", left[rand.Intn(len(left))], right[rand.Intn(len(right))])
844: if name == "boring_wozniak" /* Steve Wozniak is not boring */ {
```
#### 中优先级问题
这个工具还发现了一些中优先级问题。它标记了一个通过与 `tar` 相关的解压炸弹这种方式实现的潜在的 DoS 威胁,这种方式可能会被恶意的攻击者利用。
```
[/root/gosec-demo/docker-ce/components/engine/pkg/archive/copy.go:357] - G110 (CWE-409): Potential DoS vulnerability via decompression bomb (Confidence: MEDIUM, Severity: MEDIUM)
356:
> 357: if _, err = io.Copy(rebasedTar, srcTar); err != nil {
358: w.CloseWithError(err)
```
它还发现了一个通过变量访问文件的问题。如果恶意使用者能访问这个变量,那么他们就可以改变变量的值去读其他文件。
```
[/root/gosec-demo/docker-ce/components/cli/cli/context/tlsdata.go:80] - G304 (CWE-22): Potential file inclusion via variable (Confidence: HIGH, Severity: MEDIUM)
79: if caPath != "" {
> 80: if ca, err = ioutil.ReadFile(caPath); err != nil {
81: return nil, err
```
文件和目录通常是操作系统安全的最基础的元素。这里,`gosec` 报出了一个可能需要你检查目录的权限是否安全的问题。
```
[/root/gosec-demo/docker-ce/components/engine/contrib/apparmor/main.go:41] - G301 (CWE-276): Expect directory permissions to be 0750 or less (Confidence: HIGH, Severity: MEDIUM)
40: // make sure /etc/apparmor.d exists
> 41: if err := os.MkdirAll(path.Dir(apparmorProfilePath), 0755); err != nil {
42: log.Fatal(err)
```
你经常需要在源码中启动命令行工具。Go 使用内建的 exec 库来实现。仔细地分析用来调用这些工具的变量,就能发现安全缺陷。
```
[/root/gosec-demo/docker-ce/components/engine/testutil/fakestorage/fixtures.go:59] - G204 (CWE-78): Subprocess launched with variable (Confidence: HIGH, Severity: MEDIUM)
58:
> 59: cmd := exec.Command(goCmd, "build", "-o", filepath.Join(tmp, "httpserver"), "github.com/docker/docker/contrib/httpserver")
60: cmd.Env = append(os.Environ(), []string{
```
#### 低优先级问题
在这个输出中gosec 报出了一个 `unsafe` 调用相关的低优先级问题,这个调用会绕开 Go 提供的内存保护。再仔细分析下你调用 `unsafe` 的方式,看看是否有被别人利用的可能性。
```
[/root/gosec-demo/docker-ce/components/engine/pkg/archive/changes_linux.go:264] - G103 (CWE-242): Use of unsafe calls should be audited (Confidence: HIGH, Severity: LOW)
263: for len(buf) > 0 {
> 264: dirent := (*unix.Dirent)(unsafe.Pointer(&buf[0]))
265: buf = buf[dirent.Reclen:]
[/root/gosec-demo/docker-ce/components/engine/pkg/devicemapper/devmapper_wrapper.go:88] - G103 (CWE-242): Use of unsafe calls should be audited (Confidence: HIGH, Severity: LOW)
87: func free(p *C.char) {
> 88: C.free(unsafe.Pointer(p))
89: }
```
它还标记了源码中未处理的错误。源码中出现的错误你都应该处理。
```
[/root/gosec-demo/docker-ce/components/cli/cli/command/image/build/context.go:172] - G104 (CWE-703): Errors unhandled. (Confidence: HIGH, Severity: LOW)
171: err := tar.Close()
> 172: os.RemoveAll(dockerfileDir)
173: return err
```
### 自定义 gosec 扫描
使用 `gosec` 的默认选项会带来很多的问题。然而,经过人工审计,随着时间推移你会掌握哪些问题是不需要标记的。你可以自己指定排除和包含哪些测试。
我上面提到过,`gosec` 是基于一系列的规则从 Go 源码中查找问题的。下面是它使用的完整的[规则][10]列表:
- G101查找硬编码凭证
- G102绑定到所有接口
- G103审计 `unsafe` 块的使用
- G104审计未检查的错误
- G106审计 `ssh.InsecureIgnoreHostKey` 的使用
- G107: 提供给 HTTP 请求的 url 作为污点输入
- G108: `/debug/pprof` 上自动暴露的剖析端点
- G109: `strconv.Atoi` 转换到 int16 或 int32 时潜在的整数溢出
- G110: 潜在的通过解压炸弹实现的 DoS
- G201SQL 查询构造使用格式字符串
- G202SQL 查询构造使用字符串连接
- G203在 HTML 模板中使用未转义的数据
- G204审计命令执行情况
- G301创建目录时文件权限分配不合理
- G302使用 `chmod` 时文件权限分配不合理
- G303使用可预测的路径创建临时文件
- G304通过污点输入提供的文件路径
- G305提取 zip/tar 文档时遍历文件
- G306: 写到新文件时文件权限分配不合理
- G307: 把返回错误的函数放到 `defer`
- G401检测 DES、RC4、MD5 或 SHA1 的使用
- G402查找错误的 TLS 连接设置
- G403确保最小 RSA 密钥长度为 2048 位
- G404不安全的随机数源`rand`
- G501导入黑名单列表crypto/md5
- G502导入黑名单列表crypto/des
- G503导入黑名单列表crypto/rc4
- G504导入黑名单列表net/http/cgi
- G505导入黑名单列表crypto/sha1
- G601: 在 `range` 语句中使用隐式的元素别名
#### 排除指定的测试
你可以自定义 `gosec` 来避免对已知为安全的问题进行扫描和报告。你可以使用 `-exclude` 选项和上面的规则编号来忽略指定的问题。
例如,如果你不想让 `gosec` 检查源码中硬编码凭证相关的未处理的错误,那么你可以运行下面的命令来忽略这些错误:
```
$ gosec -exclude=G104 ./...
$ gosec -exclude=G104,G101 ./...
```
有时候你知道某段代码是安全的,但是 `gosec` 还是会报出问题。然而,你又不想完全排除掉整个检查,因为你想让 `gosec` 检查新增的代码。通过在你已知为安全的代码块添加 `#nosec` 标记可以避免 `gosec` 扫描。这样 `gosec` 会继续扫描新增代码,而忽略掉 `#nosec` 标记的代码块。
#### 运行指定的检查
另一方面,如果你只想检查指定的问题,你可以通过 `-include` 选项和规则编号来告诉 `gosec` 运行哪些检查:
```
$ gosec -include=G201,G202 ./...
```
#### 扫描测试文件
Go 语言自带对测试的支持,通过单元测试来检验一个元素是否符合预期。在默认模式下,`gosec` 会忽略测试文件,你可以使用 `-tests` 选项把它们包含进来:
```
gosec -tests ./...
```
#### 修改输出的格式
找出问题只是它的一半功能;另一半功能是把它检查到的问题以用户友好同时又方便工具处理的方式报告出来。幸运的是,`gosec` 可以用不同的方式输出。例如,如果你想看 JSON 格式的报告,那么就使用 `-fmt` 选项指定 JSON 格式并把结果保存到 `results.json` 文件中:
```
$ gosec -fmt=json -out=results.json ./...
$ ls -l results.json
-rw-r--r--. 1 root root 748098 Aug 20 05:06 results.json
$
{
"severity": "LOW",
"confidence": "HIGH",
"cwe": {
"ID": "242",
"URL": "https://cwe.mitre.org/data/definitions/242.html"
},
"rule_id": "G103",
"details": "Use of unsafe calls should be audited",
"file": "/root/gosec-demo/docker-ce/components/engine/daemon/graphdriver/graphtest/graphtest_unix.go",
"code": "304: \t// Cast to []byte\n305: \theader := *(*reflect.SliceHeader)(unsafe.Pointer(\u0026buf))\n306: \theader. Len *= 8\n",
"line": "305",
"column": "36"
},
```
### 用 gosec 检查容易被发现的问题
静态检查工具不能完全代替人工代码审计。然而,当代码量变大、有众多开发者时,这样的工具往往有助于以可重复的方式找出容易被发现的问题。它对于帮助新开发者识别和在编码时避免引入这些安全缺陷很有用。
--------------------------------------------------------------------------------
via: https://opensource.com/article/20/9/gosec
作者:[Gaurav Kamathe][a]
选题:[lujun9972][b]
译者:[lxbowlf](https://github.com/lxbwolf)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://opensource.com/users/gkamathe
[b]: https://github.com/lujun9972
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/BUSINESS_3reasons.png?itok=k6F3-BqA "A lock on the side of a building"
[2]: https://golang.org/
[3]: https://www.synopsys.com/software-integrity/security-testing/static-analysis-sast.html
[4]: https://pypi.org/project/bandit/
[5]: https://github.com/securego/gosec
[6]: https://github.com/trending/go
[7]: https://github.com/docker/docker-ce
[8]: https://golang.org/doc/install
[9]: https://github.com/securego/gosec#install
[10]: https://github.com/securego/gosec#available-rules

View File

@ -0,0 +1,75 @@
[#]: collector: (lujun9972)
[#]: translator: (geekpi)
[#]: reviewer: (wxy)
[#]: publisher: (wxy)
[#]: url: (https://linux.cn/article-12691-1.html)
[#]: subject: (5 questions to ask yourself when writing project documentation)
[#]: via: (https://opensource.com/article/20/9/project-documentation)
[#]: author: (Alexei Leontief https://opensource.com/users/alexeileontief)
编写项目文档时要问自己的 5 个问题
======
> 使用有效沟通的一些基本原则可以帮助你创建与你的品牌一致的、编写良好、内容丰富的项目文档。
![](https://img.linux.net.cn/data/attachment/album/202010/06/223150omjnutjpml8inc9n.jpg)
在开始实际撰写又一个开源项目的文档之前,甚至在采访专家之前,最好回答一些有关新文档的高级问题。
著名的传播理论家 Harold Lasswell 在他 1948 年的文章《<ruby>社会中的传播结构和功能<rt>The Structure and Function of Communication in Society</rt></ruby>》中写道:
> (一种)描述沟通行为的方便方法是回答以下问题:
>
> * 谁
> * 说什么
> * 在哪个渠道
> * 对谁
> * 有什么效果?
作为一名技术交流者,你可以运用 Lasswell 的理论,回答关于你文档的类似问题,以更好地传达你的信息,达到预期的效果。
### 谁:谁是文档的所有者?
或者说,文档背后是什么公司?它想向受众传达什么品牌形象?这个问题的答案将极大地影响你的写作风格。公司可能有自己的风格指南,或者至少有正式的使命声明,在这种情况下,你应该从这开始。
如果公司刚刚起步,你可以向文件的主人提出上述问题。作为作者,将你为公司创造的声音和角色与你自己的世界观和信念结合起来是很重要的。这将使你的写作看起来更自然,而不像公司的行话。
### 说什么:文件类型是什么?
你需要传达什么信息它是什么类型的文档用户指南、API 参考、发布说明等?许多文档类型有模板或普遍认可的结构,这些结构为你提供一个开始的地方,并帮助确保包括所有必要的信息。
### 在哪个渠道:文档的格式是什么?
对于技术文档,沟通的渠道通常会告诉你文档的最终格式,也就是 PDF、HTML、文本文件等。这很可能也决定了你应该使用什么工具来编写你的文档。
### 对谁:目标受众是谁?
谁会阅读这份文档?他们的知识水平如何?他们的工作职责和主要挑战是什么?这些问题将帮助你确定你应该覆盖什么内容,是否应该应该涉及细节,是否可以使用特定的术语,等等。在某些情况下,这些问题的答案甚至可以影响你使用的语法的复杂性。
### 有什么效果:文档的目的是什么?
在这里,你应该定义这个文档要为它的潜在读者解决什么问题,或者它应该为他们回答什么问题。例如,你的文档的目的可以是教你的客户如何使用你的产品。
这时,你可以参考 [Divio][2] 建议的方法。根据这种方法,你可以根据文档的总体方向,将任何文档分为四种类型之一:学习、解决问题、理解或获取信息。
在这个阶段,另一个很好的问题是,这个文档要解决什么业务问题(例如,如何削减支持成本)。带着业务问题,你可能会看到你写作的一个重要角度。
### 总结
上面的问题旨在帮助你形成有效沟通的基础,并确保你的文件涵盖了所有应该涵盖的内容。你可以把它们分解成你自己的问题清单,并把它们放在身边,以便在你有文件要创建的时候使用。当你面对空白页无从着笔时,这份清单也可能会派上用场。希望它能激发你的灵感,帮助你产生想法。
--------------------------------------------------------------------------------
via: https://opensource.com/article/20/9/project-documentation
作者:[Alexei Leontief][a]
选题:[lujun9972][b]
译者:[geekpi](https://github.com/geekpi)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://opensource.com/users/alexeileontief
[b]: https://github.com/lujun9972
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/rh_003784_02_os.comcareers_resume_rh1x.png?itok=S3HGxi6E (A person writing.)
[2]: https://documentation.divio.com/

View File

@ -0,0 +1,218 @@
[#]: collector: "lujun9972"
[#]: translator: "lxbwolf"
[#]: reviewer: "wxy"
[#]: publisher: "wxy"
[#]: url: "https://linux.cn/article-12671-1.html"
[#]: subject: "10 Open Source Static Site Generators to Create Fast and Resource-Friendly Websites"
[#]: via: "https://itsfoss.com/open-source-static-site-generators/"
[#]: author: "Ankush Das https://itsfoss.com/author/ankush/"
10 大静态网站生成工具
======
![](https://img.linux.net.cn/data/attachment/album/202010/01/123903lx1q0w2oh1lxx7wh.jpg)
> 在寻找部署静态网页的方法吗?这几个开源的静态网站生成工具可以帮你迅速部署界面优美、功能强大的静态网站,无需掌握复杂的 HTML 和 CSS 技能。
### 静态网站是什么?
技术上来讲静态网站是指网页不是由服务器动态生成的。HTML、CSS 和 JavaScript 文件就静静地躺在服务器的某个路径下,它们的内容与终端用户接收到的版本是一样的。原始的源码文件已经提前编译好了,源码在每次请求后都不会变化。
Linux.CN 是一个依赖多个数据库的动态网站,当有浏览器的请求时,网页就会生成并提供服务。大部分网站是动态的,你与这些网站互动时,大量的内容会经常改变。
静态网站有一些好处,比如加载时间更短,请求的服务器资源更少、更安全(值得商榷)。
传统上,静态网站更适合于创建只有少量网页、内容变化不频繁的小网站。
然而,随着静态网站生成工具出现后,静态网站的适用范围越来越大。你还可以使用这些工具搭建博客网站。
我整理了几个开源的静态网站生成工具,这些工具可以帮你搭建界面优美的网站。
### 最好的开源静态网站生成工具
请注意,静态网站不会提供很复杂的功能。如果你需要复杂的功能,那么你可以参考适用于动态网站的[最佳开源 CMS][1]列表。
#### 1、Jekyll
![][2]
Jekyll 是用 [Ruby][3] 写的最受欢迎的开源静态生成工具之一。实际上Jekyll 是 [GitHub 页面][4] 的引擎,它可以让你免费用 GitHub 托管网站。
你可以很轻松地跨平台配置 Jekyll包括 Ubuntu。它利用 [Markdown][5]、[Liquid][5]模板语言、HTML 和 CSS 来生成静态的网页文件。如果你要搭建一个没有广告或推广自己工具或服务的产品页的博客网站,它是个不错的选择。
它还支持从常见的 CMS<ruby>内容管理系统<rt>Content management system</rt></ruby>)如 Ghost、WordPress、Drupal 7 迁移你的博客。你可以管理永久链接、类别、页面、文章还可以自定义布局这些功能都很强大。因此即使你已经有了一个网站如果你想转成静态网站Jekyll 会是一个完美的解决方案。你可以参考[官方文档][6]或 [GitHub 页面][7]了解更多内容。
- [Jekyll][8]
#### 2、Hugo
![][9]
Hugo 是另一个很受欢迎的用于搭建静态网站的开源框架。它是用 [Go 语言][10]写的。
它运行速度快、使用简单、可靠性高。如果你需要它也可以提供更高级的主题。它还提供了一些有用的快捷方式来帮助你轻松完成任务。无论是组合展示网站还是博客网站Hogo 都有能力管理大量的内容类型。
如果你想使用 Hugo你可以参照它的[官方文档][11]或它的 [GitHub 页面][12]来安装以及了解更多相关的使用方法。如果需要的话,你还可以将 Hugo 部署在 GitHub 页面或任何 CDN 上。
- [Hugo][13]
#### 3、Hexo
![][14]
Hexo 是一个有趣的开源框架,基于 [Node.js][15]。像其他的工具一样,你可以用它搭建相当快速的网站,不仅如此,它还提供了丰富的主题和插件。
它还根据用户的每个需求提供了强大的 API 来扩展功能。如果你已经有一个网站,你可以用它的[迁移][16]扩展轻松完成迁移工作。
你可以参照[官方文档][17]或 [GitHub 页面][18] 来使用 Hexo。
- [Hexo][19]
#### 4、Gatsby
![][20]
Gatsby 是一个越来越流行的开源网站生成框架。它使用 [React.js][21] 来生成快速、界面优美的网站。
几年前在一个实验性的项目中,我曾经非常想尝试一下这个工具,它提供的成千上万的新插件和主题的能力让我印象深刻。与其他静态网站生成工具不同的是,你可以使用 Gatsby 生成一个网站,并在不损失任何功能的情况下获得静态网站的好处。
它提供了与很多流行的服务的整合功能。当然,你可以不使用它的复杂的功能,或将其与你选择的流行 CMS 配合使用,这也会很有趣。你可以查看他们的[官方文档][22]或它的 [GitHub 页面][23]了解更多内容。
- [Gatsby][24]
#### 5、VuePress
![][25]
VuePress 是由 [Vue.js][26] 支持的静态网站生成工具,而 Vue.js 是一个开源的渐进式 JavaScript 框架。
如果你了解 HTML、CSS 和 JavaScript那么你可以无压力地使用 VuePress。你应该可以找到几个有用的插件和主题来为你的网站建设开个头。此外看起来 Vue.js 的更新一直很活跃,很多开发者都在关注 Vue.js这是一件好事。
你可以参照他们的[官方文档][27]和 [GitHub 页面][28]了解更多。
- [VuePress][29]
#### 6、Nuxt.js
![][30]
Nuxt.js 使用了 Vue.js 和 Node.js但它致力于模块化并且有能力依赖服务端而非客户端。不仅如此它的目标是为开发者提供直观的体验并提供描述性错误以及详细的文档等。
正如它声称的那样在你用来搭建静态网站的所有工具中Nuxt.js 可以做到功能和灵活性两全其美。他们还提供了一个 [Nuxt 线上沙盒][31],让你不费吹灰之力就能直接测试它。
你可以查看它的 [GitHub 页面][32]和[官方网站][33]了解更多。
- [Nuxt.js][33]
#### 7、Docusaurus
![][34]
Docusaurus 是一个有趣的开源静态网站生成工具,为搭建文档类网站量身定制。它还是 [Facebook 开源计划][35]的一个项目。
Docusaurus 是用 React 构建的。你可以使用所有的基本功能,像文档版本管理、文档搜索和翻译大多是预先配置的。如果你想为你的产品或服务搭建一个文档网站,那么可以试试 Docusaurus。
你可以从它的 [GitHub 页面][36]和它的[官网][37]获取更多信息。
- [Docusaurus][37]
#### 8、Eleventy
![][38]
Eleventy 自称是 Jekyll 的替代品,旨在以更简单的方法来制作更快的静态网站。
它似乎很容易上手而且它还提供了适当的文档来帮助你。如果你想找一个简单的静态网站生成工具Eleventy 似乎会是一个有趣的选择。
你可以参照它的 [GitHub 页面][39]和[官网][40]来了解更多的细节。
- [Eleventy][40]
#### 9、Publii
![][41]
Publii 是一个令人印象深刻的开源 CMS它能使生成一个静态网站变得很容易。它是用 [Electron][42] 和 Vue.js 构建的。如果有需要,你也可以把你的文章从 WorkPress 网站迁移过来。此外,它还提供了与 GitHub 页面、Netlify 及其它类似服务的一键同步功能。
如果你利用 Publii 生成一个静态网站,你还可以得到一个所见即所得的编辑器。你可以从[官网][43]下载它,或者从它的 [GitHub 页面][44]了解更多信息。
- [Publii][43]
#### 10、Primo
![][45]
一个有趣的开源静态网站生成工具,目前开发工作仍很活跃。虽然与其他的静态生成工具相比,它还不是一个成熟的解决方案,有些功能还不完善,但它是一个独特的项目。
Primo 旨在使用可视化的构建器帮你构建和搭建网站,这样你就可以轻松编辑和部署到任意主机上。
你可以参照[官网][46]或查看它的 [GitHub 页面][47]了解更多信息。
- [Primo][46]
### 结语
还有很多文章中没有列出的网站生成工具。然而,我试图提到最好的静态生成器,为您提供最快的加载时间,最好的安全性和令人印象深刻的灵活性。
列表中没有你最喜欢的工具?在下面的评论中告诉我。
--------------------------------------------------------------------------------
via: https://itsfoss.com/open-source-static-site-generators/
作者:[Ankush Das][a]
选题:[lujun9972][b]
译者:[lxbwolf](https://github.com/lxbwolf)
校对:[wxy](https://github.com/wxy)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://itsfoss.com/author/ankush/
[b]: https://github.com/lujun9972
[1]: https://itsfoss.com/open-source-cms/
[2]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2018/01/jekyll-screenshot.jpg?resize=800%2C450&ssl=1
[3]: https://www.ruby-lang.org/en/
[4]: https://pages.github.com/
[5]: https://github.com/Shopify/liquid/wiki
[6]: https://jekyllrb.com/docs/
[7]: https://github.com/jekyll/jekyll
[8]: https://jekyllrb.com/
[9]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/09/hugo.jpg?resize=800%2C414&ssl=1
[10]: https://golang.org/
[11]: https://gohugo.io/getting-started/
[12]: https://github.com/gohugoio/hugo
[13]: https://gohugo.io/
[14]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/09/hexo.jpg?resize=800%2C213&ssl=1
[15]: https://nodejs.org/en/
[16]: https://hexo.io/api/migrator.html
[17]: https://hexo.io/docs/
[18]: https://github.com/hexojs/hexo
[19]: https://hexo.io/
[20]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/09/gatsbyjs.png?resize=800%2C388&ssl=1
[21]: https://reactjs.org/
[22]: https://www.gatsbyjs.com/docs/
[23]: https://github.com/gatsbyjs/gatsby
[24]: https://www.gatsbyjs.com/
[25]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/09/VuePress.jpg?resize=800%2C498&ssl=1
[26]: https://vuejs.org/
[27]: https://vuepress.vuejs.org/guide/
[28]: https://github.com/vuejs/vuepress
[29]: https://vuepress.vuejs.org/
[30]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/09/nuxtjs.jpg?resize=800%2C415&ssl=1
[31]: https://template.nuxtjs.org/
[32]: https://github.com/nuxt/nuxt.js
[33]: https://nuxtjs.org/
[34]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2020/09/docusaurus.jpg?resize=800%2C278&ssl=1
[35]: https://opensource.facebook.com/
[36]: https://github.com/facebook/docusaurus
[37]: https://docusaurus.io/
[38]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/09/eleventy.png?resize=800%2C375&ssl=1
[39]: https://github.com/11ty/eleventy/
[40]: https://www.11ty.dev/
[41]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/09/publii.jpg?resize=800%2C311&ssl=1
[42]: https://www.electronjs.org
[43]: https://getpublii.com/
[44]: https://github.com/GetPublii/Publii
[45]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2020/09/primo-af.jpg?resize=800%2C394&ssl=1
[46]: https://primo.af/
[47]: https://github.com/primo-app/primo-desktop

Some files were not shown because too many files have changed in this diff Show More