mirror of
https://github.com/LCTT/TranslateProject.git
synced 2025-01-28 23:20:10 +08:00
commit
1d1d4c3cf2
27
.github/workflows/lctt-article-badge.yml
vendored
Normal file
27
.github/workflows/lctt-article-badge.yml
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
name: LCTT Article Badge
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [master]
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: checkout old pages branch
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: lctt/translateproject
|
||||
path: build
|
||||
ref: gh-pages
|
||||
- name: remove pages .git
|
||||
run: rm -rf ./build/.git
|
||||
- name: run badge
|
||||
run: sh ./scripts/badge.sh;
|
||||
- uses: crazy-max/ghaction-github-pages@v2.2.0
|
||||
with:
|
||||
build_dir: ./build
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
18
.github/workflows/lctt-article-checker.yml
vendored
Normal file
18
.github/workflows/lctt-article-checker.yml
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
name: LCTT Article Checker
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [master]
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
PULL_REQUEST_ID: ${{ github.event.number }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: "checkout master branch & return to pull request branch"
|
||||
run: CURRENT=$(echo ${{github.ref}} | sed "s|refs/|refs/remotes/|") && git checkout master && git checkout $CURRENT
|
||||
- name: run check
|
||||
run: sh ./scripts/check.sh;
|
28
.github/workflows/lctt-article-status.yml
vendored
Normal file
28
.github/workflows/lctt-article-status.yml
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
name: LCTT Article Status
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "*/30 * * * *"
|
||||
workflow_dispatch:
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: checkout old pages branch
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: lctt/translateproject
|
||||
path: build
|
||||
ref: gh-pages
|
||||
- name: remove pages .git
|
||||
run: rm -rf ./build/.git
|
||||
- name: run status
|
||||
run: sh ./scripts/status.sh;
|
||||
- uses: crazy-max/ghaction-github-pages@v2.2.0
|
||||
with:
|
||||
build_dir: ./build
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
27
.travis.yml
27
.travis.yml
@ -1,27 +0,0 @@
|
||||
language: minimal
|
||||
install:
|
||||
- sudo apt-get install jq
|
||||
- git clone --depth=1 -b gh-pages https://github.com/LCTT/TranslateProject/ build && rm -rf build/.git
|
||||
script:
|
||||
- 'if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then sh ./scripts/check.sh; fi'
|
||||
- 'if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then sh ./scripts/badge.sh; fi'
|
||||
- 'if [ "$TRAVIS_EVENT_TYPE" = "cron" ]; then sh ./scripts/status.sh; fi'
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
# - status
|
||||
except:
|
||||
- gh-pages
|
||||
git:
|
||||
submodules: false
|
||||
depth: false
|
||||
deploy:
|
||||
provider: pages
|
||||
skip_cleanup: true
|
||||
github_token: $GITHUB_TOKEN
|
||||
local_dir: build
|
||||
on:
|
||||
branch:
|
||||
- master
|
||||
# - status
|
@ -0,0 +1,445 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (gxlct008)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-12984-1.html)
|
||||
[#]: subject: (Go channels are bad and you should feel bad)
|
||||
[#]: via: (https://www.jtolio.com/2016/03/go-channels-are-bad-and-you-should-feel-bad)
|
||||
[#]: author: (jtolio.com https://www.jtolio.com/)
|
||||
|
||||
Go 通道是糟糕的,你应该也觉得很糟糕
|
||||
======
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202101/05/101049y2995vz8l9mdg4bz.jpg)
|
||||
|
||||
更新:如果你是从一篇题为 《[糟糕的 Go 语言](https://github.com/ksimka/go-is-not-good)》 的汇编文章看到这篇博文的话,那么我想表明的是,我很惭愧被列在这样的名单上。Go 绝对是我使用过的最不糟糕的的编程语言。在我写作本文时,我是想遏制我所看到的一种趋势,那就是过度使用 Go 的一些较复杂的部分。我仍然认为 <ruby>
|
||||
通道<rt>Channel</rt></ruby>可以更好,但是总体而言,Go 很棒。这就像你最喜欢的工具箱中有 [这个工具][1];它可以有用途(甚至还可能有更多的用途),它仍然可以成为你最喜欢的工具箱!
|
||||
|
||||
更新 2:如果我没有指出这项对真实问题的优秀调查,那我将是失职的:《[理解 Go 中的实际并发错误][2]》。这项调查的一个重要发现是...Go 通道会导致很多错误。
|
||||
|
||||
从 2010 年中后期开始,我就断断续续地在使用 Google 的 [Go 编程语言][3],自 2012 年 1 月开始(在 Go 1.0 之前!),我就用 Go 为 [Space Monkey][4] 编写了合规的产品代码。我对 Go 的最初体验可以追溯到我在研究 Hoare 的 [通信顺序进程][5] 并发模型和 [Matt Might][7] 的 [UCombinator 研究组][8] 下的 [π-演算][6] 时,作为我([现在已重定向][9])博士工作的一部分,以更好地支持多核开发。Go 就是在那时发布的(多么巧合啊!),我当即就开始学习尝试了。
|
||||
|
||||
它很快就成为了 Space Monkey 开发的核心部分。目前,我们在 Space Monkey 的生产系统有超过 42.5 万行的纯 Go 代码(_不_ 包括我们所有的 vendored 库中的代码量,这将使它接近 150 万行),所以也并不是你见过的最多的 Go 代码,但是对于相对年轻的语言,我们是重度用户。我们之前 [写了我们的 Go 使用情况][10]。也开源了一些使用率很高的库;许多人似乎是我们的 [OpenSSL 绑定][11](比 [crypto/tls][12] 更快,但请保持 openssl 本身是最新的!)、我们的 [错误处理库][13]、[日志库][14] 和 [度量标准收集库/zipkin 客户端][15] 的粉丝。我们使用 Go、我们热爱 Go、我们认为它是目前为止我们使用过的最不糟糕的、符合我们需求的编程语言。
|
||||
|
||||
尽管我也不认为我能说服自己不要提及我的广泛避免使用 [goroutine-local-storage 库][16] (尽管它是一个你不应该使用的魔改技巧,但它是一个漂亮的魔改),希望我的其他经历足以证明我在解释我故意煽动性的帖子标题之前知道我在说什么。
|
||||
|
||||
![][17]
|
||||
|
||||
### 等等,什么?
|
||||
|
||||
如果你在大街上问一个有名的程序员,Go 有什么特别之处? 她很可能会告诉你 Go 最出名的是<ruby>通道<rt>Channels</rt></ruby> 和 goroutine。 Go 的理论基础很大程度上是建立在 Hoare 的 CSP(<ruby>通信顺序进程<rt>Communicating Sequential Processes</rt></ruby>)模型上的,该模型本身令人着迷且有趣,我坚信,到目前为止,它产生的收益远远超过了我们的预期。
|
||||
|
||||
CSP(和 π-演算)都使用通信作为核心同步原语,因此 Go 会有通道是有道理的。Rob Pike 对 CSP 着迷(有充分的理由)[相当深][18] 已经有一段时间了。([当时][19] 和 [现在][20])。
|
||||
|
||||
但是从务实的角度来看(也是 Go 引以为豪的),Go 把通道搞错了。在这一点上,通道的实现在我的书中几乎是一个坚实的反模式。为什么这么说呢?亲爱的读者,让我细数其中的方法。
|
||||
|
||||
#### 你可能最终不会只使用通道
|
||||
|
||||
Hoare 的 “通信顺序进程” 是一种计算模型,实际上,唯一的同步原语是在通道上发送或接收的。一旦使用 <ruby>互斥量<rt>mutex</rt></ruby>、<ruby>信号量<rt>semaphore</rt></ruby> 或 <ruby>条件变量<rt>condition variable</rt></ruby>、bam,你就不再处于纯 CSP 领域。 Go 程序员经常通过高呼 “[通过交流共享内存][22]” 的 [缓存的思想][21] 来宣扬这种模式和哲学。
|
||||
|
||||
那么,让我们尝试在 Go 中仅使用 CSP 编写一个小程序!让我们成为高分接收者。我们要做的就是跟踪我们看到的最大的高分值。如此而已。
|
||||
|
||||
首先,我们将创建一个 `Game` 结构体。
|
||||
|
||||
```
|
||||
type Game struct {
|
||||
bestScore int
|
||||
scores chan int
|
||||
}
|
||||
```
|
||||
|
||||
`bestScore` 不会受到<ruby>互斥量<rt>mutex</rt></ruby>的保护!这很好,因为我们只需要一个 goroutine 来管理其状态并通过通道来接收新的分值即可。
|
||||
|
||||
```
|
||||
func (g *Game) run() {
|
||||
for score := range g.scores {
|
||||
if g.bestScore < score {
|
||||
g.bestScore = score
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
好的,现在我们将创建一个有用的构造函数来开始 `Game`。
|
||||
|
||||
```
|
||||
func NewGame() (g *Game) {
|
||||
g = &Game{
|
||||
bestScore: 0,
|
||||
scores: make(chan int),
|
||||
}
|
||||
go g.run()
|
||||
return g
|
||||
}
|
||||
```
|
||||
|
||||
接下来,假设有人给了我们一个可以返回分数的 `Player`。它也可能会返回错误,因为可能传入的 TCP 流可能会死掉或发生某些故障,或者玩家退出。
|
||||
|
||||
```
|
||||
type Player interface {
|
||||
NextScore() (score int, err error)
|
||||
}
|
||||
```
|
||||
|
||||
为了处理 `Player`,我们假设所有错误都是致命的,并将获得的比分向下传递到通道。
|
||||
|
||||
```
|
||||
func (g *Game) HandlePlayer(p Player) error {
|
||||
for {
|
||||
score, err := p.NextScore()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
g.scores <- score
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
好极了!现在我们有了一个 `Game` 类型,可以以线程安全的方式跟踪 `Player` 获得的最高分数。
|
||||
|
||||
你圆满完成了自己的开发工作,并开始拥有客户。你将这个游戏服务器公开,就取得了令人难以置信的成功!你的游戏服务器上也许正在创建许多游戏。
|
||||
|
||||
很快,你发现人们有时会离开你的游戏。许多游戏不再有任何玩家在玩,但没有任何东西可以阻止游戏运行的循环。死掉的 `(*Game).run` goroutines 让你不知所措。
|
||||
|
||||
**挑战:** 在无需互斥量或 panics 的情况下修复上面的 goroutine 泄漏。实际上,可以滚动到上面的代码,并想出一个仅使用通道来解决此问题的方案。
|
||||
|
||||
我等着。
|
||||
|
||||
就其价值而言,它完全可以只通过通道来完成,但是请观察以下解决方案的简单性,它甚至没有这个问题:
|
||||
|
||||
```
|
||||
type Game struct {
|
||||
mtx sync.Mutex
|
||||
bestScore int
|
||||
}
|
||||
|
||||
func NewGame() *Game {
|
||||
return &Game{}
|
||||
}
|
||||
|
||||
func (g *Game) HandlePlayer(p Player) error {
|
||||
for {
|
||||
score, err := p.NextScore()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
g.mtx.Lock()
|
||||
if g.bestScore < score {
|
||||
g.bestScore = score
|
||||
}
|
||||
g.mtx.Unlock()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
你想选择哪一个?不要被欺骗了,以为通道的解决方案可以使它在更复杂的情况下更具可读性和可理解性。<ruby>拆解<rt>Teardown</rt></ruby>是非常困难的。这种拆解若用<ruby>互斥量<rt>mutex</rt></ruby>来做那只是小菜一碟,但最困难的是只使用 Go 专用通道来解决。另外,如果有人回复说发送通道的通道更容易推理,我马上就是感到头疼。
|
||||
|
||||
重要的是,这个特殊的情况可能真的 **很容易** 解决,而通道有一些运行时的帮助,而 Go 没有提供!不幸的是,就目前的情况来看,与 Go 的 CSP 版本相比,使用传统的<ruby>同步原语<rt>synchronization primitives</rt></ruby>可以更好地解决很多问题,这是令人惊讶的。稍后,我们将讨论 Go 可以做些什么来简化此案例。
|
||||
|
||||
**练习:** 还在怀疑? 试着让上面两种解决方案(只使用通道与只使用互斥量channel-only vs mutex-only)在一旦 `bestScore` 大于或等于 100 时,就停止向 `Players` 索要分数。继续打开你的文本编辑器。这是一个很小的玩具问题。
|
||||
|
||||
这里的总结是,如果你想做任何实际的事情,除了通道之外,你还会使用传统的同步原语。
|
||||
|
||||
#### 通道比你自己实现要慢一些
|
||||
|
||||
Go 如此重视 CSP 理论,我认为其中一点就是,运行时应该可以通过通道做一些杀手级的调度优化。也许通道并不总是最直接的原语,但肯定是高效且快速的,对吧?
|
||||
|
||||
![][23]
|
||||
|
||||
正如 [Dustin Hiatt][24] 在 [Tyler Treat’s post about Go][25] 上指出的那样,
|
||||
|
||||
> 在幕后,通道使用锁来序列化访问并提供线程安全性。 因此,通过使用通道同步对内存的访问,你实际上就是在使用锁。 被包装在线程安全队列中的锁。 那么,与仅仅使用标准库 `sync` 包中的互斥量相比,Go 的花式锁又如何呢? 以下数字是通过使用 Go 的内置基准测试功能,对它们的单个集合连续调用 Put 得出的。
|
||||
|
||||
```
|
||||
> BenchmarkSimpleSet-8 3000000 391 ns/op
|
||||
> BenchmarkSimpleChannelSet-8 1000000 1699 ns/o
|
||||
>
|
||||
```
|
||||
|
||||
无缓冲通道的情况与此类似,甚至是在争用而不是串行运行的情况下执行相同的测试。
|
||||
|
||||
也许 Go 调度器会有所改进,但与此同时,良好的旧互斥量和条件变量是非常好、高效且快速。如果你想要提高性能,请使用久经考验的方法。
|
||||
|
||||
#### 通道与其他并发原语组合不佳
|
||||
|
||||
好的,希望我已经说服了你,有时候,你至少还会与除了通道之外的原语进行交互。标准库似乎显然更喜欢传统的同步原语而不是通道。
|
||||
|
||||
你猜怎么着,正确地将通道与互斥量和条件变量一起使用,其实是有一定的挑战性的。
|
||||
|
||||
关于通道的一个有趣的事情是,通道发送是同步的,这在 CSP 中是有很大意义的。通道发送和通道接收的目的是为了成为同步屏蔽,发送和接收应该发生在同一个虚拟时间。如果你是在执行良好的 CSP 领域,那就太好了。
|
||||
|
||||
![][26]
|
||||
|
||||
实事求是地说,Go 通道也有多种缓冲方式。你可以分配一个固定的空间来考虑可能的缓冲,以便发送和接收是不同的事件,但缓冲区大小是有上限的。Go 并没有提供一种方法来让你拥有任意大小的缓冲区 —— 你必须提前分配缓冲区大小。 *这很好*,我在邮件列表上看到有人在争论,*因为无论如何内存都是有限的*。
|
||||
|
||||
What。
|
||||
|
||||
这是个糟糕的答案。有各种各样的理由来使用一个任意缓冲的通道。如果我们事先知道所有的事情,为什么还要使用 `malloc` 呢?
|
||||
|
||||
没有任意缓冲的通道意味着在 *任何* 通道上的幼稚发送可能会随时阻塞。你想在一个通道上发送,并在互斥下更新其他一些记账吗?小心!你的通道发送可能被阻塞!
|
||||
|
||||
```
|
||||
// ...
|
||||
s.mtx.Lock()
|
||||
// ...
|
||||
s.ch <- val // might block!
|
||||
s.mtx.Unlock()
|
||||
// ...
|
||||
```
|
||||
|
||||
这是哲学家晚餐大战的秘诀。如果你使用了锁,则应该迅速更新状态并释放它,并且尽可能不要在锁下做任何阻塞。
|
||||
|
||||
有一种方法可以在 Go 中的通道上进行非阻塞发送,但这不是默认行为。假设我们有一个通道 `ch := make(chan int)`,我们希望在其上无阻塞地发送值 `1`。以下是在不阻塞的情况下你必须要做的最小量的输入:
|
||||
|
||||
```
|
||||
select {
|
||||
case ch <- 1: // it sent
|
||||
default: // it didn't
|
||||
}
|
||||
```
|
||||
|
||||
对于刚入门的 Go程序员来说,这并不是自然而然就能想到的事情。
|
||||
|
||||
综上所述,因为通道上的很多操作都会阻塞,所以需要对哲学家及其就餐仔细推理,才能在互斥量的保护下,成功地将通道操作与之并列使用,而不会造成死锁。
|
||||
|
||||
#### 严格来说,回调更强大,不需要不必要的 goroutines
|
||||
|
||||
![][27]
|
||||
|
||||
每当 API 使用通道时,或者每当我指出通道使某些事情变得困难时,总会有人会指出我应该启动一个 goroutine 来读取该通道,并在读取该通道时进行所需的任何转换或修复。
|
||||
|
||||
呃,不。如果我的代码位于热路径中怎么办?需要通道的实例很少,如果你的 API 可以设计为使用<ruby>互斥量<rt>mutexes</rt></ruby>、<ruby>信号量<rt>semaphores</rt></ruby>和<ruby>回调<rt>callbacks</rt></ruby>,而不使用额外的 goroutine (因为所有事件边缘都是由 API 事件触发的),那么使用通道会迫使我在资源使用中添加另一个内存分配堆栈。是的,goroutine 比线程轻得多,但更轻量并不意味着是最轻量。
|
||||
|
||||
正如我以前 [在一篇关于使用通道的文章的评论中争论过的][28](呵呵,互联网),如果你使用回调而不是通道,你的 API *总是* 可以更通用,*总是* 更灵活,而且占用的资源也会大大减少。“总是” 是一个可怕的词,但我在这里是认真的。有证据级的东西在进行。
|
||||
|
||||
如果有人向你提供了一个基于回调的 API,而你需要一个通道,你可以提供一个回调,在通道上发送,开销不大,灵活性十足。
|
||||
|
||||
另一方面,如果有人提供了一个基于通道的 API 给你,而你需要一个回调,你必须启动一个 goroutine 来读取通道,*并且* 你必须希望当你完成读取时,没有人试图在通道上发送更多的东西,这样你就会导致阻塞的 goroutine 泄漏。
|
||||
|
||||
对于一个超级简单的实际例子,请查看 [context 接口][29](顺便说一下,它是一个非常有用的包,你应该用它来代替 [goroutine 本地存储][16])。
|
||||
|
||||
```
|
||||
type Context interface {
|
||||
...
|
||||
// Done returns a channel that closes when this work unit should be canceled.
|
||||
// Done 返回一个通道,该通道在应该取消该工作单元时关闭。
|
||||
Done() <-chan struct{}
|
||||
|
||||
// Err returns a non-nil error when the Done channel is closed
|
||||
// 当 Done 通道关闭时,Err 返回一个非 nil 错误
|
||||
Err() error
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
想象一下,你要做的只是在 `Done()` 通道触发时记录相应的错误。你该怎么办?如果你没有在通道中选择的好地方,则必须启动 goroutine 进行处理:
|
||||
|
||||
```
|
||||
go func() {
|
||||
<-ctx.Done()
|
||||
logger.Errorf("canceled: %v", ctx.Err())
|
||||
}()
|
||||
```
|
||||
|
||||
如果 `ctx` 在不关闭返回 `Done()` 通道的情况下被垃圾回收怎么办?哎呀!这正是一个 goroutine 泄露!
|
||||
|
||||
现在假设我们更改了 `Done` 的签名:
|
||||
|
||||
```
|
||||
// Done calls cb when this work unit should be canceled.
|
||||
Done(cb func())
|
||||
```
|
||||
|
||||
首先,现在日志记录非常容易。看看:`ctx.Done(func() { log.Errorf ("canceled:%v", ctx.Err()) })`。但是假设你确实需要某些选择行为。你可以这样调用它:
|
||||
|
||||
```
|
||||
ch := make(chan struct{})
|
||||
ctx.Done(func() { close(ch) })
|
||||
```
|
||||
|
||||
瞧!通过使用回调,不会失去表现力。 `ch` 的工作方式类似于用于返回的通道 `Done()`,在日志记录的情况下,我们不需要启动整个新堆栈。我必须保留堆栈跟踪信息(如果我们的日志包倾向于使用它们);我必须避免将其他堆栈分配和另一个 goroutine 分配给调度程序。
|
||||
|
||||
下次你使用通道时,问问你自己,如果你用互斥量和条件变量代替,是否可以消除一些 goroutine ? 如果答案是肯定的,那么修改这些代码将更加有效。而且,如果你试图使用通道只是为了在集合中使用 `range` 关键字,那么我将不得不请你放下键盘,或者只是回去编写 Python 书籍。
|
||||
|
||||
![more like Zooey De-channel, amirite][30]
|
||||
|
||||
#### 通道 API 不一致,只是 cray-cray
|
||||
|
||||
在通道已关闭的情况下,执行关闭或发送消息将会引发 panics!为什么呢? 如果想要关闭通道,你需要在外部同步它的关闭状态(使用互斥量等,这些互斥量的组合不是很好!),这样其他写入者才不会写入或关闭已关闭的通道,或者只是向前冲,关闭或写入已关闭的通道,并期望你必须恢复所有引发的 panics。
|
||||
|
||||
这是多么怪异的行为。 Go 中几乎所有其他操作都有避免 panic 的方法(例如,类型断言具有 `, ok =` 模式),但是对于通道,你只能自己动手处理它。
|
||||
|
||||
好吧,所以当发送失败时,通道会出现 panic。我想这是有一定道理的。但是,与几乎所有其他带有 nil 值的东西不同,发送到 nil 通道不会引发 panic。相反,它将永远阻塞!这很违反直觉。这可能是有用的行为,就像在你的除草器上附加一个开罐器,可能有用(在 Skymall 可以找到)一样,但这肯定是意想不到的。与 nil 映射(执行隐式指针解除引用),nil 接口(隐式指针解除引用),未经检查的类型断言以及其他所有类型交互不同,nil 通道表现出实际的通道行为,就好像为该操作实例化了一个全新的通道一样。
|
||||
|
||||
接收的情况稍微好一点。在已关闭的通道上执行接收会发生什么?好吧,那会是有效操作——你将得到一个零值。好吧,我想这是有道理的。奖励!接收允许你在收到值时进行 `, ok =` 样式的检查,以确定通道是否打开。谢天谢地,我们在这里得到了 `, ok =`。
|
||||
|
||||
但是,如果你从 nil 渠道接收会发生什么呢? *也是永远阻塞!* 耶!不要试图利用这样一个事实:如果你关闭了通道,那么你的通道是 nil!
|
||||
|
||||
### 通道有什么好处?
|
||||
|
||||
当然,通道对于某些事情是有好处的(毕竟它们是一个通用容器),有些事情你只能用它们来做(比如 `select`)。
|
||||
|
||||
#### 它们是另一种特殊情况下的通用数据结构
|
||||
|
||||
Go 程序员已经习惯于对泛型的争论,以至于我一提起这个词就能感觉到 PTSD(创伤后应激障碍)的到来。我不是来谈论这件事的,所以擦擦额头上的汗,让我们继续前进吧。
|
||||
|
||||
无论你对泛型的看法是什么,Go 的映射、切片和通道都是支持泛型元素类型的数据结构,因为它们已经被特殊封装到语言中了。
|
||||
|
||||
在一种不允许你编写自己的泛型容器的语言中,任何允许你更好地管理事物集合的东西都是有价值的。在这里,通道是一个支持任意值类型的线程安全数据结构。
|
||||
|
||||
所以这很有用!我想这可以省去一些陈词滥调。
|
||||
|
||||
我很难把这算作是通道的胜利。
|
||||
|
||||
#### Select
|
||||
|
||||
使用通道可以做的主要事情是 `select` 语句。在这里,你可以等待固定数量的事件输入。它有点像 epoll,但你必须预先知道要等待多少个套接字。
|
||||
|
||||
这是真正有用的语言功能。如果不是 `select`,通道将被彻底清洗。但是我的天呐,让我告诉你,第一次决定可能需要在多个事物中选择,但是你不知道有多少项,因此必须使用 `reflect.Select`。
|
||||
|
||||
### 通道如何才能更好?
|
||||
|
||||
很难说 Go 语言团队可以为 Go 2.0 做的最具战术意义的事情是什么(Go 1.0 兼容性保证很好,但是很费劲),但这并不能阻止我提出一些建议。
|
||||
|
||||
#### 在条件变量上的 Select !
|
||||
|
||||
我们可以不需要通道!这是我提议我们摆脱一些“<ruby>圣牛<rt>sacred cows</rt></ruby>”(LCTT 译注:神圣不可质疑的事物)的地方,但是让我问你,如果你可以选择任何自定义同步原语,那会有多棒?(答:太棒了。)如果有的话,我们根本就不需要通道了。
|
||||
|
||||
#### GC 可以帮助我们吗?
|
||||
|
||||
在第一个示例中,如果我们能够使用定向类型的通道垃圾回收(GC)来帮助我们进行清理,我们就可以轻松地解决通道的高分服务器清理问题。
|
||||
|
||||
![][31]
|
||||
|
||||
如你所知,Go 具有定向类型的通道。 你可以使用仅支持读取的通道类型(`<-chan`)和仅支持写入的通道类型(`chan<-`)。 这太棒了!
|
||||
|
||||
Go 也有垃圾回收功能。 很明显,某些类型的记账方式太繁琐了,我们不应该让程序员去处理它们。 我们清理未使用的内存! 垃圾回收非常有用且整洁。
|
||||
|
||||
那么,为什么不帮助清理未使用或死锁的通道读取呢? 与其让 `make(chan Whatever)` 返回一个双向通道,不如让它返回两个单向通道(`chanReader, chanWriter:= make(chan Type)`)。
|
||||
|
||||
让我们重新考虑一下最初的示例:
|
||||
|
||||
```
|
||||
type Game struct {
|
||||
bestScore int
|
||||
scores chan<- int
|
||||
}
|
||||
|
||||
func run(bestScore *int, scores <-chan int) {
|
||||
// 我们不会直接保留对游戏的引用,因为这样我们就会保留着通道的发送端。
|
||||
for score := range scores {
|
||||
if *bestScore < score {
|
||||
*bestScore = score
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func NewGame() (g *Game) {
|
||||
// 这种 make(chan) 返回风格是一个建议
|
||||
scoreReader, scoreWriter := make(chan int)
|
||||
g = &Game{
|
||||
bestScore: 0,
|
||||
scores: scoreWriter,
|
||||
}
|
||||
go run(&g.bestScore, scoreReader)
|
||||
return g
|
||||
}
|
||||
|
||||
func (g *Game) HandlePlayer(p Player) error {
|
||||
for {
|
||||
score, err := p.NextScore()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
g.scores <- score
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
如果垃圾回收关闭了一个通道,而我们可以证明它永远不会有更多的值,那么这个解决方案是完全可行的。是的,是的,`run` 中的评论暗示着有一把相当大的枪瞄准了你的脚,但至少现在这个问题可以很容易地解决了,而以前确实不是这样。此外,一个聪明的编译器可能会做出适当的证明,以减少这种脚枪造成的损害。
|
||||
|
||||
#### 其他小问题
|
||||
|
||||
* **Dup 通道吗?** —— 如果我们可以在通道上使用等效于 `dup` 的系统调用,那么我们也可以很容易地解决多生产者问题。 每个生产者可以关闭自己的 `dup` 版通道,而不会破坏其他生产者。
|
||||
* **修复通道 API!** —— 关闭不是幂等的吗? 在已关闭的通道上发送信息引起的 panics 没有办法避免吗? 啊!
|
||||
* **任意缓冲的通道** —— 如果我们可以创建没有固定的缓冲区大小限制的缓冲通道,那么我们可以创建非阻塞的通道。
|
||||
|
||||
### 那我们该怎么向大家介绍 Go 呢?
|
||||
|
||||
如果你还没有,请看看我目前最喜欢的编程文章:《[你的函数是什么颜色][32]》。虽然不是专门针对 Go,但这篇博文比我更有说服力地阐述了为什么 goroutines 是 Go 最好的特性(这也是 Go 在某些应用程序中优于 Rust 的方式之一)。
|
||||
|
||||
如果你还在使用这样的一种编程语言写代码,它强迫你使用类似 `yield` 关键字来获得高性能、并发性或事件驱动的模型,那么你就是活在过去,不管你或其他人是否知道这一点。到目前为止,Go 是我所见过的实现 M:N 线程模型(非 1:1 )的语言中最好的入门者之一,而且这种模型非常强大。
|
||||
|
||||
所以,跟大家说说 goroutines 吧。
|
||||
|
||||
如果非要我选择 Go 的另一个主要特性,那就是接口。静态类型的 <ruby>[鸭子模型][33]<rt>duck typing</rt></ruby> 使得扩展、使用你自己或他人的项目变得如此有趣而令人惊奇,这也许值得我改天再写一组完全不同的文章来介绍它。
|
||||
|
||||
### 所以…
|
||||
|
||||
我一直看到人们争先恐后冲进 Go,渴望充分利用通道来发挥其全部潜力。这是我对你的建议。
|
||||
|
||||
**够了!**
|
||||
|
||||
当你在编写 API 和接口时,尽管“绝不”的建议可能很糟糕,但我非常肯定,通道从来没有什么时候好过,我用过的每一个使用通道的 Go API,最后都不得不与之抗争。我从来没有想过“哦 太好了,这里是一个通道;”它总是被一些变体取代,_**这是什么新鲜的地狱?**_
|
||||
|
||||
所以,_请在适当的地方,并且只在适当的地方使用通道。_
|
||||
|
||||
在我使用的所有 Go 代码中,我可以用一只手数出有多少次通道真的是最好的选择。有时候是这样的。那很好!那就用它们吧。但除此之外,就不要再使用了。
|
||||
|
||||
![][34]
|
||||
|
||||
_特别感谢我的校对读者 Jeff Wendling、[Andrew Harding][35]、[George Shank][36] 和 [Tyler Treat][37] 提供的宝贵反馈。_
|
||||
|
||||
如果你想和我们一起用 Go 在 Space Monkey 项目工作,请[给我打个招呼][38]!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.jtolio.com/2016/03/go-channels-are-bad-and-you-should-feel-bad
|
||||
|
||||
作者:[jtolds][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://www.jtolio.com/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://blog.codinghorror.com/content/images/uploads/2012/06/6a0120a85dcdae970b017742d249d5970d-800wi.jpg
|
||||
[2]: https://songlh.github.io/paper/go-study.pdf
|
||||
[3]: https://golang.org/
|
||||
[4]: http://www.spacemonkey.com/
|
||||
[5]: https://en.wikipedia.org/wiki/Communicating_sequential_processes
|
||||
[6]: https://en.wikipedia.org/wiki/%CE%A0-calculus
|
||||
[7]: http://matt.might.net
|
||||
[8]: http://www.ucombinator.org/
|
||||
[9]: https://www.jtolio.com/writing/2015/11/research-log-cell-states-and-microarrays/
|
||||
[10]: https://www.jtolio.com/writing/2014/04/go-space-monkey/
|
||||
[11]: https://godoc.org/github.com/spacemonkeygo/openssl
|
||||
[12]: https://golang.org/pkg/crypto/tls/
|
||||
[13]: https://godoc.org/github.com/spacemonkeygo/errors
|
||||
[14]: https://godoc.org/github.com/spacemonkeygo/spacelog
|
||||
[15]: https://godoc.org/gopkg.in/spacemonkeygo/monitor.v1
|
||||
[16]: https://github.com/jtolds/gls
|
||||
[17]: https://www.jtolio.com/images/wat/darth-helmet.jpg
|
||||
[18]: https://en.wikipedia.org/wiki/Newsqueak
|
||||
[19]: https://en.wikipedia.org/wiki/Alef_%28programming_language%29
|
||||
[20]: https://en.wikipedia.org/wiki/Limbo_%28programming_language%29
|
||||
[21]: https://lesswrong.com/lw/k5/cached_thoughts/
|
||||
[22]: https://blog.golang.org/share-memory-by-communicating
|
||||
[23]: https://www.jtolio.com/images/wat/jon-stewart.jpg
|
||||
[24]: https://twitter.com/HiattDustin
|
||||
[25]: http://bravenewgeek.com/go-is-unapologetically-flawed-heres-why-we-use-it/
|
||||
[26]: https://www.jtolio.com/images/wat/obama.jpg
|
||||
[27]: https://www.jtolio.com/images/wat/yael-grobglas.jpg
|
||||
[28]: http://www.informit.com/articles/article.aspx?p=2359758#comment-2061767464
|
||||
[29]: https://godoc.org/golang.org/x/net/context
|
||||
[30]: https://www.jtolio.com/images/wat/zooey-deschanel.jpg
|
||||
[31]: https://www.jtolio.com/images/wat/joel-mchale.jpg
|
||||
[32]: http://journal.stuffwithstuff.com/2015/02/01/what-color-is-your-function/
|
||||
[33]: https://en.wikipedia.org/wiki/Duck_typing
|
||||
[34]: https://www.jtolio.com/images/wat/michael-cera.jpg
|
||||
[35]: https://github.com/azdagron
|
||||
[36]: https://twitter.com/taterbase
|
||||
[37]: http://bravenewgeek.com
|
||||
[38]: https://www.jtolio.com/contact/
|
@ -0,0 +1,93 @@
|
||||
GCC:优化 Linux、互联网和一切
|
||||
======
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202101/22/122155ujfd62u6zbx3i4b3.jpg)
|
||||
|
||||
软件如果不能被电脑运行,那么它就是无用的。而在处理<ruby>运行时<rt>run-time</rt></ruby>性能的问题上,即使是最有才华的开发人员也会受编译器的支配 —— 因为如果没有可靠的编译器工具链,就无法构建任何重要的东西。<ruby>GNU 编译器集合<rt>GNU Compiler Collection</rt></ruby>(GCC)提供了一个健壮、成熟和高性能的工具,以帮助你充分发挥你代码的潜能。经过数十年成千上万人的开发,GCC 成为了世界上最受尊敬的编译器之一。如果你在构建应用程序是没有使用 GCC,那么你可能错过了最佳解决方案。
|
||||
|
||||
根据 LLVM.org 的说法,GCC 是“如今事实上的标准开源编译器” [^1],也是用来构建完整系统的基础 —— 从内核开始。GCC 支持超过 60 种硬件平台,包括 ARM、Intel、AMD、IBM POWER、SPARC、HP PA-RISC 和 IBM Z,以及各种操作环境,包括 GNU、Linux、Windows、macOS、FreeBSD、NetBSD、OpenBSD、DragonFly BSD、Solaris、AIX、HP-UX 和 RTEMS。它提供了高度兼容的 C/C++ 编译器,并支持流行的 C 库,如 GNU C Library(glibc)、Newlib、musl 和各种 BSD 操作系统中包含的 C 库,以及 Fortran、Ada 和 GO 语言的前端。GCC 还可以作为一个交叉编译器,可以为运行编译器的平台以外的其他平台创建可执行代码。GCC 是紧密集成的 GNU 工具链的核心组件,由 GNU 项目产生,它包括 glibc、Binutils 和 GNU 调试器(GDB)。
|
||||
|
||||
“一直以来我最喜欢的 GNU 工具是 GCC,即<ruby>GNU 编译器集合<rt>GNU Compiler Collection</rt></ruby>。在开发工具非常昂贵的时候,GCC 是第二个 GNU 工具,也是使社区能够编写和构建所有其他工具的工具。这个工具一手改变了这个行业,导致了自由软件运动的诞生,因为一个好的、自由的编译器是一个社区软件的先决条件。”—— Red Hat 开源和标准团队的 Dave Neary。[^2]
|
||||
|
||||
### 优化 Linux
|
||||
|
||||
作为 Linux 内核源代码的默认编译器,GCC 提供了可靠、稳定的性能以及正确构建内核所需的额外扩展。GCC 是流行的 Linux 发行版的标准组件,如 ArchLinux、CentOS、Debian、Fedora、openSUSE 和 Ubuntu 这些发行版中,GCC 通常用来编译支持系统的组件。这包括 Linux 使用的默认库(如 libc、libm、libintl、libssh、libssl、libcrypto、libexpat、libpthread 和 ncurses),这些库依赖于 GCC 来提供可靠性和高性能,并且使应用程序和系统程序可以访问 Linux 内核功能。发行版中包含的许多应用程序包也是用 GCC 构建的,例如 Python、Perl、Ruby、nginx、Apache HTTP 服务器、OpenStack、Docker 和 OpenShift。各个 Linux 发行版使用 GCC 构建的大量代码组成了内核、库和应用程序软件。对于 openSUSE 发行版,几乎 100% 的原生代码都是由 GCC 构建的,包括 6135 个源程序包、5705 个共享库和 38927 个可执行文件。这相当于每周编译 24540 个源代码包。[^3]
|
||||
|
||||
Linux 发行版中包含的 GCC 的基本版本用于创建定义系统<ruby>应用程序二进制接口<rt>Application Binary Interface</rt></ruby>(ABI)的内核和库。<ruby>用户空间<rt>User space</rt></ruby>开发者可以选择下载 GCC 的最新稳定版本,以获得高级功能、性能优化和可用性改进。Linux 发行版提供安装说明或预构建的工具链,用于部署最新版本的 GCC 以及其他 GNU 工具,这些工具有助于提高开发人员的工作效率和缩短部署时间。
|
||||
|
||||
### 优化互联网
|
||||
|
||||
GCC 是嵌入式系统中被广泛采用的核心编译器之一,支持为日益增长的物联网设备开发软件。GCC 提供了许多扩展功能,使其非常适合嵌入式系统软件开发,包括使用编译器的内建函数、#语法、内联汇编和以应用程序为中心的命令行选项进行精细控制。GCC 支持广泛的嵌入式体系结构,包括 ARM、AMCC、AVR、Blackfin、MIPS、RISC-V、Renesas Electronics V850、NXP 和 Freescale Power 处理器,可以生成高效、高质量的代码。GCC提供的交叉编译能力对这个社区至关重要,而预制的交叉编译工具链 [^4] 是一个主要需求。例如,GNU ARM 嵌入式工具链是经过集成和验证的软件包,其中包含 ARM 嵌入式 GCC 编译器、库和其它裸机软件开发所需的工具。这些工具链可用于在 Windows、Linux 和 macOS 主机操作系统上对流行的 ARM Cortex-R 和 Cortex-M 处理器进行交叉编译,这些处理器已装载于数百亿台支持互联网的设备中。[^5]
|
||||
|
||||
GCC 为云计算赋能,为需要直接管理计算资源的软件提供了可靠的开发平台,如数据库和 Web 服务引擎以及备份和安全软件。GCC 完全兼容 C++ 11 和 C++ 14,为 C++ 17 和 C++ 2a 提供实验支持 [^6](LCTT 译注:本文原文发布于 2018 年),可以创建性能优异的对象代码,并提供可靠的调试信息。使用 GCC 的应用程序的一些例子包括:MySQL 数据库管理系统,它需要 Linux 的 GCC [^7];Apache HTTP 服务器,它建议使用 GCC [^8];Bacula,一个企业级网络备份工具,它需要 GCC。[^9]
|
||||
|
||||
### 优化一切
|
||||
|
||||
对于<ruby>高性能计算<rt>High Performance Computing</rt></ruby>(HPC)中使用的科学代码的研究和开发,GCC 提供了成熟的 C、C++ 和 Fortran 前端,以及对 OpenMP 和 OpenACC API的支持,用于基于指令的并行编程。因为 GCC 提供了跨计算环境的可移植性,它使得代码能够更容易地在各种新的和传统的客户机和服务器平台上进行测试。GCC 为 C、C++ 和 Fortran 编译器提供了 OpenMP 4.0 的完整支持,为 C 和 C++ 编译器提供了 OpenMP 4.5 完整支持。对于 OpenACC、 GCC 支持大部分 2.5 规范和性能优化,并且是唯一提供 [OpenACC][1] 支持的非商业、非学术编译器。
|
||||
|
||||
代码性能是这个社区的一个重要参数,GCC 提供了一个坚实的性能基础。Colfax Research 于 2017 年 11 月发表的一篇论文评估了 C++ 编译器在使用 OpenMP 4.x 指令并行化编译代码的速度和编译后代码的运行速度。图 1 描绘了不同编译器编译并使用单个线程运行时计算内核的相对性能。性能值经过了归一化处理,以 G++ 的性能为 1.0。
|
||||
|
||||
![performance][3]
|
||||
|
||||
*图 1 为由不同编译器编译的每个内核的相对性能。(单线程,越高越好)。*
|
||||
|
||||
他的论文总结道:“GNU 编译器在我们的测试中也做得很好。G++ 在六种情况中的三种情况下生成的代码速度是第二快的,并且在编译时间方面是最快的编译器之一。”[^10]
|
||||
|
||||
### 谁在用 GCC?
|
||||
|
||||
在 JetBrains 2018 年的开发者生态状况调查中,在接受调查的 6000 名开发者中,66% 的 C++ 程序员和 73% 的 C 程序员经常使用 GCC。[^11] 以下简要介绍 GCC 的优点,正是这些优点使它在开发人员社区中如此受欢迎。
|
||||
|
||||
* 对于需要为各种新的和遗留的计算平台和操作环境编写代码的开发人员,GCC 提供了对最广泛的硬件和操作环境的支持。硬件供应商提供的编译器主要侧重于对其产品的支持,而其他开源编译器在所支持的硬件和操作系统方面则受到很大限制。[^12]
|
||||
* 有各种各样的基于 GCC 的预构建工具链,这对嵌入式系统开发人员特别有吸引力。这包括 GNU ARM 嵌入式工具链和 Bootlin 网站上提供的 138 个预编译交叉编译器工具链。[^13] 虽然其他开源编译器(如 Clang/LLVM)可以取代现有交叉编译工具链中的 GCC,但这些工具集需要开发者完全重新构建。[^14]
|
||||
* GCC 通过成熟的编译器平台向应用程序开发人员提供可靠、稳定的性能。《在 AMD EPYC 平台上用 GCC 8/9 与 LLVM Clang 6/7 编译器基准测试》这篇文章提供了 49 个基准测试的结果,这些测试的编译器在三个优化级别上运行。使用 `-O3 -march=native` 级别的 GCC 8.2 RC1 在 34% 的时间里排在第一位,而在相同的优化级别 LLVM Clang 6.0 在 20% 的时间里赢得了第二位。[^15]
|
||||
* GCC 为编译调试 [^16] 提供了改进的诊断方法,并为运行时调试提供了准确而有用的信息。GCC 与 GDB 紧密集成,GDB 是一个成熟且功能齐全的工具,它提供“不间断”调试,可以在断点处停止单个线程。
|
||||
* GCC 是一个得到良好支持的平台,它有一个活跃的、有责任感的社区,支持当前版本和以前的两个版本。由于每年都有发布计划,这为一个版本提供了两年的支持。
|
||||
|
||||
### GCC:仍然在继续优化
|
||||
|
||||
GCC 作为一个世界级的编译器继续向前发展。GCC 的最新版本是 8.2,于 2018 年 7 月发布(LCTT 译注:本文原文发表于 2018 年),增加了对即将推出的 Intel CPU、更多 ARM CPU 的硬件支持,并提高了 AMD 的 ZEN CPU 的性能。增加了对 C17 的初步支持,同时也对 C++2A 进行了初步工作。诊断功能继续得到增强,包括更好的发射诊断,改进了定位、定位范围和修复提示,特别是在 C++ 前端。Red Hat 的 David Malcolm 在 2018 年 3 月撰写的博客概述了 GCC 8 中的可用性改进。[^17]
|
||||
|
||||
新的硬件平台继续依赖 GCC 工具链进行软件开发,例如 RISC-V,这是一种自由开放的 ISA,机器学习、人工智能(AI)和物联网细分市场都对其感兴趣。GCC 仍然是 Linux 系统持续开发的关键组件。针对 Intel 架构的 Clear Linux 项目是一个为云、客户端和物联网用例构建的新兴发行版,它提供了一个很好的示例,说明如何使用和改进 GCC 编译器技术来提高基于 Linux 的系统的性能和安全性。GCC 还被用于微软 Azure Sphere 的应用程序开发,这是一个基于 Linux 的物联网应用程序操作系统,最初支持基于 ARM 的联发科 MT3620 处理器。在培养下一代程序员方面,GCC 也是树莓派的 Windows 工具链的核心组件,树莓派是一种运行基于 Debian 的 GNU/Linux 的低成本嵌入式板,用于促进学校和发展中国家的基础计算机科学教学。
|
||||
|
||||
GCC 由 GNU 项目的创始人<ruby>理查德•斯托曼<rt>Richard Stallman</rt></ruby>首次发布 于 1987 年 3 月 22 日,由于它是第一个作为自由软件发布的可移植的 ANSI C 优化编译器,因此它被认为是一个重大突破。GCC 由来自世界各地的程序员组成的社区在指导委员会的指导下维护,以确保对项目进行广泛的、有代表性的监督。GCC 的社区方法是它的优势之一,它形成了一个由开发人员和用户组成的庞大而多样化的社区,他们为项目做出了贡献并提供支持。根据 Open Hub 的说法,“GCC 是世界上最大的开源团队之一,在 Open Hub 上的所有项目团队中排名前 2%。”[^18]
|
||||
|
||||
关于 GCC 的许可问题,人们进行了大量的讨论,其中大多数是混淆而不是启发。GCC 在 GNU 通用公共许可证(GPL)版本 3 或更高版本下发布,但运行时库例外。这是一个左版许可,这意味着衍生作品只能在相同的许可条款下分发。GPLv3 旨在保护 GCC,防止其成为专有软件,并要求对 GCC 代码的更改可以自由公开地进行。对于“最终用户”来说,这个编译器与其他编译器完全相同;使用 GCC 对你为自己的代码所选择的任何许可都没有区别。[^19]
|
||||
|
||||
[^1]: http://clang.llvm.org/features.html#gcccompat
|
||||
[^2]: https://opensource.com/article/18/9/happy-birthday-gnu
|
||||
[^3]: 由 SUSE 基于最近的构建统计提供的信息。在 openSUSE 中还有其他不生成可执行镜像的源码包,这些不包括在统计中。
|
||||
[^4]: https://community.arm.com/tools/b/blog/posts/gnu-toolchain-performance-in-2018
|
||||
[^5]: https://www.arm.com/products/processors/cortex-m
|
||||
[^6]: https://gcc.gnu.org/projects/cxx-status.html#cxx17
|
||||
[^7]: https://mysqlserverteam.com/mysql-8-0-source-code-improvements/
|
||||
[^8]: http://httpd.apache.org/docs/2.4/install.html
|
||||
[^9]: https://blog.bacula.org/what-is-bacula/system-requirements/
|
||||
[^10]: https://colfaxresearch.com/compiler-comparison/
|
||||
[^11]: https://www.jetbrains.com/research/devecosystem-2018/
|
||||
[^12]: http://releases.llvm.org/6.0.0/tools/clang/docs/UsersManual.html
|
||||
[^13]: https://bootlin.com/blog/free-and-ready-to-use-cross-compilation-toolchains/
|
||||
[^14]: https://clang.llvm.org/docs/Toolchain.html
|
||||
[^15]: https://www.phoronix.com/scan.php?page=article&item=gcclang-epyc-summer18&num=1
|
||||
[^16]: https://gcc.gnu.org/wiki/ClangDiagnosticsComparison
|
||||
[^17]: https://developers.redhat.com/blog/2018/03/15/gcc-8-usability-improvements/
|
||||
[^18]: https://www.openhub.net/p/gcc/factoids#FactoidTeamSizeVeryLarge
|
||||
[^19]: https://www.gnu.org/licenses/gcc-exception-3.1-faq.en.html
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.linux.com/blog/2018/10/gcc-optimizing-linux-internet-and-everything
|
||||
|
||||
作者:[Margaret Lewis][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[Chao-zhi](https://github.com/Chao-zhi)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://www.linux.com/users/margaret-lewis
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://www.openacc.org/tools
|
||||
[2]: /files/images/gccjpg-0
|
||||
[3]: https://lcom.static.linuxfound.org/sites/lcom/files/gcc_0.jpg?itok=HbGnRqWX "performance"
|
||||
[4]: https://www.linux.com/licenses/category/used-permission
|
148
published/20181123 Three SSH GUI Tools for Linux.md
Normal file
148
published/20181123 Three SSH GUI Tools for Linux.md
Normal file
@ -0,0 +1,148 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (stevenzdg988)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: subject: (Three SSH GUI Tools for Linux)
|
||||
[#]: via: (https://www.linux.com/blog/learn/intro-to-linux/2018/11/three-ssh-guis-linux)
|
||||
[#]: author: (Jack Wallen https://www.linux.com/users/jlwallen)
|
||||
[#]: url: (https://linux.cn/article-13010-1.html)
|
||||
|
||||
三种 Linux 下的 SSH 图形界面工具
|
||||
======
|
||||
|
||||
![](https://lcom.static.linuxfound.org/sites/lcom/files/ssh.jpg)
|
||||
|
||||
在你作为 Linux 系统管理员的职业生涯中,你可以使用 Secure Shell(SSH)远程访问 Linux 服务器或桌面系统。很有可能,你已经使用过了。在某些情况下,你会通过 SSH 一次性登录多个 Linux 服务器。实际上,SSH 很可能是 Linux 工具箱中最常用的工具之一。因此,你会希望操作尽可能高效。对于许多系统管理员来说,没有什么比命令行更有效的了。但是,有些用户确实更喜欢 GUI 工具,尤其是从一台桌面台式机远程连接到服务器上工作时。
|
||||
|
||||
如果你碰巧喜欢 GUI 工具,那么你肯定想了解一下 Linux 上的一些出色的 SSH 图形界面工具。将其与独特的终端窗口相结合,可以从同一窗口远程访问多台计算机,你便拥有了高效工作所需的一切。让我们看以下这三个工具,找出其中一个(或多个)是否完全适合你的需求。
|
||||
|
||||
我将在 [Elementary OS][1] 上演示这些工具,但是大多数流行的发行版都可以使用它们。
|
||||
|
||||
### PuTTY
|
||||
|
||||
只要是久经沙场的人都知道 [PuTTY][2]。 实际上,PuTTY 是从 Windows 环境通过 SSH 连接到 Linux 服务器的事实标准工具。但是 PuTTY 不仅适用于 Windows。实际上,从其标准存储库中,PuTTY 也可以安装到 Linux 上。 PuTTY 的功能列表包括:
|
||||
|
||||
* 保存会话
|
||||
* 通过 IP 地址或主机名链接
|
||||
* 定义备用 SSH 端口
|
||||
* 链接类型定义
|
||||
* 日志记录
|
||||
* 键盘、响铃、外观、连接等选项
|
||||
* 本地和远程隧道配置
|
||||
* 支持代理
|
||||
* 支持X11 隧道
|
||||
|
||||
PuTTY GUI 主要是一种保存 SSH 会话的方式,因此,你可以更轻松地管理那些你需要不断远程登录、登出的各种 Linux 服务器和桌面台式机。从 PuTTY 连接到 Linux 服务器后,你将拥有一个可以运行的终端窗口。此时,你可能会问自己,为什么不只在终端窗口中工作?对于某些人来说,保存会话的便捷性确实使 PuTTY 值得使用。
|
||||
|
||||
在 Linux 上安装 PuTTY 很简单。例如,你可以在基于 Debian 的发行版上执行命令:
|
||||
|
||||
```
|
||||
sudo apt-get install -y putty
|
||||
```
|
||||
|
||||
安装后,你可以从桌面菜单运行 PuTTY GUI 或执行命令 `putty`。在“<ruby>PuTTY 配置<rt>PuTTY Configuration</rt></ruby>” 窗口(图 1)中,在 “<ruby>主机名(或 IP 地址)<rt>HostName (or IP address)</rt></ruby>”位置键入主机名或 IP 地址,配置<ruby>端口<rt>Port</rt></ruby>”(如果不是默认值 22),从“<ruby>连接类型<rt>Connection type</rt></ruby>”中选择 “SSH” ,然后单击“<ruby>打开<rt>Open</rt></ruby>”。
|
||||
|
||||
![PuTTY Connection][4]
|
||||
|
||||
*图 1:PuTTY 连接配置窗口。*
|
||||
|
||||
建立连接后,系统将提示你输入远程服务器上的用户凭据(图 2)。
|
||||
|
||||
![log in][7]
|
||||
|
||||
*图 2:使用 PuTTY 登录到远程服务器。*
|
||||
|
||||
要保存会话(以便不必总是键入远程服务器信息),填写 IP 地址(或主机名),配置端口和连接类型,然后(在单击 “<ruby>打开<rt>Open</rt></ruby>” 之前),在 “<ruby>保存会话<rt>Saved Sessions</rt></ruby>” 顶部文本区域中键入链接的名称,然后单击 “<ruby>保存<rt>Save</rt></ruby>”。 这样将保存此会话的配置。若要连接到已保存的会话,请从 “<ruby>已保存的会话<rt>Saved Sessions</rt></ruby>” 窗口中选择它,单击 “<ruby>加载<rt>Load</rt></ruby>”,然后单击 “<ruby>打开<rt>Open</rt></ruby>”。 然后,系统将提示你输入远程服务器上的远程凭据登录远程服务器。
|
||||
|
||||
### EasySSH
|
||||
|
||||
尽管 [EasySSH][8] 没有提供 PuTTY 中提供的大量配置选项,但是(顾名思义)它非常易于使用。 EasySSH 的最佳功能之一是提供标签式界面,因此你可以打开多个 SSH 连接并在它们之间快速切换。 EasySSH 的功能包括:
|
||||
|
||||
* 分组(你可以将选项卡分组以获得更高效的体验)。
|
||||
* 保存用户名/密码。
|
||||
* 外观选项。
|
||||
* 支持本地和远程隧道。
|
||||
|
||||
在 Linux 桌面上安装 EasySSH 很简单,因为可以通过 flatpak 安装该应用程序(这意味着你必须在系统上安装 Flatpak )。 安装 flatpak 后,使用以下命令添加 EasySSH :
|
||||
|
||||
```
|
||||
sudo flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
|
||||
|
||||
sudo flatpak install flathub com.github.muriloventuroso.easyssh
|
||||
```
|
||||
|
||||
使用以下命令运行 EasySSH :
|
||||
|
||||
```
|
||||
flatpak run com.github.muriloventuroso.easyssh
|
||||
```
|
||||
|
||||
你可以在其中单击左上角的 “+” 按钮打开 EasySSH 应用程序。 在出现的窗口(图 3)中,根据需要配置 SSH 连接。
|
||||
|
||||
![Adding a connection][10]
|
||||
|
||||
*图 3:在 EasySSH 中添加连接很简单。*
|
||||
|
||||
添加连接后,它将显示在主窗口的左侧导航中(图 4)。
|
||||
|
||||
![EasySSH][12]
|
||||
|
||||
*图 4:EasySSH 主窗口。*
|
||||
|
||||
要在 EasySSH 中连接到远程服务器,请从左侧导航中选择它,然后单击 “<ruby>连接<rt>Connect</rt></ruby>” 按钮(图 5)。
|
||||
|
||||
![Connecting][14]
|
||||
|
||||
*图 5:使用 EasySSH 连接到远程服务器。*
|
||||
|
||||
EasySSH 的一个注意事项是你必须在连接配置中保存用户名和密码(否则连接将失败)。这意味着有权访问运行 EasySSH 的桌面的任何人都可以在不知道密码的情况下远程访问你的服务器。因此,你必须始终记得在外出时锁定桌面屏幕(并确保使用强密码)。你最不希望的就是避免服务器受到不必要的登录攻击。
|
||||
|
||||
### Terminator
|
||||
|
||||
Terminator 实际上不是 SSH GUI。相反,Terminator 的功能是作为一个单一窗口,使你可以一次运行多个终端(甚至一组终端)。实际上,你可以打开 Terminator,将窗口垂直和水平拆分(直到拥有所需的所有终端),然后通过标准 SSH 命令连接到所有远程 Linux 服务器(图 6)。
|
||||
|
||||
![Terminator][16]
|
||||
|
||||
*图 6:Terminator 分为三个不同的窗口,每个窗口都连接到不同的 Linux 服务器。*
|
||||
|
||||
要安装 Terminator,请执行以下命令:
|
||||
|
||||
```
|
||||
sudo apt-get install -y terminator
|
||||
```
|
||||
|
||||
安装后,从桌面菜单或用命令 `terminator` 打开该工具。打开窗口后,你可以在 Terminator 内部右键单击,然后选择 “<ruby>水平分割<rt>Split Horizontally</rt></ruby>” 或 “<ruby>垂直分割<rt>Split Vertically</rt></ruby>”。继续拆分终端,直到你打开所需的终端为止,然后开始远程管理这些服务器。使用 Terminator 的注意事项是它不是标准的 SSH GUI 工具,因为它不会保存你的会话或使你可以快速访问这些服务器。换句话说,你将始终必须手动登录到远程 Linux 服务器。但是,能够并行查看远程 Secure Shell 会话确实使管理多个远程计算机变得容易得多。
|
||||
|
||||
### 少而精的选择
|
||||
|
||||
Linux 没有多少可用的 SSH GUI 工具。为什么呢?因为大多数管理员更喜欢简单地打开终端窗口,并使用标准命令行工具来远程访问服务器。但是,如果需要 GUI 工具,则有两个可靠的选择,和一个使登录多台计算机稍微容易一些的终端。尽管对于那些寻找 SSH GUI 工具的人来说只有少数选择,但是可用的那些肯定值得你花时间,根据需要尝试其中之一。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.linux.com/blog/learn/intro-to-linux/2018/11/three-ssh-guis-linux
|
||||
|
||||
作者:[Jack Wallen][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[stevenzdg988](https://github.com/stevenzdg988)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://www.linux.com/users/jlwallen
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://elementary.io/
|
||||
[2]: https://www.chiark.greenend.org.uk/~sgtatham/putty/latest.html
|
||||
[3]: https://lcom.static.linuxfound.org/sites/lcom/files/ssh_guis_1.jpg
|
||||
[4]: https://lcom.static.linuxfound.org/sites/lcom/files/ssh_guis_1.jpg (PuTTY Connection)
|
||||
[5]: https://www.linux.com/licenses/category/used-permission
|
||||
[6]: https://lcom.static.linuxfound.org/sites/lcom/files/ssh_guis_2.jpg
|
||||
[7]: https://lcom.static.linuxfound.org/sites/lcom/files/ssh_guis_2.jpg (log in)
|
||||
[8]: https://github.com/muriloventuroso/easyssh
|
||||
[9]: https://lcom.static.linuxfound.org/sites/lcom/files/ssh_guis_3.jpg
|
||||
[10]: https://lcom.static.linuxfound.org/sites/lcom/files/ssh_guis_3.jpg (Adding a connection)
|
||||
[11]: https://lcom.static.linuxfound.org/sites/lcom/files/ssh_guis_4.jpg
|
||||
[12]: https://lcom.static.linuxfound.org/sites/lcom/files/ssh_guis_4.jpg (EasySSH)
|
||||
[13]: https://lcom.static.linuxfound.org/sites/lcom/files/ssh_guis_5.jpg
|
||||
[14]: https://lcom.static.linuxfound.org/sites/lcom/files/ssh_guis_5.jpg (Connecting)
|
||||
[15]: https://lcom.static.linuxfound.org/sites/lcom/files/ssh_guis_6.jpg
|
||||
[16]: https://lcom.static.linuxfound.org/sites/lcom/files/ssh_guis_6.jpg (Terminator)
|
@ -0,0 +1,219 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (qfzy1233)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-13005-1.html)
|
||||
[#]: subject: (Search, Study And Practice Linux Commands On The Fly!)
|
||||
[#]: via: (https://www.ostechnix.com/search-study-and-practice-linux-commands-on-the-fly/)
|
||||
[#]: author: (SK https://www.ostechnix.com/author/sk/)
|
||||
|
||||
光速!搜索、学习和实践 Linux 命令!!
|
||||
======
|
||||
|
||||
![](https://www.ostechnix.com/wp-content/uploads/2019/01/tldr-720x340.png)
|
||||
|
||||
这一标题可能看起来很粗略且吸睛。请允许我解释一下我在本教程中将要阐释的内容。假设你想下载一个压缩文件,将其解压缩,并从命令行中将文件从一个位置移动到另一个位置。根据上面的场景,我们可能需要至少三个 Linux 命令,一个用于下载文件,一个用于提取下载的文件,一个用于移动文件。如果你是中高级 Linux 用户,你可以通过[一行命令][16]或脚本在几秒钟/分钟内轻松完成这一任务。但是,如果你是一个不懂得太多 Linux 命令的菜鸟你可能就需要一些帮助了。
|
||||
|
||||
当然,谷歌的快速搜索可能会找到很多结果。或者,你可以使用 [手册页][1]。但是有些手册页实在很长,很全面,但缺少有用的示例。当你在特定的标志/选项上寻找特定的信息时,你可能需要向下检索相当长的时间。值得庆幸的是,有一些 [好的手册页替代品][2],它们主要关注于实用的命令。一个很好的选择是 **TLDR 手册**。使用 TLDR 手册,我们可以通过实际示例快速轻松地学习一个 Linux 命令。要使用 TLDR 手册,我们需要 TLDR 客户端。有很多客户。今天我们就来了解一个这样的客户端,名为 **“Tldr++”**。
|
||||
|
||||
Tldr++ 是一个快速和交互式的 Tldr 客户端,用 **Go** 编程语言编写。与其他 Tldr 客户端不同,它是完全交互式的。这意味着,你可以选择一个命令,读取所有示例,并立即运行任何命令,而不必在终端中重新键入或复制/粘贴每个命令。还是不明白?没有问题。请继续阅读,以便动态学习和实践 Linux 命令。
|
||||
|
||||
### 安装 Tldr++
|
||||
|
||||
安装 Tldr++ 非常简单。从 [发布页面][3] 下载 Tldr++ 最新版本。解压它并将 Tldr++ 二进制文件移动到你的 `$PATH` 中。
|
||||
|
||||
```
|
||||
$ wget https://github.com/isacikgoz/tldr/releases/download/v0.5.0/tldr_0.5.0_linux_amd64.tar.gz
|
||||
$ tar xzf tldr_0.5.0_linux_amd64.tar.gz
|
||||
$ sudo mv tldr /usr/local/bin
|
||||
$ sudo chmod +x /usr/local/bin/tldr
|
||||
```
|
||||
|
||||
现在,运行 `tldr` 二进制代码将 TLDR 手册部署到本地系统中。
|
||||
|
||||
```
|
||||
$ tldr
|
||||
```
|
||||
|
||||
示例输出:
|
||||
|
||||
```
|
||||
Enumerating objects: 6, done.
|
||||
Counting objects: 100% (6/6), done.
|
||||
Compressing objects: 100% (6/6), done.
|
||||
Total 18157 (delta 0), reused 3 (delta 0), pack-reused 18151
|
||||
Successfully cloned into: /home/sk/.local/share/tldr
|
||||
```
|
||||
|
||||
![](https://www.ostechnix.com/wp-content/uploads/2019/01/tldr-2.png)
|
||||
|
||||
Tldr++ 可以在 AUR 中使用。如果你使用 Arch Linux 上,你可以使用任何 AUR 助手来安装它,例如 [YaY][4]。确保你已经从系统中删除了任何现有的 TLDR 客户端,并运行以下命令安装 Tldr++。
|
||||
|
||||
```
|
||||
$ yay -S tldr++
|
||||
```
|
||||
|
||||
或者,你也可以像下面描述的那样从源代码进行编译。因为 Tldr++ 是用 Go 语言编写的,所以请确保你 Linux 系统中已经安装了 Go 语言。如果还没有安装,请参考下面的指南。
|
||||
|
||||
- [如何在 Linux 系统中安装 Go 语言](https://www.ostechnix.com/install-go-language-linux/)
|
||||
|
||||
在安装好 Go 语言之后, 运行以下的命令来安装 Tldr++。
|
||||
|
||||
```
|
||||
$ go get -u github.com/isacikgoz/tldr
|
||||
```
|
||||
|
||||
该命令在当前工作目录中下载 `tldr` 代码库中的内容并存储到 `go` 文件夹中。
|
||||
|
||||
现在,运行 `tldr` 二进制代码将 TLDR 手册部署到本地系统中。
|
||||
|
||||
```
|
||||
$ go/bin/tldr
|
||||
```
|
||||
|
||||
示例输出:
|
||||
|
||||
![][6]
|
||||
|
||||
最后,将 `tldr` 二进制文件复制到你的路径中。
|
||||
|
||||
```
|
||||
$ sudo mv tldr /usr/local/bin
|
||||
```
|
||||
|
||||
现在是时候看一些例子了。
|
||||
|
||||
### Tldr++ 用法
|
||||
|
||||
输入不带任何选项的 `tldr` 命令,以字母顺序显示所有命令示例。
|
||||
|
||||
![][7]
|
||||
|
||||
使用 **向上/向下箭头** 来浏览命令,键入任何字母来搜索或键入命令名称来查看相应命令的示例。 `?` 以浏览更多消息,按 `Ctrl+c` 返回/退出。
|
||||
|
||||
要显示特定命令的示例命令,例如 `apt`,可以这样做:
|
||||
|
||||
```
|
||||
$ tldr apt
|
||||
```
|
||||
|
||||
![][8]
|
||||
|
||||
从列表中选择任意示例命令并按回车键。在选定的命令前会看到一个 `*` 符号。例如,我选择第一个命令即 `sudo apt update`。现在,它会问你是否继续。如果命令正确,只需键入 `y` 继续,并输入 `sudo` 密码运行所选命令。
|
||||
|
||||
![][9]
|
||||
|
||||
看到了吗?你不需要在终端中复制/粘贴或键入实际的命令。只需从列表中选择它,并极速运行!
|
||||
|
||||
Tldr 手册中有数百个 Linux 命令示例。你可以每天选择一个或两个命令,并彻底学习它们。每天坚持这样的练习,尽可能多的掌握。
|
||||
|
||||
### 使用 Tldr++ 动态学习和实践 Linux 命令
|
||||
|
||||
现在回到我在第一段中提到的场景。你需要下载一个文件,将其解压缩并将其移动到不同的位置,并使其可执行。让我们看看如何使用 Tldr++ 客户端进行交互。
|
||||
|
||||
#### 第一步 – 从网上下载文件
|
||||
|
||||
要使用命令行下载文件,我们主要使用 `curl` 或 `wget` 命令。让我使用 `wget` 下载文件。要打开 `wget` 命令的 TLDR 页面,只需执行以下命令:
|
||||
|
||||
```
|
||||
$ tldr wget
|
||||
```
|
||||
|
||||
下面是 `wget` 命令的示例。
|
||||
|
||||
![](https://www.ostechnix.com/wp-content/uploads/2019/01/wget-tldr.png)
|
||||
|
||||
你可以使用 **向上/向下箭头** 来浏览命令列表。一旦你选择了你所选择的命令,按回车键。这里我选择了第一个命令。
|
||||
|
||||
现在,输入路径来下载文件。
|
||||
|
||||
![](https://www.ostechnix.com/wp-content/uploads/2019/01/tldr-3.png)
|
||||
|
||||
然后将要求你确认该命令是否正确。如果命令正确,只需键入 `yes` 或 `y` 就可以开始下载文件。
|
||||
|
||||
![][10]
|
||||
|
||||
我们已经下载了文件。让我们继续解压这个文件。
|
||||
|
||||
#### 第二步 – 解压已下载的文件
|
||||
|
||||
我们下载了 tar.gz 文件。所以我将打开 TLDR 手册的 `tar` 页面。
|
||||
|
||||
```
|
||||
$ tldr tar
|
||||
```
|
||||
|
||||
你将看到示例命令列表。浏览这些示例,找出哪个命令适合提取 tar.gz(gzip 格式)文件,按回车键。在我们的例子中,它是第三个命令。
|
||||
|
||||
![][11]
|
||||
|
||||
现在,系统将提示你输入 tar.gz 文件的路径。只需输入路径并按回车键。Tldr++ 支持智能文件提示。这意味着它会在你键入时自动补全文件名。只需按 `TAB` 键自动完成。
|
||||
|
||||
![][12]
|
||||
|
||||
如果将文件下载到其他位置,只需键入完整路径,例如 `/home/sk/Downloads/tldr_0.5.0_linux_amd64.tar.gz`。
|
||||
|
||||
输入要解压的文件的路径后,按回车键,然后输入 `y` 进行确认。
|
||||
|
||||
![][13]
|
||||
|
||||
#### 第三步 – 将文件从一个目录移动到另一个目录
|
||||
|
||||
我们解压了文件。现在我们需要将文件移动到另一个位置。为了将文件从一个位置移动到另一个位置,我们使用 `mv` 命令。所以,让我们打开 TLDR 手册的 `mv` 命令。
|
||||
|
||||
```
|
||||
$ tldr mv
|
||||
```
|
||||
|
||||
选择正确的命令将文件从一个位置移动到另一个位置。在我们的例子中,第一个命令可以工作,所以让我们选中它。
|
||||
|
||||
![][14]
|
||||
|
||||
输入要移动的文件路径,并输入目标路径并按回车键。
|
||||
|
||||
![][15]
|
||||
|
||||
**附注:** 输入 `y!` 或 `yes!` 来以 `sudo` 权限运行命令。
|
||||
|
||||
正如你在上面的截图中看到的,我将名为 ``tldr` 的文件移动到 `/usr/local/bin/`。
|
||||
|
||||
要了解更多细节,请参考项目最后给出的 GitHub 页面。
|
||||
|
||||
|
||||
### 总结
|
||||
|
||||
别误会,毫无疑问 **手册页** 是伟大的!但是,正如我已经说过的,许多手册页都很全面,缺少有用的示例。我不可能记住带有复杂标志的冗长的所有命令。有时,我花了很多时间在手册页上,却还是一窍不通。Tldr 手册帮助我在几分钟内找到了我需要的东西。而且,我们偶尔会使用一些命令,然后就会完全忘记它们。另一方面,Tldr 手册实际上在使用那些使用率很低的命令时很有帮助。Tldr++ 客户端通过智能的用户交互使这个任务变得更容易。试试吧,在下面的评论区告诉我们你对这个工具的看法。
|
||||
|
||||
以上,更多的好的分享将会陆续推出,请继续保持关注!
|
||||
|
||||
祝好!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.ostechnix.com/search-study-and-practice-linux-commands-on-the-fly/
|
||||
|
||||
作者:[SK][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[qfzy1233](https://github.com/qfzy1233)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://www.ostechnix.com/author/sk/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://www.ostechnix.com/learn-use-man-pages-efficiently/
|
||||
[2]: https://www.ostechnix.com/3-good-alternatives-man-pages-every-linux-user-know/
|
||||
[3]: https://github.com/isacikgoz/tldr/releases
|
||||
[4]: https://www.ostechnix.com/yay-found-yet-another-reliable-aur-helper/
|
||||
[5]: data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7
|
||||
[6]: http://www.ostechnix.com/wp-content/uploads/2019/01/tldr-1.png
|
||||
[7]: http://www.ostechnix.com/wp-content/uploads/2019/01/tldr-11.png
|
||||
[8]: http://www.ostechnix.com/wp-content/uploads/2019/01/tldr-12.png
|
||||
[9]: http://www.ostechnix.com/wp-content/uploads/2019/01/tldr-13.png
|
||||
[10]: http://www.ostechnix.com/wp-content/uploads/2019/01/tldr-4.png
|
||||
[11]: http://www.ostechnix.com/wp-content/uploads/2019/01/tldr-6.png
|
||||
[12]: http://www.ostechnix.com/wp-content/uploads/2019/01/tldr-7.png
|
||||
[13]: http://www.ostechnix.com/wp-content/uploads/2019/01/tldr-8.png
|
||||
[14]: http://www.ostechnix.com/wp-content/uploads/2019/01/tldr-9.png
|
||||
[15]: http://www.ostechnix.com/wp-content/uploads/2019/01/tldr-10.png
|
||||
[16]: https://ostechnix.com/random-one-liner-linux-commands-part-1/
|
124
published/20190204 Getting started with Git- Terminology 101.md
Normal file
124
published/20190204 Getting started with Git- Terminology 101.md
Normal file
@ -0,0 +1,124 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (wxy)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-12994-1.html)
|
||||
[#]: subject: (Getting started with Git: Terminology 101)
|
||||
[#]: via: (https://opensource.com/article/19/2/git-terminology)
|
||||
[#]: author: (Matthew Broberg https://opensource.com/users/mbbroberg)
|
||||
|
||||
Git 入门:术语基础
|
||||
======
|
||||
|
||||
> 想学习 Git?看看这个最重要的术语和命令的快速总结。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202101/08/171156gu9l8dvulxmxom6d.jpg)
|
||||
|
||||
如今,对于任何希望跟踪他们的变化的人来说,版本控制是一个重要的工具。它对程序员、系统管理员和<ruby>网站可靠性工程师<rt>site reliability engineers</rt></ruby>(SRE)都特别有用。确保可以从错误中恢复到已知的良好状态是一个巨大的胜利,比以前给复制的文件添加 `.old` 后缀的策略更友好。
|
||||
|
||||
但学习 Git 这件事往往被告诉大家“投身开源”的好心同行们过度简化了。在你还不明白之前,就有人要你给一个从<ruby>上游<rt>upstream</rt></ruby> <ruby>变基<rt>rebase</rt></ruby>的<ruby>拉取请求<rt>pull request</rt></ruby>(PR)或<ruby>合并请求<rt>merge request</rt></ruby>(MR),然后他们才能从你的<ruby>远程版本库<rt>remote</rt></ruby>合并 —— 而且一定会删除<ruby>合并提交<rt>merge commits</rt></ruby>。无论你想给开源项目做出什么好的贡献,当你看到这些你不认识的单词时,都会觉得难以融入。
|
||||
|
||||
![Git 速查表封面图][2]
|
||||
|
||||
- [下载][3] 我们的 Git 速查表。
|
||||
|
||||
如果你有一两个月的时间和足够的好奇心,[Git SCM][4] 是你需要学习所有术语的权威来源。但如果你正在寻找来自实践的总结,请继续阅读。
|
||||
|
||||
### 提交就是提醒
|
||||
|
||||
对我来说,Git 最难理解的部分是 Git 最简单的概念:一个<ruby>提交<rt>commit</rt></ruby>就是一个内容的集合,包括一个关于描述的信息,以及之前的提交。没有固有的代码发布策略,甚至没有内置的明确建议。这个内容甚至不一定是代码 —— 可以是*任何*你想添加到版本库的东西。<ruby>提交消息<rt>commit message</rt></ruby>会对这些内容进行注释。
|
||||
|
||||
我喜欢把提交信息看作是给未来的自己的礼物:它可能会提到你编辑的文件,但更重要的是它提醒你修改这些文件的意图。添加更多关于你为什么编辑这些内容的信息,可以帮助任何使用你的版本库的人,即使那个人是你。
|
||||
|
||||
### origin/master 在哪里?
|
||||
|
||||
要知道自己在 Git 项目中的位置,首先把它想成一棵树。所有 Git 项目都有一个根目录,类似于文件系统的根目录。所有的提交都是这个根目录下的分支。这样一来,分支只是一个提交的指针。按照惯例,`master` 是根目录下默认的分支名称。(LCTT 译注:世界变得快,原文发表于 2019 年,而现在有些地方开始用 `main` 替代这个名字。)
|
||||
|
||||
由于 Git 是一个分布式的版本控制系统,同一个代码库分布在多个地方,所以人们经常用<ruby>版本库<rt>repository</rt></ruby>这个词来表示同一个项目的所有副本。(LCTT 译注:“repository” 英文原意是仓库、存储库,在计算机环境中,常用于版本控制、软件分发等方面,有时候会统一译作“仓库”、“存储库”。但我们认为,应该根据不同语境采用更有指向性的译法。在 Git 等版本控制语境中,采用“版本库”;在软件分发方面,采用“软件库”;其它泛指或不确定的语境中,可采用“仓库”、“存储库”译法。)有<ruby>本地版本库<rt>local repository</rt></ruby>,这是你编辑代码的地方(稍后会有更多的介绍),还有<ruby>远程版本库<rt>remote repository</rt></ruby>,这是你完成后想把代码发送到的地方。远程版本库可以在任何地方,甚至在你的本地版本库所在的同一台计算机上,但它们通常托管在 GitLab 或 GitHub 等版本库服务上。
|
||||
|
||||
### 我在哪里?
|
||||
|
||||
虽然不是官方的卖点,但迷路也是 Git 仓库的“乐趣”之一。你可以通过这套可靠的命令来找到自己的方向:
|
||||
|
||||
* `git branch` —— 找到你所在的分支。
|
||||
* `git log` —— 查看你正在进行的提交。
|
||||
* `git status` —— 查看自上次提交以来你所做的编辑。
|
||||
* `git remote` —— 查看你正在跟踪的远程仓库。
|
||||
|
||||
用这些命令来定位自己的方向,当你被卡住的时候,会让你有一种方向感。
|
||||
|
||||
### 我是否已将我的提交暂存或缓存起来?
|
||||
|
||||
你电脑上的代码俗称为你的<ruby>工作空间<rt>workspace</rt></ruby>。但不是很明显的是,当你在 Git 仓库中时,你还有两个(是的,两个!)其他位置:<ruby>索引<rt>index</rt></ruby>和<ruby>暂存<rt>stash</rt></ruby>。当你写了一些内容,然后**添加**时,你是把它添加到索引中,也就是准备提交的缓存内容。有的时候,你的索引中的文件还没有准备好提交,但你想查看另一个分支。这时,暂存就派上用场了。你可以使用 `git stash` 将索引了但尚未提交的文件存储到暂存区中。当你准备好取回文件时,运行 `git stash pop` 将更改带回索引中。
|
||||
|
||||
下面是一些你需要使用暂存区和缓存区的命令:
|
||||
|
||||
* `git diff ...origin/master` —— 显示最近的本地提交和远程的 `origin` 版本库的 `master` 分支之间的差异。
|
||||
* `git diff --cached` —— 显示最近的本地提交与添加到本地索引的内容之间的任何差异。
|
||||
* `git stash` —— 将索引的(已添加但未提交的)文件放在暂存区堆栈中。
|
||||
* `git stash list` —— 显示暂存区堆栈中的变化。
|
||||
* `git stash pop` —— 将最近的变化从暂存库中删除。
|
||||
|
||||
### 无头骑士
|
||||
|
||||
Git 里面有各种比喻。当我想到 `HEAD` 是哪里的时候,我就会想到火车线路。如果你最终处于<ruby>脱离的 HEAD<rt>detached HEAD</rt></ruby>模式,就意味着你已经脱离了这个隐喻的轨道。
|
||||
|
||||
`HEAD` 是指向当前签出分支中最近一次提交的指针。默认的“<ryby>签出<rt>checkout</rt></ruby>”是指当你创建一个 Git 仓库并进入到 `master` 分支的时候。每次创建或修改到另一个分支时,你都会切换到该分支行。如果你在当前分支的某处进行 `git checkout <commit>`,`HEAD` 就会移动到该提交。如果没有提交历史记录将你的当前提交连接到已签出的提交,那么你将处于脱离的 `HEAD` 状态。如果你找不到 `HEAD` 的位置,你可以随时用 `git reset --hard origin/master` 来删除修改,回到已知状态。*警告:这将删除你上次推送到 `master` 后的任何改动。*
|
||||
|
||||
### 你是上游还是下游?
|
||||
|
||||
你的项目的本地副本被认为是你的本地版本库,它可能有也可能没有远程版本库 —— 远程版本库的副本是用于协作或保存的。也可能还有一个<ruby>上游<rt>upstream</rt></ruby>版本库,在那里,项目的第三个副本由不同的贡献者托管和维护。
|
||||
|
||||
例如,假设我想为 Kubernetes 做贡献。我会首先将 `kubernetes/kubernetes` 项目<ruby>复刻<rt>fork</rt></ruby>到我的账户下 `mbbroberg/kubernetes`。然后我会将我的项目克隆到我的本地工作区。在这种情况下,我的本地克隆是我的本地仓库,`mbbroberg/kubernetes` 是我的远程仓库,`kubernetes/kubernetes` 是上游。
|
||||
|
||||
### 合并的隐喻
|
||||
|
||||
当你深入 Git 分支时,根系统的视觉效果就会和火车轨道的形象合二为一。分支通常被用作开发一个新功能的方式,最终你想把它<ruby>合并<rt>merge</rt></ruby>到主分支中。当这样做时,Git 会按顺序保留共同的提交历史,然后将你的分支的新提交追加到历史中。这个过程有一大堆的细节:是否<ruby>变基<rt>rebase</rt></ruby>,是否添加一个<ruby>合并提交<rt>merge commit</rt></ruby>,[Brent Laster][5] 在《[如何在 Git 中重置、恢复和返回之前的状态][6]》中会有更详细的探讨。
|
||||
|
||||
### 我想现在就去 Git
|
||||
|
||||
要掌握 Git 命令的世界,有大量的术语和需要探索的地方。我希望这篇关于日常使用术语的第一人称探索能帮助你适应这一切。如果你觉得自己被卡住了或者遇到了挫折,欢迎在 Twitter [@mbbroberg][7] 上联系我。
|
||||
|
||||
#### 回顾
|
||||
|
||||
* <ruby>提交<rt>Commit</rt></ruby> —— 将当前索引的内容保存在一个新的提交中,并附上用户描述更改的日志信息。
|
||||
* <ruby>分支<rt>Branch</rt></ruby> —— 指向一个提交的指针。
|
||||
* `master` —— 第一个分支的默认名称。
|
||||
* `HEAD` —— 指向当前分支上最近一次提交的指针。
|
||||
* <ruby>合并<rt>Merge</rt></ruby> —— 合并两个或多个提交的历史。
|
||||
* <ruby>工作空间<rt>Workspace</rt></ruby> —— Git 仓库本地副本的通俗名称。
|
||||
* <ruby>工作树<rt>Working tree</rt></ruby> —— 工作区中的当前分支;任何时候你都可以在 `git status` 的输出中看到这个。
|
||||
* <ruby>缓存<rt>Cache</rt></ruby> —— 用于临时存储未提交的变更的空间。
|
||||
* <ruby>索引<rt>Index</rt></ruby> —— 变更提交前存储其变化的缓存。
|
||||
* 跟踪和未跟踪的文件 —— 没有被索引缓存的文件或尚未加入其中的文件。
|
||||
* <ruby>暂存<rt>Stash</rt></ruby> —— 另一个缓存,作为一个堆栈,在这里可以存储更改而不需要提交它们。
|
||||
* `origin` —— 远程版本库的默认名称。
|
||||
* <ruby>本地仓库<rt>Local repository</rt></ruby> —— 也就是你在工作站上保存 Git 仓库副本的地方。
|
||||
* <ruby>远程存储库<rt>Remote repository</rt></ruby> —— Git 存储库的第二副本,你可以在这里推送变更以便协作或备份。
|
||||
* <ruby>上游存储库<rt>Upstream repository</rt></ruby> —— 你跟踪的远程存储库的通俗说法。
|
||||
* <ruby>拉取请求<rt>Pull request</rt></ruby> —— 这是 GitHub 的专用术语,用于让其他人知道你推送到仓库分支的变化。
|
||||
* <ruby>合并请求<rt>Merge request</rt></ruby> —— 这是 GitLab 的专用术语,用于让其他人知道你推送到仓库分支的变化。
|
||||
* `origin/master` —— 远程版本库及其主要分支的默认名称。
|
||||
|
||||
后记:双关语是 Git 最好的部分之一,愿你喜欢。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/19/2/git-terminology
|
||||
|
||||
作者:[Matthew Broberg][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/mbbroberg
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/rh_003588_01_rd3os.combacktoschoolseriesk12_rh_021x_0.png?itok=fvorN0e- (Digital hand surrounding by objects, bike, light bulb, graphs)
|
||||
[2]: https://opensource.com/sites/default/files/uploads/git_cheat_sheet_cover.jpg (Git Cheat Sheet cover image)
|
||||
[3]: https://opensource.com/downloads/cheat-sheet-git
|
||||
[4]: https://git-scm.com/about
|
||||
[5]: https://opensource.com/users/bclaster
|
||||
[6]: https://opensource.com/article/18/6/git-reset-revert-rebase-commands
|
||||
[7]: https://twitter.com/mbbroberg
|
134
published/20190205 5 Streaming Audio Players for Linux.md
Normal file
134
published/20190205 5 Streaming Audio Players for Linux.md
Normal file
@ -0,0 +1,134 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (Chao-zhi)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-13029-1.html)
|
||||
[#]: subject: (5 Streaming Audio Players for Linux)
|
||||
[#]: via: (https://www.linux.com/blog/2019/2/5-streaming-audio-players-linux)
|
||||
[#]: author: (Jack Wallen https://www.linux.com/users/jlwallen)
|
||||
|
||||
5 个适用于 Linux 的流式音频播放器
|
||||
======
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202101/18/220035k8mmbl1blmkb97f8.jpg)
|
||||
|
||||
当我工作的时候,我会一直在后台播放音乐。大多数情况下,这些音乐是以黑胶唱片的形式在转盘上旋转。但有时我不想用这种单纯的方法听音乐时,我会选择听流媒体音频应用程序的方式。然而,由于我工作在 Linux 平台上,所以我只可以使用在我的操作系统上运行良好的软件。幸运的是,对于想在 Linux 桌面听流式音频的人来说,有很多工具可以选择。
|
||||
|
||||
事实上,Linux 为音乐流媒体提供了许多可靠的产品,我将重点介绍我最喜欢的五种用于此任务的工具。警告一句,并不是所有的玩意都是开源的。但是如果你不介意在你的开源桌面上运行一个专有的应用程序,你有一些非常棒的选择。让我们来看看有什么可用的。
|
||||
|
||||
### Spotify
|
||||
|
||||
Linux 版的 Spotify 不是那种在你启动就闪退的愚蠢的、半生不熟的应用程序,也没有阉割什么功能。事实上,Spotify 的 Linux 版本与其他平台上的版本完全相同。使用 Spotify 流媒体客户端,你可以收听音乐和播客、创建播放列表、发现新的艺术家等等。Spotify 界面(图 1)非常易于导航和使用。
|
||||
|
||||
![Spotify][2]
|
||||
|
||||
*图 1:Spotify 界面可以很容易地找到新的音乐和旧的收藏。*
|
||||
|
||||
你可以使用 snap(使用 `sudo snap install Spotify` 命令)安装 Spotify,也可以使用以下命令从官方存储库安装 Spotify:
|
||||
|
||||
```
|
||||
sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 931FF8E79F0876134EDDBDCCA87FF9DF48BF1C90
|
||||
sudo echo deb http://repository.spotify.com stable non-free | sudo tee /etc/apt/sources.list.d/spotify.list
|
||||
sudo apt-get update
|
||||
sudo apt-get install spotify-client
|
||||
```
|
||||
|
||||
一旦安装,你就可以登录你的 Spotify 帐户,这样你就可以开始听好听的音乐,以帮助激励你完成你的工作。如果你已在其他设备上安装了 Spotify(并登录到同一帐户),则可以指定音乐应该流式传输到哪个设备(通过单击 Spotify 窗口右下角附近的“可用设备”图标)。
|
||||
|
||||
### Clementine
|
||||
|
||||
Clementine 是 Linux 平台上最好的音乐播放器之一。Clementine 不仅允许用户播放本地存储的音乐,还可以连接到许多流媒体音频服务,例如:
|
||||
|
||||
* Amazon Cloud Drive
|
||||
* Box
|
||||
* Dropbox
|
||||
* Icecast
|
||||
* Jamendo
|
||||
* Magnatune
|
||||
* RockRadio.com
|
||||
* Radiotunes.com
|
||||
* SomaFM
|
||||
* SoundCloud
|
||||
* Spotify
|
||||
* Subsonic
|
||||
* Vk.com
|
||||
* 或其他有趣的电台
|
||||
|
||||
使用 Clementine 有两个注意事项。首先,你必须使用最新版本(因为某些软件库中可用的构建版本已过时,并且不会安装必要的流式处理插件)。第二,即使是最新的构建版本,一些流媒体服务也不会像预期的那样工作。例如,接入 Spotify 频道时,你只能使用最热门的曲目(而无法使用播放列表,或搜索歌曲的功能)。
|
||||
|
||||
使用 Clementine 互联网流媒体服务时,你会发现其中有很多你从来没有听说过的音乐家和乐队(图 2)。
|
||||
|
||||
![Clementine][5]
|
||||
|
||||
*图 2:Clementine 互联网广播是寻找新音乐的好方法。*
|
||||
|
||||
### Odio
|
||||
|
||||
Odio 是一个跨平台的专有应用程序(可用于 Linux、MacOS 和 Windows),它允许你流式传输各种类型的互联网音乐站。广播的内容是取自 [www.radio-browser.info][6],而应用程序本身在为你呈现流方面做了令人难以置信的工作(图 3)。
|
||||
|
||||
![Odio][8]
|
||||
|
||||
*图 3:Odio 接口是你能找到的最好的接口之一。*
|
||||
|
||||
Odio 让你很容易找到独特的互联网广播电台,甚至可以把你找到并收藏的电台添加到你的库中。目前,在 Linux 上安装 Odio 的唯一方法是通过 Snap。如果你的发行版支持 snap 软件包,请使用以下命令安装此流应用程序:
|
||||
|
||||
```
|
||||
sudo snap install odio
|
||||
```
|
||||
|
||||
安装后,你可以打开应用程序并开始使用它。无需登录(或创建)帐户。Odio 的设置非常有限。实际上,它只提供了在设置窗口中选择暗色主题或亮色主题的选项。然而,尽管它可能功能有限,但 Odio 是在 Linux 上播放互联网广播的最佳选择之一。
|
||||
|
||||
### StreamTuner2
|
||||
|
||||
Streamtuner2 是一个优秀的互联网电台 GUI 工具。使用它,你可以流式播放以下音乐:
|
||||
|
||||
* Internet radio stations
|
||||
* Jameno
|
||||
* MyOggRadio
|
||||
* Shoutcast.com
|
||||
* SurfMusic
|
||||
* TuneIn
|
||||
* Xiph.org
|
||||
* YouTube
|
||||
|
||||
Streamtuner2 提供了一个很好的界面(如果不是有点过时的话),可以很容易地找到和播放你喜爱的音乐。StreamTuner2 的一个警告是,它实际上只是一个用于查找你想要听到的流媒体的 GUI。当你找到一个站点时,双击它打开与流相关的应用程序。这意味着你必须安装必要的应用程序,才能播放流媒体。如果你没有合适的应用程序,你就不能播放流媒体。因此,你将花费大量的时间来确定要为某些流媒体安装哪些应用程序(图 4)。
|
||||
|
||||
![Streamtuner2][10]
|
||||
|
||||
*图4:配置 Streamtuner2 需要一个坚强的心脏。*
|
||||
|
||||
### VLC
|
||||
|
||||
很长一段时间以来,VLC 一直被称为 Linux 最好的媒体播放工具。这是有充分理由的,因为几乎所有你丢给它的东西它都能播放。其中包括流媒体广播电台。虽然你无法让 VLC 连接到 Spotify 这样的网站,但你可以直接访问互联网广播,点击播放列表,而 VLC 毫无疑问可以打开它。考虑到目前有很多互联网广播电台,你在寻找适合自己口味的音乐方面不会有任何问题。VLC 还包括可视化工具、均衡器(图 5)等工具。
|
||||
|
||||
![VLC ][12]
|
||||
|
||||
*图 5:VLC 可视化工具和均衡器特性。*
|
||||
|
||||
VLC 唯一需要注意的是,你必须有一个你希望听到的互联网广播的 URL,因为这个工具本身并不能进行管理。但是有了这些链接,你就找不到比 VLC 更好的媒体播放器了。
|
||||
|
||||
### 这些工具软件怎么来的
|
||||
|
||||
如果这五个工具都不太不适合你的需要,我建议你打开你发行版的应用商店,搜索一个适合你的。有很多工具可以制作流媒体音乐、播客等等,不仅可以在 Linux 上实现,而且很简单。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.linux.com/blog/2019/2/5-streaming-audio-players-linux
|
||||
|
||||
作者:[Jack Wallen][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[Chao-zhi](https://github.com/Chao-zhi)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://www.linux.com/users/jlwallen
|
||||
[b]: https://github.com/lujun9972
|
||||
[2]: https://lcom.static.linuxfound.org/sites/lcom/files/spotify_0.jpg?itok=8-Ym-R61 (Spotify)
|
||||
[3]: https://www.linux.com/licenses/category/used-permission
|
||||
[5]: https://lcom.static.linuxfound.org/sites/lcom/files/clementine_0.jpg?itok=5oODJO3b (Clementine)
|
||||
[6]: http://www.radio-browser.info
|
||||
[8]: https://lcom.static.linuxfound.org/sites/lcom/files/odio.jpg?itok=sNPTSS3c (Odio)
|
||||
[10]: https://lcom.static.linuxfound.org/sites/lcom/files/streamtuner2.jpg?itok=1MSbafWj (Streamtuner2)
|
||||
[12]: https://lcom.static.linuxfound.org/sites/lcom/files/vlc_0.jpg?itok=QEOsq7Ii (VLC )
|
||||
[13]: https://training.linuxfoundation.org/linux-courses/system-administration-training/introduction-to-linux
|
@ -0,0 +1,436 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (stevenzdg988)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-13041-1.html)
|
||||
[#]: subject: (Install Apache, MySQL, PHP \(LAMP\) Stack On Ubuntu 18.04 LTS)
|
||||
[#]: via: (https://www.ostechnix.com/install-apache-mysql-php-lamp-stack-on-ubuntu-18-04-lts/)
|
||||
[#]: author: (SK https://www.ostechnix.com/author/sk/)
|
||||
|
||||
在 Ubuntu 中安装 Apache、MySQL、PHP(LAMP)套件
|
||||
======
|
||||
|
||||
![](https://www.ostechnix.com/wp-content/uploads/2019/02/lamp-720x340.jpg)
|
||||
|
||||
**LAMP** 套件是一种流行的开源 Web 开发平台,可用于运行和部署动态网站和基于 Web 的应用程序。通常,LAMP 套件由 Apache Web 服务器、MariaDB/MySQL 数据库、PHP/Python/Perl 程序设计(脚本)语言组成。 LAMP 是 **L**inux,**M**ariaDB/**M**YSQL,**P**HP/**P**ython/**P**erl 的缩写。 本教程描述了如何在 Ubuntu 18.04 LTS 服务器中安装 Apache、MySQL、PHP(LAMP 套件)。
|
||||
|
||||
就本教程而言,我们将使用以下 Ubuntu 测试。
|
||||
|
||||
* **操作系统**:Ubuntu 18.04.1 LTS Server Edition
|
||||
* **IP 地址** :192.168.225.22/24
|
||||
|
||||
### 1. 安装 Apache Web 服务器
|
||||
|
||||
首先,利用下面命令更新 Ubuntu 服务器:
|
||||
|
||||
```
|
||||
$ sudo apt update
|
||||
$ sudo apt upgrade
|
||||
```
|
||||
|
||||
然后,安装 Apache Web 服务器(命令如下):
|
||||
|
||||
```
|
||||
$ sudo apt install apache2
|
||||
```
|
||||
|
||||
检查 Apache Web 服务器是否已经运行:
|
||||
|
||||
```
|
||||
$ sudo systemctl status apache2
|
||||
```
|
||||
|
||||
输出结果大概是这样的:
|
||||
|
||||
```
|
||||
● apache2.service - The Apache HTTP Server
|
||||
Loaded: loaded (/lib/systemd/system/apache2.service; enabled; vendor preset: en
|
||||
Drop-In: /lib/systemd/system/apache2.service.d
|
||||
└─apache2-systemd.conf
|
||||
Active: active (running) since Tue 2019-02-05 10:48:03 UTC; 1min 5s ago
|
||||
Main PID: 2025 (apache2)
|
||||
Tasks: 55 (limit: 2320)
|
||||
CGroup: /system.slice/apache2.service
|
||||
├─2025 /usr/sbin/apache2 -k start
|
||||
├─2027 /usr/sbin/apache2 -k start
|
||||
└─2028 /usr/sbin/apache2 -k start
|
||||
|
||||
Feb 05 10:48:02 ubuntuserver systemd[1]: Starting The Apache HTTP Server...
|
||||
Feb 05 10:48:03 ubuntuserver apachectl[2003]: AH00558: apache2: Could not reliably
|
||||
Feb 05 10:48:03 ubuntuserver systemd[1]: Started The Apache HTTP Server.
|
||||
```
|
||||
|
||||
祝贺你! Apache 服务已经启动并运行了!!
|
||||
|
||||
#### 1.1 调整防火墙允许 Apache Web 服务器
|
||||
|
||||
默认情况下,如果你已在 Ubuntu 中启用 UFW 防火墙,则无法从远程系统访问 Apache Web 服务器。 必须按照以下步骤开启 `http` 和 `https` 端口。
|
||||
|
||||
首先,使用以下命令列出 Ubuntu 系统上可用的应用程序配置文件:
|
||||
|
||||
```
|
||||
$ sudo ufw app list
|
||||
```
|
||||
|
||||
输出结果:
|
||||
|
||||
```
|
||||
Available applications:
|
||||
Apache
|
||||
Apache Full
|
||||
Apache Secure
|
||||
OpenSSH
|
||||
```
|
||||
|
||||
如你所见,Apache 和 OpenSSH 应用程序已安装 UFW 配置文件。你可以使用 `ufw app info "Profile Name"` 命令列出有关每个配置文件及其包含的规则的信息。
|
||||
|
||||
让我们研究一下 “Apache Full” 配置文件。 为此,请运行:
|
||||
|
||||
```
|
||||
$ sudo ufw app info "Apache Full"
|
||||
```
|
||||
|
||||
输出结果:
|
||||
|
||||
```
|
||||
Profile: Apache Full
|
||||
Title: Web Server (HTTP,HTTPS)
|
||||
Description: Apache v2 is the next generation of the omnipresent Apache web
|
||||
server.
|
||||
|
||||
Ports:
|
||||
80,443/tcp
|
||||
```
|
||||
|
||||
如你所见,“Apache Full” 配置文件包含了启用经由端口 **80** 和 **443** 的传输规则:
|
||||
|
||||
现在,运行以下命令配置允许 HTTP 和 HTTPS 传入通信:
|
||||
|
||||
```
|
||||
$ sudo ufw allow in "Apache Full"
|
||||
Rules updated
|
||||
Rules updated (v6)
|
||||
```
|
||||
|
||||
如果你不想允许 HTTP 通信,而只允许 HTTP(80) 通信,请运行:
|
||||
|
||||
```
|
||||
$ sudo ufw app info "Apache"
|
||||
```
|
||||
|
||||
#### 1.2 测试 Apache Web 服务器
|
||||
|
||||
现在,打开 Web 浏览器并导航到 <http://localhost/> 或 <http://IP-Address/> 来访问 Apache 测试页。
|
||||
|
||||
![](https://www.ostechnix.com/wp-content/uploads/2016/06/apache-2.png)
|
||||
|
||||
如果看到上面类似的显示内容,那就成功了。 Apache 服务器正在工作!
|
||||
|
||||
### 2. 安装 MySQL
|
||||
|
||||
在 Ubuntu 安装 MySQL 请运行:
|
||||
|
||||
```
|
||||
$ sudo apt install mysql-server
|
||||
```
|
||||
|
||||
使用以下命令验证 MySQL 服务是否正在运行:
|
||||
|
||||
```
|
||||
$ sudo systemctl status mysql
|
||||
```
|
||||
|
||||
输出结果:
|
||||
|
||||
```
|
||||
● mysql.service - MySQL Community Server
|
||||
Loaded: loaded (/lib/systemd/system/mysql.service; enabled; vendor preset: enab
|
||||
Active: active (running) since Tue 2019-02-05 11:07:50 UTC; 17s ago
|
||||
Main PID: 3423 (mysqld)
|
||||
Tasks: 27 (limit: 2320)
|
||||
CGroup: /system.slice/mysql.service
|
||||
└─3423 /usr/sbin/mysqld --daemonize --pid-file=/run/mysqld/mysqld.pid
|
||||
|
||||
Feb 05 11:07:49 ubuntuserver systemd[1]: Starting MySQL Community Server...
|
||||
Feb 05 11:07:50 ubuntuserver systemd[1]: Started MySQL Community Server.
|
||||
```
|
||||
|
||||
MySQL 正在运行!
|
||||
|
||||
#### 2.1 配置数据库管理用户(root)密码
|
||||
|
||||
默认情况下,MySQL root 用户密码为空。你需要通过运行以下脚本使你的 MySQL 服务器安全:
|
||||
|
||||
```
|
||||
$ sudo mysql_secure_installation
|
||||
```
|
||||
|
||||
系统将询问你是否要安装 “VALIDATE PASSWORD plugin(密码验证插件)”。该插件允许用户为数据库配置强密码凭据。如果启用,它将自动检查密码的强度并强制用户设置足够安全的密码。**禁用此插件是安全的**。但是,必须为数据库使用唯一的强密码凭据。如果不想启用此插件,只需按任意键即可跳过密码验证部分,然后继续其余步骤。
|
||||
|
||||
如果回答是 `y`,则会要求你选择密码验证级别。
|
||||
|
||||
```
|
||||
Securing the MySQL server deployment.
|
||||
|
||||
Connecting to MySQL using a blank password.
|
||||
|
||||
VALIDATE PASSWORD PLUGIN can be used to test passwords
|
||||
and improve security. It checks the strength of password
|
||||
and allows the users to set only those passwords which are
|
||||
secure enough. Would you like to setup VALIDATE PASSWORD plugin?
|
||||
|
||||
Press y|Y for Yes, any other key for No y
|
||||
```
|
||||
|
||||
可用的密码验证有 “low(低)”、 “medium(中)” 和 “strong(强)”。只需输入适当的数字(0 表示低,1 表示中,2 表示强密码)并按回车键。
|
||||
|
||||
```
|
||||
There are three levels of password validation policy:
|
||||
|
||||
LOW Length >= 8
|
||||
MEDIUM Length >= 8, numeric, mixed case, and special characters
|
||||
STRONG Length >= 8, numeric, mixed case, special characters and dictionary file
|
||||
|
||||
Please enter 0 = LOW, 1 = MEDIUM and 2 = STRONG:
|
||||
```
|
||||
|
||||
现在,输入 MySQL root 用户的密码。请注意,必须根据上一步中选择的密码策略,为 MySQL root 用户使用密码。如果你未启用该插件,则只需使用你选择的任意强度且唯一的密码即可。
|
||||
|
||||
```
|
||||
Please set the password for root here.
|
||||
|
||||
New password:
|
||||
|
||||
Re-enter new password:
|
||||
|
||||
Estimated strength of the password: 50
|
||||
Do you wish to continue with the password provided?(Press y|Y for Yes, any other key for No) : y
|
||||
```
|
||||
|
||||
两次输入密码后,你将看到密码强度(在此示例情况下为 50)。如果你确定可以,请按 `y` 继续提供的密码。如果对密码长度不满意,请按其他任意键并设置一个强密码。我现在的密码可以,所以我选择了`y`。
|
||||
|
||||
对于其余的问题,只需键入 `y` 并按回车键。这将删除匿名用户、禁止 root 用户远程登录并删除 `test`(测试)数据库。
|
||||
|
||||
```
|
||||
Remove anonymous users? (Press y|Y for Yes, any other key for No) : y
|
||||
Success.
|
||||
|
||||
Normally, root should only be allowed to connect from
|
||||
'localhost'. This ensures that someone cannot guess at
|
||||
the root password from the network.
|
||||
|
||||
Disallow root login remotely? (Press y|Y for Yes, any other key for No) : y
|
||||
Success.
|
||||
|
||||
By default, MySQL comes with a database named 'test' that
|
||||
anyone can access. This is also intended only for testing,
|
||||
and should be removed before moving into a production
|
||||
environment.
|
||||
|
||||
Remove test database and access to it? (Press y|Y for Yes, any other key for No) : y
|
||||
- Dropping test database...
|
||||
Success.
|
||||
|
||||
- Removing privileges on test database...
|
||||
Success.
|
||||
|
||||
Reloading the privilege tables will ensure that all changes
|
||||
made so far will take effect immediately.
|
||||
|
||||
Reload privilege tables now? (Press y|Y for Yes, any other key for No) : y
|
||||
Success.
|
||||
|
||||
All done!
|
||||
```
|
||||
|
||||
以上就是为 MySQL root 用户设置密码。
|
||||
|
||||
#### 2.2 更改 MySQL 超级用户的身份验证方法
|
||||
|
||||
默认情况下,Ubuntu 系统的 MySQL root 用户为 MySQL 5.7 版本及更新的版本使用插件 `auth_socket` 设置身份验证。尽管它增强了安全性,但是当你使用任何外部程序(例如 phpMyAdmin)访问数据库服务器时,也会变得更困难。要解决此问题,你需要将身份验证方法从 `auth_socket` 更改为 `mysql_native_password`。为此,请使用以下命令登录到你的 MySQL 提示符下:
|
||||
|
||||
```
|
||||
$ sudo mysql
|
||||
```
|
||||
|
||||
在 MySQL 提示符下运行以下命令,找到所有 MySQL 当前用户帐户的身份验证方法:
|
||||
|
||||
```
|
||||
SELECT user,authentication_string,plugin,host FROM mysql.user;
|
||||
```
|
||||
|
||||
输出结果:
|
||||
|
||||
```
|
||||
+------------------|-------------------------------------------|-----------------------|-----------+
|
||||
| user | authentication_string | plugin | host |
|
||||
+------------------|-------------------------------------------|-----------------------|-----------+
|
||||
| root | | auth_socket | localhost |
|
||||
| mysql.session | *THISISNOTAVALIDPASSWORDTHATCANBEUSEDHERE | mysql_native_password | localhost |
|
||||
| mysql.sys | *THISISNOTAVALIDPASSWORDTHATCANBEUSEDHERE | mysql_native_password | localhost |
|
||||
| debian-sys-maint | *F126737722832701DD3979741508F05FA71E5BA0 | mysql_native_password | localhost |
|
||||
+------------------|-------------------------------------------|-----------------------|-----------+
|
||||
4 rows in set (0.00 sec)
|
||||
```
|
||||
|
||||
![][2]
|
||||
|
||||
如你所见,Mysql root 用户使用 `auth_socket` 插件进行身份验证。
|
||||
|
||||
要将此身份验证更改为 `mysql_native_password` 方法,请在 MySQL 提示符下运行以下命令。 别忘了用你选择的强大唯一的密码替换 `password`。 如果已启用 VALIDATION 插件,请确保已根据当前策略要求使用了强密码。
|
||||
|
||||
```
|
||||
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'password';
|
||||
```
|
||||
|
||||
使用以下命令更新数据库:
|
||||
|
||||
```
|
||||
FLUSH PRIVILEGES;
|
||||
```
|
||||
|
||||
使用命令再次检查身份验证方法是否已更改:
|
||||
|
||||
```
|
||||
SELECT user,authentication_string,plugin,host FROM mysql.user;
|
||||
```
|
||||
|
||||
输出结果:
|
||||
|
||||
![][3]
|
||||
|
||||
好!MySQL root 用户就可以使用密码进行身份验证来访问 `mysql shell`。
|
||||
|
||||
从 MySQL 提示符下退出:
|
||||
|
||||
```
|
||||
exit
|
||||
```
|
||||
|
||||
### 3. 安装 PHP
|
||||
|
||||
安装 PHP 请运行:
|
||||
|
||||
```
|
||||
$ sudo apt install php libapache2-mod-php php-mysql
|
||||
```
|
||||
|
||||
安装 PHP 后,在 Apache 文档根目录中创建 `info.php` 文件。通常,在大多数基于 Debian 的 Linux 发行版中,Apache 文档根目录为 `/var/www/html/` 或 `/var/www/`。Ubuntu 18.04 LTS 系统下,文档根目录是 `/var/www/html/`。
|
||||
|
||||
在 Apache 根目录中创建 `info.php` 文件:
|
||||
|
||||
```
|
||||
$ sudo vi /var/www/html/info.php
|
||||
```
|
||||
|
||||
在此文件中编辑如下内容:
|
||||
|
||||
```
|
||||
<?php
|
||||
phpinfo();
|
||||
?>
|
||||
```
|
||||
|
||||
然后按下 `ESC` 键并且输入 `:wq` 保存并退出此文件。重新启动 Apache 服务使更改生效。
|
||||
|
||||
```
|
||||
$ sudo systemctl restart apache2
|
||||
```
|
||||
|
||||
#### 3.1 测试 PHP
|
||||
|
||||
打开 Web 浏览器,然后导航到 URL <http://IP地址/info.php>。
|
||||
|
||||
你就将看到 PHP 测试页面。
|
||||
|
||||
![](https://www.ostechnix.com/wp-content/uploads/2019/02/php-test-page.png)
|
||||
|
||||
通常,当用户向 Web 服务器发出请求时,Apache 首先会在文档根目录中查找名为 `index.html` 的文件。如果你想将 Apache 更改为 `php` 文件提供服务而不是其他文件,请将 `dir.conf` 配置文件中的 `index.php` 移至第一个位置,如下所示:
|
||||
|
||||
```
|
||||
$ sudo vi /etc/apache2/mods-enabled/dir.conf
|
||||
```
|
||||
|
||||
上面的配置文件(`dir.conf`) 内容如下:
|
||||
|
||||
```
|
||||
<IfModule mod_dir.c>
|
||||
DirectoryIndex index.html index.cgi index.pl index.php index.xhtml index.htm
|
||||
</IfModule>
|
||||
|
||||
# vim: syntax=apache ts=4 sw=4 sts=4 sr noet
|
||||
```
|
||||
|
||||
将 `index.php` 移动到最前面。更改后,`dir.conf` 文件内容看起来如下所示。
|
||||
|
||||
```
|
||||
<IfModule mod_dir.c>
|
||||
DirectoryIndex index.php index.html index.cgi index.pl index.xhtml index.htm
|
||||
</IfModule>
|
||||
|
||||
# vim: syntax=apache ts=4 sw=4 sts=4 sr noet
|
||||
```
|
||||
|
||||
然后按下 `ESC` 键并且输入 `:wq` 保存并关闭此文件。重新启动 Apache 服务使更改生效。
|
||||
|
||||
```
|
||||
$ sudo systemctl restart apache2
|
||||
```
|
||||
|
||||
#### 3.2 安装 PHP 模块
|
||||
|
||||
为了增加 PHP 的功能,可以安装一些其他的 PHP 模块。
|
||||
|
||||
要列出可用的 PHP 模块,请运行:
|
||||
|
||||
```
|
||||
$ sudo apt-cache search php- | less
|
||||
```
|
||||
|
||||
输出结果:
|
||||
|
||||
![][4]
|
||||
|
||||
使用方向键浏览结果。要退出,请输入 `q` 并按下回车键。
|
||||
|
||||
要查找任意 `php` 模块的详细信息,例如 `php-gd`,请运行:
|
||||
|
||||
```
|
||||
$ sudo apt-cache show php-gd
|
||||
```
|
||||
|
||||
安装 PHP 模块请运行:
|
||||
|
||||
```
|
||||
$ sudo apt install php-gd
|
||||
```
|
||||
|
||||
安装所有的模块(虽然没有必要),请运行:
|
||||
|
||||
```
|
||||
$ sudo apt-get install php*
|
||||
```
|
||||
|
||||
安装任何 `php` 模块后,请不要忘记重新启动 Apache 服务。要检查模块是否已加载,请在浏览器中打开 `info.php` 文件并检查是否存在。
|
||||
|
||||
接下来,你可能需要安装数据库管理工具,以通过 Web 浏览器轻松管理数据库。如果是这样,请按照以下链接中的说明安装 `phpMyAdmin`。
|
||||
|
||||
祝贺你!我们已经在 Ubuntu 服务器中成功配置了 LAMP 套件。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.ostechnix.com/install-apache-mysql-php-lamp-stack-on-ubuntu-18-04-lts/
|
||||
|
||||
作者:[SK][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[stevenzdg988](https://github.com/stevenzdg988)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://www.ostechnix.com/author/sk/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7
|
||||
[2]: http://www.ostechnix.com/wp-content/uploads/2019/02/mysql-1.png
|
||||
[3]: http://www.ostechnix.com/wp-content/uploads/2019/02/mysql-2.png
|
||||
[4]: http://www.ostechnix.com/wp-content/uploads/2016/06/php-modules.png
|
@ -0,0 +1,89 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (Chao-zhi)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-13023-1.html)
|
||||
[#]: subject: (Do Linux distributions still matter with containers?)
|
||||
[#]: via: (https://opensource.com/article/19/2/linux-distributions-still-matter-containers)
|
||||
[#]: author: (Scott McCarty https://opensource.com/users/fatherlinux)
|
||||
|
||||
容器开发仍然要考虑 Linux 发行版吗?
|
||||
======
|
||||
|
||||
> 容器构建有两大趋势:使用基本镜像和从头开始构建。每个都有工程上的权衡。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202101/16/223919aubhguedlt8sk8i8.jpg)
|
||||
|
||||
有人说 Linux 发行版不再与容器有关。像 distroless 和 scratch 容器等可替代的方法,似乎是风靡一时。看来,我们在考虑和做出技术决策时,更多的是基于时尚感和即时的情感满足,而不是考虑我们选择的次要影响。我们应该问这样的问题:这些选择将如何影响未来六个月的维护?工程权衡是什么?这种范式转换如何影响我们的大规模构建系统?
|
||||
|
||||
这真让人沮丧。如果我们忘记了工程是一个零和游戏,有可衡量的利弊权衡,有不同方法的成本和收益 —— 这样对我们自己不利,对雇主不利,对最终维护我们的代码的同事不利。最后,我们对所有的维护人员([向维护人员致敬!][1] )都是一种伤害,因为我们不欣赏他们所做的工作。
|
||||
|
||||
### 理解问题所在
|
||||
|
||||
为了理解这个问题,我们必须首先研究为什么我们使用 Linux 发行版。我将把原因分为两大类:内核和其他包。编译内核实际上相当容易。Slackware 和 Gentoo( 我的小心脏还是有点害怕)教会了我们这一点。
|
||||
|
||||
另一方面,对于一个可用的 Linux 系统需要打包大量的开发软件和应用软件,这可能会让人望而生畏。此外,确保数百万个程序包可以一起安装和工作的唯一方法是使用旧的范例:即编译它并将它作为一个工件(即 Linux 发行版)一起发布。那么,为什么 Linux 发行版要将内核和所有包一起编译呢?很简单:确保事情协调一致。
|
||||
|
||||
首先,我们来谈谈内核。内核很特别。在没有编译好的内核的情况下引导 Linux 系统有点困难。它是 Linux 操作系统的核心,也是我们在系统启动时首先依赖的。内核在编译时有很多不同的配置选项,这些选项会对硬件和软件如何在一个内核上运行产生巨大影响。这方面中的第二个问题是,系统软件(如编译器 、C 库和解释器)必须针对内核中内置的选项进行调优。Gentoo 的维基以一种发自内心的方式教我们这一点,它把每个人都变成了一个微型的开发版维护者。
|
||||
|
||||
令人尴尬的是(因为我在过去五年里一直在使用容器),我必须承认我最近才编译过内核。我必须让嵌套的 KVM 在 RHEL7 上工作,这样我才能在笔记本电脑上的 KVM 虚拟机中运行 [OpenShift on OpenStack][2] 虚拟机,以及我的 [Container Development Kit(CDK)][3]。我只想说,当时我在一个全新的 4.X 内核上启动了 RHEL7。和任何优秀的系统管理员一样,我有点担心自己错过了一些重要的配置选项和补丁。当然,我也的确错过了一些东西。比如睡眠模式无法正常工作,我的扩展底座无法正常工作,还有许多其他小的随机错误。但它在我的笔记本电脑上的一个 KVM 虚拟机上,对于 OpenStack 上的 OpenShift 的实时演示来说已经足够好了。来吧,这很有趣,对吧?但我离题了……
|
||||
|
||||
现在,我们来谈谈其他的软件包。虽然内核和相关的系统软件可能很难编译,但从工作负载的角度来看,更大的问题是编译成千上万的包,以提供一个可用的 Linux 系统。每个软件包都需要专业知识。有些软件只需要运行三个命令:`./configure`、`make` 和 `make install`。另一些则需要大量的专业知识,从在 `etc` 中添加用户和配置特定的默认值到运行安装后脚本和添加 systemd 单元文件。对于任何一个人来说,调试好你可能用得到的成千上万种不同软件所需要的一套技能都是令人望而生畏的。但是,如果你想要一个可以随时尝试新软件的可用系统,你必须学会如何编译和安装新软件,然后才能开始学习使用它。这就是没有 Linux 发行版的 Linux。当你放弃使用 Linux 发行版时,那么你就得自己编译软件。
|
||||
|
||||
关键是,你必须将所有内容构建在一起,以确保它能够以任何合理的可靠性级别协同工作,而且构建一个可用的包群需要大量的知识。这是任何一个开发人员或系统管理员都无法合理地学习和保留的知识。我描述的每个问题都适用于你的 [容器主机][4](内核和系统软件)和 [容器镜像][5](系统软件和所有其他包)——请注意:在容器镜像中还包含有编译器 、C 库、解释器和 JVM。
|
||||
|
||||
### 解决方案
|
||||
|
||||
所以你也看到了,其实使用 Linux 发行版就是解决方案。别再看了,给离你最近的软件包维护者(再次向维护人员致敬!)发张电子卡吧(等等,我是不是把我的年龄告诉别人了?)。不过说真的,这些人做了大量的工作,这真的是被低估了。Kubernetes、Istio、Prometheus,还有 Knative:我在看着你们。你们的时代要来了,到时候你们会进入维护模式,被过度使用,被低估。大约七到十年后,我将再次写这篇文章,可能是关于 Kubernetes 的。
|
||||
|
||||
### 容器构建的首要原则
|
||||
|
||||
从零开始构建和从基础镜像构建之间存在权衡。
|
||||
|
||||
#### 从基础镜像构建
|
||||
|
||||
从基础镜像构建的优点是,大多数构建操作只不过是安装或更新包。它依赖于 Linux 发行版中包维护人员所做的大量工作。它还有一个优点,即六个月甚至十年后的修补事件(使用 RHEL)是运维/系统管理员事件 (`yum update`),而不是开发人员事件(这需要通过代码找出某些函数参数不再工作的原因)。
|
||||
|
||||
你想想,应用程序代码依赖于许多库,从 JSON mung 库到对象关系映射器。与 Linux 内核和 Glibc 不同,这些类型的库很少改变 API 兼容性。这意味着三年后你的修补事件可能会变成代码更改事件,而不是 yum 更新事件。因此让他自己深入下去吧。开发人员,如果安全团队找不到防火墙黑客来阻止攻击,你将在凌晨 2 点收到短信。
|
||||
|
||||
从基础镜像构建不是完美的;还有一些缺点,比如所有被拖入的依赖项的大小。这几乎总是会使容器镜像比从头开始构建的镜像更大。另一个缺点是你并不总是能够访问最新的上游代码。这可能会让开发人员感到沮丧,尤其是当你只想使用依赖项中的一部分功能时,但是你仍然不得不将你根本用不着的东西一起打包带走,因为上游的维护人员一直在改变这个库。
|
||||
|
||||
如果你是一个 web 开发人员,正在对我翻白眼,我有一个词可以形容你:DevOps。那意味着你带着寻呼机,我的朋友。
|
||||
|
||||
#### Scratch 构建
|
||||
|
||||
Scratch 构建的优点是镜像非常小。当你不依赖容器中的 Linux 发行版时,你有很多控制权,这意味着你可以根据需要定制所有内容。这是一个最佳模型,在某些用例中是很有效的。另一个优势是你可以访问最新的软件包。你不必等待 Linux 发行版更新任何内容。是你自己在控制,所以你可以自行选择什么时候去费功夫纳入新的软件。
|
||||
|
||||
记住,控制一切都是有代价的。通常,更新到具有新特性的新库会拖如不必要的 API 更改,这意味着修复代码中的不兼容(换句话说,这就像[给牦牛剪毛][6])。在凌晨 2 点应用程序不起作用的时候给牦牛剪毛是不好玩的。幸运的是,使用容器,你可以在下一个工作日回滚并给牦牛剪毛,但它仍会占用你为业务提供新价值、为应用程序提供新功能的时间。欢迎来到系统管理员的生活。
|
||||
|
||||
好吧,也就是说,有些时候,Scratch 构建是有意义的。我完全承认,静态编译的 Golang 程序和 C 程序是 scratch/distorless 构建的两个不错的候选程序。对于这些类型的程序,每个容器构建都是一个编译事件。三年后你仍然需要担心 API 的损坏,但是如果你是一个 Golang 商店,你应该有能力随着时间的推移修复问题。
|
||||
|
||||
### 结论
|
||||
|
||||
基本上,Linux 发行版做了大量工作来节省你在常规 Linux 系统或容器上的时间。维护人员所拥有的知识是巨大的,而且没有得到真正的赞赏。容器的采用使得问题更加严重,因为它被进一步抽象了。
|
||||
|
||||
通过容器主机,Linux 发行版可以让你访问广泛的硬件生态系统,从微型 ARM 系统到 128 核 CPU x86 巨型机箱,再到云服务商的虚拟机。他们提供可工作的容器引擎和开箱即用的容器运行时环境,所以你只需启动你的容器,让其他人担心事情的进展。
|
||||
|
||||
对于容器镜像,Linux 发行版为你的项目提供了对大量软件的轻松访问。即使你从头开始构建,你也可能会看到一个包维护人员是如何构建和运送东西的 —— 一个好的艺术家是一个好的偷学者,所以不要低估这项工作的价值。
|
||||
|
||||
所以,感谢 Fedora、RHEL(Frantisek,你是我的英雄 )、Debian、Gentoo 和其他 Linux 发行版的所有维护人员。我很感激你所做的工作,尽管我是个“容器工人”
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/19/2/linux-distributions-still-matter-containers
|
||||
|
||||
作者:[Scott McCarty][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[Chao-zhi](https://github.com/Chao-zhi)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/fatherlinux
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://aeon.co/essays/innovation-is-overvalued-maintenance-often-matters-more
|
||||
[2]: https://blog.openshift.com/openshift-on-openstack-delivering-applications-better-together/
|
||||
[3]: https://developers.redhat.com/blog/2018/02/13/red-hat-cdk-nested-kvm/
|
||||
[4]: https://developers.redhat.com/blog/2018/02/22/container-terminology-practical-introduction/#h.8tyd9p17othl
|
||||
[5]: https://developers.redhat.com/blog/2018/02/22/container-terminology-practical-introduction/#h.dqlu6589ootw
|
||||
[6]: https://en.wiktionary.org/wiki/yak_shaving
|
@ -1,33 +1,33 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: translator: (stevenzdg988)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-13012-1.html)
|
||||
[#]: subject: (Printing from the Linux command line)
|
||||
[#]: via: (https://www.networkworld.com/article/3373502/printing-from-the-linux-command-line.html)
|
||||
[#]: author: (Sandra Henry-Stocker https://www.networkworld.com/author/Sandra-Henry_Stocker/)
|
||||
|
||||
Printing from the Linux command line
|
||||
从 Linux 命令行进行打印
|
||||
======
|
||||
|
||||
There's a lot more to printing from the Linux command line than the lp command. Check out some of the many available options.
|
||||
> 在 Linux 命令行进行打印的内容比单单一个 `lp` 命令多得多,让我们来看一些可用选项。
|
||||
|
||||
![Sherry \(CC BY 2.0\)][1]
|
||||
|
||||
Printing from the Linux command line is easy. You use the **lp** command to request a print, and **lpq** to see what print jobs are in the queue, but things get a little more complicated when you want to print double-sided or use portrait mode. And there are lots of other things you might want to do — such as printing multiple copies of a document or canceling a print job. Let's check out some options for getting your printouts to look just the way you want them to when you're printing from the command line.
|
||||
Linux 命令行打印很容易。你可以使用 `lp` 命令来请求打印,并使用 `lpq` 命令来查看队列中有哪些打印作业,但是当你要双面打印或使用纵向模式时,这些会变得有些复杂。你可能还需要做很多其他事情,例如打印多份文档副本或取消打印作业。让我们来看看一些选项,当你从命令行打印时,如何让你的打印输出看起来如你所愿。
|
||||
|
||||
### Displaying printer settings
|
||||
### 显示打印机配置
|
||||
|
||||
To view your printer settings from the command line, use the **lpoptions** command. The output should look something like this:
|
||||
要从命令行查看打印机设置,请使用 `lpoptions` 命令。 输出应如下所示:
|
||||
|
||||
```
|
||||
$ lpoptions
|
||||
copies=1 device-uri=dnssd://HP%20Color%20LaserJet%20CP2025dn%20(F47468)._pdl-datastream._tcp.local/ finishings=3 job-cancel-after=10800 job-hold-until=no-hold job-priority=50 job-sheets=none,none marker-change-time=1553023232 marker-colors=#000000,#00FFFF,#FF00FF,#FFFF00 marker-levels=18,62,62,63 marker-names='Black\ Cartridge\ HP\ CC530A,Cyan\ Cartridge\ HP\ CC531A,Magenta\ Cartridge\ HP\ CC533A,Yellow\ Cartridge\ HP\ CC532A' marker-types=toner,toner,toner,toner number-up=1 printer-commands=none printer-info='HP Color LaserJet CP2025dn (F47468)' printer-is-accepting-jobs=true printer-is-shared=true printer-is-temporary=false printer-location printer-make-and-model='HP Color LaserJet cp2025dn pcl3, hpcups 3.18.7' printer-state=3 printer-state-change-time=1553023232 printer-state-reasons=none printer-type=167964 printer-uri-supported=ipp://localhost/printers/Color-LaserJet-CP2025dn sides=one-sided
|
||||
```
|
||||
|
||||
This output is likely to be a little more human-friendly if you turn its blanks into carriage returns. Notice how many settings are listed.
|
||||
如果将其空格转换为回车符,输出可能会更人性化,请注意列出了多少设置选项。
|
||||
|
||||
NOTE: In the output below, some lines have been reconnected to make this output more readable.
|
||||
注意:在下面的输出中,一些行被重新链接,以使输出更具可读性。
|
||||
|
||||
```
|
||||
$ lpoptions | tr " " '\n'
|
||||
@ -62,7 +62,7 @@ printer-uri-supported=ipp://localhost/printers/Color-LaserJet-CP2025dn
|
||||
sides=one-sided
|
||||
```
|
||||
|
||||
With the **-v** option, the **lpinfo** command will list drivers and related information.
|
||||
使用 `-v` 选项时,`lpinfo` 命令将列出驱动程序和相关信息:
|
||||
|
||||
```
|
||||
$ lpinfo -v
|
||||
@ -80,13 +80,13 @@ network dnssd://HP%20Color%20LaserJet%20CP2025dn%20(F47468)._pdl-datastream._tcp
|
||||
network socket://192.168.0.23 <== printer IP
|
||||
```
|
||||
|
||||
The lpoptions command will show the settings of your default printer. Use the **-p** option to specify one of a number of available printers.
|
||||
`lpoptions` 命令将显示默认打印机的设置。使用 `-p` 选项指定其中一个可用打印机代号:
|
||||
|
||||
```
|
||||
$ lpoptions -p LaserJet
|
||||
```
|
||||
|
||||
The **lpstat -p** command displays the status of a printer while **lpstat -p -d** also lists available printers.
|
||||
`lpstat -p` 命令显示打印机的状态,而 `lpstat -p -d` 列出可用打印机列表。
|
||||
|
||||
```
|
||||
$ lpstat -p -d
|
||||
@ -94,16 +94,16 @@ printer Color-LaserJet-CP2025dn is idle. enabled since Tue 19 Mar 2019 05:07:45
|
||||
system default destination: Color-LaserJet-CP2025dn
|
||||
```
|
||||
|
||||
### Useful commands
|
||||
### 非常有用的命令
|
||||
|
||||
To print a document on the default printer, just use the **lp** command followed by the name of the file you want to print. If the filename includes blanks (rare on Linux systems), either put the name in quotes or start entering the file name and press the tab key to invoke file completion (as shown in the second example below).
|
||||
要在默认打印机上打印文档,只需使用 `lp` 命令,后跟要打印的文件名即可。 如果文件名包含空格(在 Linux 系统上很少见),请将该名称放在引号中或开始输入文件名并按 `Tab` 键调用空格的转义标志(如下面的第二个示例所示)。
|
||||
|
||||
```
|
||||
$ lp "never leave home angry"
|
||||
$ lp never\ leave\ home\ angry
|
||||
```
|
||||
|
||||
The **lpq** command displays the print queue.
|
||||
`lpq` 命令显示打印队列:
|
||||
|
||||
```
|
||||
$ lpq
|
||||
@ -112,52 +112,50 @@ Rank Owner Job File(s) Total Size
|
||||
active shs 234 agenda 2048 bytes
|
||||
```
|
||||
|
||||
With the **-n** option, the lp command allows you to specify the number of copies of a printout you want.
|
||||
使用 `-n` 选项时,`lp` 命令可用来指定所需打印输出的份数:
|
||||
|
||||
```
|
||||
$ lp -n 11 agenda
|
||||
```
|
||||
|
||||
To cancel a print job, you can use the **cancel** or **lprm** command. If you don't act quickly, you might see this:
|
||||
要取消打印作业,可以使用 `cancel` 或 `lprm` 命令。如果没来得及执行,则可能会看到以下信息:
|
||||
|
||||
```
|
||||
$ cancel 229
|
||||
cancel: cancel-job failed: Job #229 is already completed - can't cancel.
|
||||
```
|
||||
|
||||
### Two-sided printing
|
||||
### 双面打印
|
||||
|
||||
To print in two-sided mode, you can issue your lp command with a **sides** option that says both to print on both sides of the paper and which edge to turn the paper on. This setting represents the normal way that you would expect two-sided portrait documents to look.
|
||||
要以双面模式打印,你可以在 `lp` 命令中使用 `sides` 选项,该选项不但表示了在纸张的正反面进行打印,还表示了从纸张的哪个边开始打印。这个设置代表了你期望以双面纵向文档的正常方式打印。
|
||||
|
||||
```
|
||||
$ lp -o sides=two-sided-long-edge Notes.pdf
|
||||
```
|
||||
|
||||
If you want all of your documents to print in two-side mode, you can change your lp settings by using the **lpoptions** command to change the setting for **sides**.
|
||||
如果要所有文档以双面模式打印,则可以使用 `lpoptions` 命令更改 `sides` 设置以修改 `lp` 的设置。
|
||||
|
||||
```
|
||||
$ lpoptions -o sides=two-sided-short-edge
|
||||
```
|
||||
|
||||
To revert to single-sided printing, you would use a command like this one:
|
||||
要恢复为单面打印,可以使用如下命令:
|
||||
|
||||
```
|
||||
$ lpoptions -o sides=one-sided
|
||||
```
|
||||
|
||||
#### Printing in landscape mode
|
||||
#### 横向打印
|
||||
|
||||
To print in landscape mode, you would use the **landscape** option with the lp command.
|
||||
要以横向模式打印,可以在 `lp` 命令中使用 `landscape` 选项。
|
||||
|
||||
```
|
||||
$ lp -o landscape penguin.jpg
|
||||
```
|
||||
|
||||
### CUPS
|
||||
### CUPS(Unix 通用打印系统)
|
||||
|
||||
The print system used on Linux systems is the standards-based, open source printing system called CUPS, originally standing for **Common Unix Printing System**. It allows a computer to act as a print server.
|
||||
|
||||
Join the Network World communities on [Facebook][2] and [LinkedIn][3] to comment on topics that are top of mind.
|
||||
Linux 系统上使用的打印系统是基于标准的开源打印系统,称为 **CUPS**,原意是<ruby>Unix 通用打印系统<rt>Common Unix Printing System</rt></ruby>。 它允许计算机充当打印服务器。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
@ -165,8 +163,8 @@ via: https://www.networkworld.com/article/3373502/printing-from-the-linux-comman
|
||||
|
||||
作者:[Sandra Henry-Stocker][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
译者:[stevenzdg988](https://github.com/stevenzdg988)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
@ -0,0 +1,264 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (Chao-zhi)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-13015-1.html)
|
||||
[#]: subject: (Monitor and Manage Docker Containers with Portainer.io \(GUI tool\) – Part-2)
|
||||
[#]: via: (https://www.linuxtechi.com/monitor-manage-docker-containers-portainer-io-part-2/)
|
||||
[#]: author: (Shashidhar Soppin https://www.linuxtechi.com/author/shashidhar/)
|
||||
|
||||
用 Portainer.io 来监控和管理 Docker 容器(2)
|
||||
======
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202101/14/204401knuxjru53n5su6ns.jpg)
|
||||
|
||||
作为[第 1 部分](https://linux.cn/article-12634-1.html)的延续,本第 2 部分将介绍 Portainer 的其余功能。
|
||||
|
||||
### 监控 docker 容器镜像
|
||||
|
||||
```
|
||||
root@linuxtechi ~}$ docker ps -a
|
||||
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
|
||||
9ab9aa72f015 ubuntu "/bin/bash" 14 seconds ago Exited (0) 12 seconds ago suspicious_shannon
|
||||
305369d3b2bb centos "/bin/bash" 24 seconds ago Exited (0) 22 seconds ago admiring_mestorf
|
||||
9a669f3dc4f6 portainer/portainer "/portainer" 7 minutes ago Up 7 minutes 0.0.0.0:9000->9000/tcp trusting_keller
|
||||
```
|
||||
|
||||
包括 `portainer`(docker 容器镜像),所有已退出和当前正在运行的 docker 镜像都会显示出来。下面的 Portainer GUI 屏幕截图显示了相同的情况。
|
||||
|
||||
![Docker_status][1]
|
||||
|
||||
### 监视事件
|
||||
|
||||
单击 portainer 网页中的“Events”选项,如下所示。
|
||||
|
||||
基于 docker 容器活动生成和创建的各种事件将被提取并显示在此页面中.
|
||||
|
||||
![Container-Events-Poratiner-GUI][3]
|
||||
|
||||
现在检查并验证“Events”部分是如何工作的。创建一个新的 docker 容器镜像 `redis`,如下所述,在 docker 命令行检查状态:`docker ps –a`:
|
||||
|
||||
```
|
||||
root@linuxtechi ~}$ docker ps -a
|
||||
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
|
||||
cdbfbef59c31 redis "docker-entrypoint.s…" About a minute ago Up About a minute 6379/tcp angry_varahamihira
|
||||
9ab9aa72f015 ubuntu "/bin/bash" 10 minutes ago Exited (0) 10 minutes ago suspicious_shannon
|
||||
305369d3b2bb centos "/bin/bash" 11 minutes ago Exited (0) 11 minutes ago admiring_mestorf
|
||||
9a669f3dc4f6 portainer/portainer "/portainer" 17 minutes ago Up 17 minutes 0.0.0.0:9000->9000/tcp trusting_keller
|
||||
```
|
||||
|
||||
单击顶部的“Event List”刷新事件列表,
|
||||
|
||||
![events_updated][5]
|
||||
|
||||
现在事件的页面也更新了这个变化,
|
||||
|
||||
### 主机状态
|
||||
|
||||
下面是 portainer 显示主机状态的屏幕截图。这是一个简单的窗口。这显示了主机 Linux 机器的基本信息,如“CPU”、“主机名”、“操作系统信息”等。这个页面在不需要登录主机命令行的情况下提供了非常有用的信息,以便快速浏览。
|
||||
|
||||
![Host-names-Portainer][7]
|
||||
|
||||
### Portainer 中的仪表板
|
||||
|
||||
到目前为止,我们已经在“Local”部分看到了基于 portainer 的各种特性。现在跳到所选 Docker 容器镜像的“Dashboard”部分。
|
||||
|
||||
在 Portainer 的网页中单击“EndPoint”选项时,会出现以下窗口:
|
||||
|
||||
![End_Point_Settings][9]
|
||||
|
||||
对于主机容器镜像,此仪表板有许多状态和选项。
|
||||
|
||||
#### Stacks
|
||||
|
||||
单击此选项可提供任何堆栈(如果有的话)的状态。因为这里没有堆栈,所以显示为零。
|
||||
|
||||
#### Images
|
||||
|
||||
单击此选项可提供主机中可用的容器镜像。此选项将显示所有活动和退出的容器镜像。
|
||||
|
||||
![Docker-Container-Images-Portainer][11]
|
||||
|
||||
例如,再创建一个“Nginx”容器并刷新此列表以查看更新:
|
||||
|
||||
```
|
||||
root@linuxtechi ~}$ sudo docker run nginx
|
||||
Unable to find image 'nginx:latest' locally
|
||||
latest: Pulling from library/nginx
|
||||
27833a3ba0a5: Pull complete
|
||||
ea005e36e544: Pull complete
|
||||
d172c7f0578d: Pull complete
|
||||
Digest: sha256:e71b1bf4281f25533cf15e6e5f9be4dac74d2328152edf7ecde23abc54e16c1c
|
||||
Status: Downloaded newer image for nginx:latest
|
||||
```
|
||||
|
||||
下面是刷新后的镜像界面:
|
||||
|
||||
![Nginx_Image_creation][13]
|
||||
|
||||
当 Nginx 镜像处于 `stopped`/`killed` 状态时,docker 的容器镜像会改变为 `unused` 状态。
|
||||
|
||||
**注**:你可以看到这里所有的镜像的细节都非常清楚,比如内存使用,创建日期和时间。与命令行选项相比,从这里维护和监视容器将非常容易。
|
||||
|
||||
#### Networks
|
||||
|
||||
此选项用于网络操作。例如分配 IP 地址、创建子网、提供 IP 地址范围、访问控制(管理员和普通用户)。下面的窗口提供了各种可能选项的详细信息。根据你的需要,可以进一步去自行研究这些选项。
|
||||
|
||||
![Conatiner-Network-Portainer][15]
|
||||
|
||||
输入所有各种网络参数后,单击“create network”按钮即可创建网络。
|
||||
|
||||
#### Container
|
||||
|
||||
此选项将提供容器状态。此列表将提供有关活动的和未运行的容器状态的详细信息。此输出类似于 docker ps 命令选项。
|
||||
|
||||
![Containers-Status-Portainer][17]
|
||||
|
||||
在该窗口中,通过选中复选框并选择上述按钮可以根据需要控制容器停止和启动。一个例子如下:
|
||||
|
||||
例如,“CentOS”和“Ubuntu”容器都处于停止状态,现在可以通过选中复选框并点击“Start”按钮来启动它们。
|
||||
|
||||
![start_containers1][19]
|
||||
|
||||
![start_containers2][21]
|
||||
|
||||
**注意:** 因为这两个都是 Linux 容器镜像,所以不会被启动。Portainer 尝试启动,但稍后又停止。试试启动“Nginx”,你会看到它变成了 `running` 状态。
|
||||
|
||||
![start_containers3][23]
|
||||
|
||||
#### Volume
|
||||
|
||||
参见本文章第一部分。
|
||||
|
||||
### Portainer 中的设置选项
|
||||
|
||||
到目前为止,我们已经在“Local”部分看到了基于 portainer 的各种特性。现在跳到所选 Docker 容器图像的“Settings”部分。
|
||||
|
||||
在 Portainer 的网页中单击“Settings”选项时,可以使用以下的配置选项:
|
||||
|
||||
#### Extensions
|
||||
|
||||
这是一个简单的 Portainer CE 订阅程序。详细信息和用途可以从附加的窗口中看到。这主要用于维护相应版本的许可证和订阅。
|
||||
|
||||
![Extensions][25]
|
||||
|
||||
#### Users
|
||||
|
||||
此选项用于添加具有或不具有管理权限的“用户”。下面的示例提供了相同的示例。
|
||||
|
||||
在本例中输入你的想好的用户名比如“shashi”和你选择的密码,然后点击下面的“Create User”按钮。
|
||||
|
||||
![create_user_portainer][27]
|
||||
|
||||
![create_user2_portainer][29]
|
||||
|
||||
![Internal-user-Portainer][31]
|
||||
|
||||
类似地,可以通过选中复选框并点击 “remove” 按钮来删除刚刚创建的用户“shashi”。
|
||||
|
||||
![user_remove_portainer][33]
|
||||
|
||||
#### Endpoints
|
||||
|
||||
此选项用于端点终端管理。终端可以添加和删除,如附加窗口中所示。
|
||||
|
||||
![Endpoint-Portainer-GUI][35]
|
||||
|
||||
新终端“shashi”是使用如下所示的各种默认参数创建的,
|
||||
|
||||
![Endpoint2-Portainer-GUI][37]
|
||||
|
||||
类似地,可以通过单击复选框并单击移除按钮来移除此端点。
|
||||
|
||||
#### Registries
|
||||
|
||||
此选项用于注册管理。由于 docker hub 有各种镜像的注册,因此此功能可用于类似的目的。
|
||||
|
||||
![Registry-Portainer-GUI][39]
|
||||
|
||||
使用默认选项就可以创建“shashi-registry”。
|
||||
|
||||
![Registry2-Portainer-GUI][41]
|
||||
|
||||
同样,如果不需要了,就可以移除它。
|
||||
|
||||
#### Settings
|
||||
|
||||
此选项用于设置以下各种选项,
|
||||
|
||||
* 设置快照间隔
|
||||
* 设置自定义徽标
|
||||
* 创建外部模板
|
||||
* 安全功能,如:为非管理员禁用和启用 bin 挂载,为非管理员禁用/启用权限,启用主机管理功能
|
||||
|
||||
下面的屏幕截图显示了出于演示目的启用和禁用的一些选项。一旦全部完成点击“保存设置”按钮保存所有这些选项。
|
||||
|
||||
![Portainer-GUI-Settings][43]
|
||||
|
||||
现在点开“Authentication settings”就会弹出 LDAP、Internal 和 OAuth(extension)选项,如下所示:
|
||||
|
||||
![Authentication-Portainer-GUI-Settings][45]
|
||||
|
||||
根据我们想要的环境安全特性级别,选择相应的选项。
|
||||
|
||||
以上就是本文的内容,我希望这些介绍 portainer 的文章能帮助你更有效地管理和监视容器。请分享你的反馈和意见。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.linuxtechi.com/monitor-manage-docker-containers-portainer-io-part-2/
|
||||
|
||||
作者:[Shashidhar Soppin][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[Chao-zhi](https://github.com/Chao-zhi)
|
||||
校对:[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/wp-content/uploads/2019/05/Docker_status-1024x423.jpg
|
||||
[2]: https://www.linuxtechi.com/wp-content/uploads/2019/05/Docker_status.jpg
|
||||
[3]: https://www.linuxtechi.com/wp-content/uploads/2019/05/Events-1024x404.jpg
|
||||
[4]: https://www.linuxtechi.com/wp-content/uploads/2019/05/Events.jpg
|
||||
[5]: https://www.linuxtechi.com/wp-content/uploads/2019/05/events_updated-1024x414.jpg
|
||||
[6]: https://www.linuxtechi.com/wp-content/uploads/2019/05/events_updated.jpg
|
||||
[7]: https://www.linuxtechi.com/wp-content/uploads/2019/05/Host_names-1024x408.jpg
|
||||
[8]: https://www.linuxtechi.com/wp-content/uploads/2019/05/Host_names.jpg
|
||||
[9]: https://www.linuxtechi.com/wp-content/uploads/2019/05/End_Point_Settings-1024x471.jpg
|
||||
[10]: https://www.linuxtechi.com/wp-content/uploads/2019/05/End_Point_Settings.jpg
|
||||
[11]: https://www.linuxtechi.com/wp-content/uploads/2019/05/Images-1024x398.jpg
|
||||
[12]: https://www.linuxtechi.com/wp-content/uploads/2019/05/Images.jpg
|
||||
[13]: https://www.linuxtechi.com/wp-content/uploads/2019/05/Nginx_Image_creation-1024x439.jpg
|
||||
[14]: https://www.linuxtechi.com/wp-content/uploads/2019/05/Nginx_Image_creation.jpg
|
||||
[15]: https://www.linuxtechi.com/wp-content/uploads/2019/05/Network-1024x463.jpg
|
||||
[16]: https://www.linuxtechi.com/wp-content/uploads/2019/05/Network.jpg
|
||||
[17]: https://www.linuxtechi.com/wp-content/uploads/2019/05/Containers-1024x364.jpg
|
||||
[18]: https://www.linuxtechi.com/wp-content/uploads/2019/05/Containers.jpg
|
||||
[19]: https://www.linuxtechi.com/wp-content/uploads/2019/05/start_containers1-1024x432.jpg
|
||||
[20]: https://www.linuxtechi.com/wp-content/uploads/2019/05/start_containers1.jpg
|
||||
[21]: https://www.linuxtechi.com/wp-content/uploads/2019/05/start_containers2-1024x307.jpg
|
||||
[22]: https://www.linuxtechi.com/wp-content/uploads/2019/05/start_containers2.jpg
|
||||
[23]: https://www.linuxtechi.com/wp-content/uploads/2019/05/start_containers3-1024x435.jpg
|
||||
[24]: https://www.linuxtechi.com/wp-content/uploads/2019/05/start_containers3.jpg
|
||||
[25]: https://www.linuxtechi.com/wp-content/uploads/2019/05/Extensions-1024x421.jpg
|
||||
[26]: https://www.linuxtechi.com/wp-content/uploads/2019/05/Extensions.jpg
|
||||
[27]: https://www.linuxtechi.com/wp-content/uploads/2019/05/create_user-1024x350.jpg
|
||||
[28]: https://www.linuxtechi.com/wp-content/uploads/2019/05/create_user.jpg
|
||||
[29]: https://www.linuxtechi.com/wp-content/uploads/2019/05/create_user2-1024x372.jpg
|
||||
[30]: https://www.linuxtechi.com/wp-content/uploads/2019/05/create_user2.jpg
|
||||
[31]: https://www.linuxtechi.com/wp-content/uploads/2019/05/Internal-user-Portainer-1024x257.jpg
|
||||
[32]: https://www.linuxtechi.com/wp-content/uploads/2019/05/Internal-user-Portainer.jpg
|
||||
[33]: https://www.linuxtechi.com/wp-content/uploads/2019/05/user_remove-1024x318.jpg
|
||||
[34]: https://www.linuxtechi.com/wp-content/uploads/2019/05/user_remove.jpg
|
||||
[35]: https://www.linuxtechi.com/wp-content/uploads/2019/05/Endpoint-1024x349.jpg
|
||||
[36]: https://www.linuxtechi.com/wp-content/uploads/2019/05/Endpoint.jpg
|
||||
[37]: https://www.linuxtechi.com/wp-content/uploads/2019/05/Endpoint2-1024x379.jpg
|
||||
[38]: https://www.linuxtechi.com/wp-content/uploads/2019/05/Endpoint2.jpg
|
||||
[39]: https://www.linuxtechi.com/wp-content/uploads/2019/05/Registry-1024x420.jpg
|
||||
[40]: https://www.linuxtechi.com/wp-content/uploads/2019/05/Registry.jpg
|
||||
[41]: https://www.linuxtechi.com/wp-content/uploads/2019/05/Registry2-1024x409.jpg
|
||||
[42]: https://www.linuxtechi.com/wp-content/uploads/2019/05/Registry2.jpg
|
||||
[43]: https://www.linuxtechi.com/wp-content/uploads/2019/05/Portainer-GUI-Settings-1024x418.jpg
|
||||
[44]: https://www.linuxtechi.com/wp-content/uploads/2019/05/Portainer-GUI-Settings.jpg
|
||||
[45]: https://www.linuxtechi.com/wp-content/uploads/2019/05/Authentication-Portainer-GUI-Settings-1024x344.jpg
|
||||
[46]: https://www.linuxtechi.com/wp-content/uploads/2019/05/Authentication-Portainer-GUI-Settings.jpg
|
@ -0,0 +1,391 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (stevenzdg988)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-13037-1.html)
|
||||
[#]: subject: (Integrate online documents editors, into a Python web app using ONLYOFFICE)
|
||||
[#]: via: (https://opensourceforu.com/2019/09/integrate-online-documents-editors-into-a-python-web-app-using-onlyoffice/)
|
||||
[#]: author: (Aashima Sharma https://opensourceforu.com/author/aashima-sharma/)
|
||||
|
||||
利用 ONLYOFFICE 将在线文档编辑器集成到 Python Web 应用程序中
|
||||
======
|
||||
|
||||
![][1]
|
||||
|
||||
[ONLYOFFICE][3] 是根据 GNU AGPL v.3 许可证条款分发的开源协作办公套件。它包含三个用于文本文档、电子表格和演示文稿的编辑器,并具有以下功能:
|
||||
|
||||
* 查看,编辑和协同编辑 `.docx`、`.xlsx`、`.pptx` 文件。OOXML 作为一种核心格式,可确保与 Microsoft Word、Excel 和 PowerPoint 文件的高度兼容性。
|
||||
* 通过内部转换为 OOXML,编辑其他流行格式(`.odt`、`.rtf`、`.txt`、`.html`、`.ods`、`.csv`、`.odp`)。
|
||||
* 熟悉的选项卡式界面。
|
||||
* 协作工具:两种协同编辑模式(快速和严谨),跟踪更改,评论和集成聊天。
|
||||
* 灵活的访问权限管理:完全访问权限、只读、审阅、表单填写和评论。
|
||||
* 使用 API 构建附加组件。
|
||||
* 250 种可用语言和象形字母表。
|
||||
|
||||
通过 API,开发人员可以将 ONLYOFFICE 编辑器集成到网站和利用程序设计语言编写的应用程序中,并能配置和管理编辑器。
|
||||
|
||||
要集成 ONLYOFFICE 编辑器,我们需要一个集成应用程序来连接编辑器(ONLYOFFICE 文档服务器)和服务。 要在你的界面中使用编辑器,因该授予 ONLYOFFICE 以下权限:
|
||||
|
||||
* 添加并执行自定义代码。
|
||||
* 用于下载和保存文件的匿名访问权限。这意味着编辑器仅与服务器端的服务通信,而不包括客户端的任何用户授权数据(浏览器 cookies)。
|
||||
* 在用户界面添加新按钮(例如,“在 ONLYOFFICE 中打开”、“在 ONLYOFFICE 中编辑”)。
|
||||
* 开启一个新页面,ONLYOFFICE 可以在其中执行脚本以添加编辑器。
|
||||
* 能够指定文档服务器连接设置。
|
||||
|
||||
流行的协作解决方案的成功集成案例有很多,如 Nextcloud、ownCloud、Alfresco、Confluence 和 SharePoint,都是通过 ONLYOFFICE 提供的官方即用型连接器实现的。
|
||||
|
||||
实际的集成案例之一是 ONLYOFFICE 编辑器与以 C# 编写的开源协作平台的集成。该平台具有文档和项目管理、CRM、电子邮件聚合器、日历、用户数据库、博客、论坛、调查、Wiki 和即时通讯程序的功能。
|
||||
|
||||
将在线编辑器与 CRM 和项目模块集成,你可以:
|
||||
|
||||
* 文档关联到 CRM 时机和容器、项目任务和讨论,甚至创建一个单独的文件夹,其中包含与项目相关的文档、电子表格和演示文稿。
|
||||
* 直接在 CRM 或项目模块中创建新的文档、工作表和演示文稿。
|
||||
* 打开和编辑关联的文档,或者下载和删除。
|
||||
* 将联系人从 CSV 文件批量导入到 CRM 中,并将客户数据库导出为 CSV 文件。
|
||||
|
||||
在“邮件”模块中,你可以关联存储在“文档模块”中的文件,或者将指向所需文档的链接插入到邮件正文中。 当 ONLYOFFICE 用户收到带有附件的文档的消息时,他们可以:下载附件、在浏览器中查看文件、打开文件进行编辑或将其保存到“文档模块”。 如上所述,如果格式不同于 OOXML ,则文件将自动转换为 `.docx`、`.xlsx`、`.pptx`,并且其副本也将以原始格式保存。
|
||||
|
||||
在本文中,你将看到 ONLYOFFICE 与最流行的编程语言之一的 Python 编写的文档管理系统的集成过程。 以下步骤将向你展示如何创建所有必要的部分,以使在 DMS(<ruby>文档管理系统<rt>Document Management System</rt></ruby>)界面内的文档中可以进行协同工作成为可能:查看、编辑、协同编辑、保存文件和用户访问管理,并可以作为服务的示例集成到 Python 应用程序中。
|
||||
|
||||
### 1、前置需求
|
||||
|
||||
首先,创建集成过程的关键组件:[ONLYOFFICE 文档服务器][4] 和用 Python 编写的文件管理系统。
|
||||
|
||||
#### 1.1、ONLYOFFICE 文档服务器
|
||||
|
||||
要安装 ONLYOFFICE 文档服务器,你可以从多个安装选项中进行选择:编译 GitHub 上可用的源代码,使用 `.deb` 或 `.rpm` 软件包亦或 Docker 镜像。
|
||||
|
||||
我们推荐使用下面这条命令利用 Docker 映像安装文档服务器和所有必需的依赖。请注意,选择此方法,你需要安装最新的 Docker 版本。
|
||||
|
||||
```
|
||||
docker run -itd -p 80:80 onlyoffice/documentserver-de
|
||||
```
|
||||
|
||||
#### 1.2、利用 Python 开发 DMS
|
||||
|
||||
如果已经拥有一个,请检查它是否满足以下条件:
|
||||
|
||||
* 包含需要打开以查看/编辑的保留文件
|
||||
* 允许下载文件
|
||||
|
||||
对于该应用程序,我们将使用 Bottle 框架。我们将使用以下命令将其安装在工作目录中:
|
||||
|
||||
```
|
||||
pip install bottle
|
||||
```
|
||||
|
||||
然后我们创建应用程序代码 `main.py` 和模板 `index.tpl`。
|
||||
|
||||
我们将以下代码添加到 `main.py` 文件中:
|
||||
|
||||
```
|
||||
from bottle import route, run, template, get, static_file # connecting the framework and the necessary components
|
||||
@route('/') # setting up routing for requests for /
|
||||
def index():
|
||||
return template('index.tpl') # showing template in response to request
|
||||
|
||||
run(host="localhost", port=8080) # running the application on port 8080
|
||||
```
|
||||
|
||||
一旦我们运行该应用程序,点击 <http://localhost:8080> 就会在浏览器上呈现一个空白页面 。
|
||||
为了使文档服务器能够创建新文档,添加默认文件并在模板中生成其名称列表,我们应该创建一个文件夹 `files` 并将3种类型文件(`.docx`、`.xlsx` 和 `.pptx`)放入其中。
|
||||
|
||||
要读取这些文件的名称,我们使用 `listdir` 组件(模块):
|
||||
|
||||
```
|
||||
from os import listdir
|
||||
```
|
||||
|
||||
现在让我们为文件夹中的所有文件名创建一个变量:
|
||||
|
||||
```
|
||||
sample_files = [f for f in listdir('files')]
|
||||
```
|
||||
|
||||
要在模板中使用此变量,我们需要通过 `template` 方法传递它:
|
||||
|
||||
```
|
||||
def index():
|
||||
return template('index.tpl', sample_files=sample_files)
|
||||
```
|
||||
|
||||
这是模板中的这个变量:
|
||||
|
||||
```
|
||||
% for file in sample_files:
|
||||
<div>
|
||||
<span>{{file}}</span>
|
||||
</div>
|
||||
% end
|
||||
```
|
||||
|
||||
我们重新启动应用程序以查看页面上的文件名列表。
|
||||
|
||||
使这些文件可用于所有应用程序用户的方法如下:
|
||||
|
||||
```
|
||||
@get("/files/<filepath:re:.*\.*>")
|
||||
def show_sample_files(filepath):
|
||||
return static_file(filepath, root="files")
|
||||
```
|
||||
|
||||
### 2、查看文档
|
||||
|
||||
所有组件准备就绪后,让我们添加函数以使编辑者可以利用应用接口操作。
|
||||
|
||||
第一个选项使用户可以打开和查看文档。连接模板中的文档编辑器 API :
|
||||
|
||||
```
|
||||
<script type="text/javascript" src="editor_url/web-apps/apps/api/documents/api.js"></script>
|
||||
```
|
||||
|
||||
`editor_url` 是文档编辑器的链接接口。
|
||||
|
||||
打开每个文件以供查看的按钮:
|
||||
|
||||
```
|
||||
<button onclick="view('files/{{file}}')">view</button>
|
||||
```
|
||||
|
||||
现在我们需要添加带有 `id` 的 `div` 标签,打开文档编辑器:
|
||||
|
||||
```
|
||||
<div id="editor"></div>
|
||||
```
|
||||
|
||||
要打开编辑器,必须调用调用一个函数:
|
||||
|
||||
```
|
||||
<script>
|
||||
function view(filename) {
|
||||
if (/docx$/.exec(filename)) {
|
||||
filetype = "text"
|
||||
}
|
||||
if (/xlsx$/.exec(filename)) {
|
||||
filetype = "spreadsheet"
|
||||
}
|
||||
if (/pptx$/.exec(filename)) {
|
||||
filetype = "presentation",
|
||||
title: filename
|
||||
}
|
||||
|
||||
new DocsAPI.DocEditor("editor",
|
||||
{
|
||||
documentType: filetype,
|
||||
document: {
|
||||
url: "host_url" + '/' + filename,
|
||||
title: filename
|
||||
},
|
||||
editorConfig: {mode: 'view'}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
DocEditor 函数有两个参数:将在其中打开编辑器的元素 `id` 和带有编辑器设置的 `JSON`。
|
||||
在此示例中,使用了以下必需参数:
|
||||
|
||||
* `documentType` 由其格式标识(`.docx`、`.xlsx`、`.pptx` 用于相应的文本、电子表格和演示文稿)
|
||||
* `document.url` 是你要打开的文件链接。
|
||||
* `editorConfig.mode`。
|
||||
|
||||
我们还可以添加将在编辑器中显示的 `title`。
|
||||
|
||||
接下来,我们可以在 Python 应用程序中查看文档。
|
||||
|
||||
### 3、编辑文档
|
||||
|
||||
首先,添加 “Edit”(编辑)按钮:
|
||||
|
||||
```
|
||||
<button onclick="edit('files/{{file}}')">edit</button>
|
||||
```
|
||||
|
||||
然后创建一个新功能,打开文件进行编辑。类似于查看功能。
|
||||
|
||||
现在创建 3 个函数:
|
||||
|
||||
```
|
||||
<script>
|
||||
var editor;
|
||||
function view(filename) {
|
||||
if (editor) {
|
||||
editor.destroyEditor()
|
||||
}
|
||||
editor = new DocsAPI.DocEditor("editor",
|
||||
{
|
||||
documentType: get_file_type(filename),
|
||||
document: {
|
||||
url: "host_url" + '/' + filename,
|
||||
title: filename
|
||||
},
|
||||
editorConfig: {mode: 'view'}
|
||||
});
|
||||
}
|
||||
|
||||
function edit(filename) {
|
||||
if (editor) {
|
||||
editor.destroyEditor()
|
||||
}
|
||||
editor = new DocsAPI.DocEditor("editor",
|
||||
{
|
||||
documentType: get_file_type(filename),
|
||||
document: {
|
||||
url: "host_url" + '/' + filename,
|
||||
title: filename
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function get_file_type(filename) {
|
||||
if (/docx$/.exec(filename)) {
|
||||
return "text"
|
||||
}
|
||||
if (/xlsx$/.exec(filename)) {
|
||||
return "spreadsheet"
|
||||
}
|
||||
if (/pptx$/.exec(filename)) {
|
||||
return "presentation"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
`destroyEditor` 被调用以关闭一个打开的编辑器。
|
||||
|
||||
你可能会注意到,`edit()` 函数中缺少 `editorConfig` 参数,因为默认情况下它的值是:`{"mode":"edit"}`。
|
||||
|
||||
现在,我们拥有了打开文档以在 Python 应用程序中进行协同编辑的所有功能。
|
||||
|
||||
### 4、如何在 Python 应用中利用 ONLYOFFICE 协同编辑文档
|
||||
|
||||
通过在编辑器中设置对同一文档使用相同的 `document.key` 来实现协同编辑。 如果没有此键值,则每次打开文件时,编辑器都会创建编辑会话。
|
||||
|
||||
为每个文档设置唯一键,以使用户连接到同一编辑会话时进行协同编辑。 密钥格式应为以下格式:`filename +"_key"`。下一步是将其添加到当前文档的所有配置中。
|
||||
|
||||
```
|
||||
document: {
|
||||
url: "host_url" + '/' + filepath,
|
||||
title: filename,
|
||||
key: filename + '_key'
|
||||
},
|
||||
```
|
||||
|
||||
### 5、如何在 Python 应用中利用 ONLYOFFICE 保存文档
|
||||
|
||||
每次我们更改并保存文件时,ONLYOFFICE 都会存储其所有版本。 让我们仔细看看它是如何工作的。 关闭编辑器后,文档服务器将构建要保存的文件版本并将请求发送到 `callbackUrl` 地址。 该请求包含 `document.key`和指向刚刚构建的文件的链接。
|
||||
|
||||
`document.key` 用于查找文件的旧版本并将其替换为新版本。 由于这里没有任何数据库,因此仅使用 `callbackUrl` 发送文件名。
|
||||
|
||||
在 `editorConfig.callbackUrl` 的设置中指定 `callbackUrl` 参数并将其添加到 `edit()` 方法中:
|
||||
|
||||
```
|
||||
function edit(filename) {
|
||||
const filepath = 'files/' + filename;
|
||||
if (editor) {
|
||||
editor.destroyEditor()
|
||||
}
|
||||
editor = new DocsAPI.DocEditor("editor",
|
||||
{
|
||||
documentType: get_file_type(filepath),
|
||||
document: {
|
||||
url: "host_url" + '/' + filepath,
|
||||
title: filename,
|
||||
key: filename + '_key'
|
||||
}
|
||||
,
|
||||
editorConfig: {
|
||||
mode: 'edit',
|
||||
callbackUrl: "host_url" + '/callback' + '&filename=' + filename // add file name as a request parameter
|
||||
}
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
编写一种方法,在获取到 POST 请求发送到 `/callback` 地址后将保存文件:
|
||||
|
||||
```
|
||||
@post("/callback") # processing post requests for /callback
|
||||
def callback():
|
||||
if request.json['status'] == 2:
|
||||
file = requests.get(request.json['url']).content
|
||||
with open('files/' + request.query['filename'], 'wb') as f:
|
||||
f.write(file)
|
||||
return "{\"error\":0}"
|
||||
|
||||
```
|
||||
|
||||
`# status 2` 是已生成的文件,当我们关闭编辑器时,新版本的文件将保存到存储器中。
|
||||
|
||||
### 6、管理用户
|
||||
|
||||
如果应用中有用户,并且你需要查看谁在编辑文档,请在编辑器的配置中输入其标识符(`id`和`name`)。
|
||||
|
||||
在界面中添加选择用户的功能:
|
||||
|
||||
```
|
||||
<select id="user_selector" onchange="pick_user()">
|
||||
<option value="1" selected="selected">JD</option>
|
||||
<option value="2">Turk</option>
|
||||
<option value="3">Elliot</option>
|
||||
<option value="4">Carla</option>
|
||||
</select>
|
||||
```
|
||||
|
||||
如果在标记 `<script>` 的开头添加对函数 `pick_user()` 的调用,负责初始化函数自身 `id` 和 `name` 变量。
|
||||
|
||||
```
|
||||
function pick_user() {
|
||||
const user_selector = document.getElementById("user_selector");
|
||||
this.current_user_name = user_selector.options[user_selector.selectedIndex].text;
|
||||
this.current_user_id = user_selector.options[user_selector.selectedIndex].value;
|
||||
}
|
||||
```
|
||||
|
||||
使用 `editorConfig.user.id` 和 `editorConfig.user.name` 来配置用户设置。将这些参数添加到文件编辑函数中的编辑器配置中。
|
||||
|
||||
```
|
||||
function edit(filename) {
|
||||
const filepath = 'files/' + filename;
|
||||
if (editor) {
|
||||
editor.destroyEditor()
|
||||
}
|
||||
editor = new DocsAPI.DocEditor("editor",
|
||||
{
|
||||
documentType: get_file_type(filepath),
|
||||
document: {
|
||||
url: "host_url" + '/' + filepath,
|
||||
title: filename
|
||||
},
|
||||
editorConfig: {
|
||||
mode: 'edit',
|
||||
callbackUrl: "host_url" + '/callback' + '?filename=' + filename,
|
||||
user: {
|
||||
id: this.current_user_id,
|
||||
name: this.current_user_name
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
使用这种方法,你可以将 ONLYOFFICE 编辑器集成到用 Python 编写的应用程序中,并获得用于在文档上进行协同工作的所有必要工具。有关更多集成示例(Java、Node.js、PHP、Ruby),请参考官方的 [API 文档][5]。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensourceforu.com/2019/09/integrate-online-documents-editors-into-a-python-web-app-using-onlyoffice/
|
||||
|
||||
作者:[Aashima Sharma][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[stevenzdg988](https://github.com/stevenzdg988)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensourceforu.com/author/aashima-sharma/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://i1.wp.com/opensourceforu.com/wp-content/uploads/2016/09/Typist-composing-text-in-laptop.jpg?resize=696%2C420&ssl=1 (Typist composing text in laptop)
|
||||
[2]: https://i1.wp.com/opensourceforu.com/wp-content/uploads/2016/09/Typist-composing-text-in-laptop.jpg?fit=900%2C543&ssl=1
|
||||
[3]: https://www.onlyoffice.com/en/
|
||||
[4]: https://www.onlyoffice.com/en/developer-edition.aspx
|
||||
[5]: https://api.onlyoffice.com/editors/basic
|
53
published/20191010 The biggest risk to uptime- Your staff.md
Normal file
53
published/20191010 The biggest risk to uptime- Your staff.md
Normal file
@ -0,0 +1,53 @@
|
||||
[#]: collector: "lujun9972"
|
||||
[#]: translator: "sthwhl"
|
||||
[#]: reviewer: "wxy"
|
||||
[#]: publisher: "wxy"
|
||||
[#]: url: "https://linux.cn/article-13049-1.html"
|
||||
[#]: subject: "The biggest risk to uptime? Your staff"
|
||||
[#]: via: "https://www.networkworld.com/article/3444762/the-biggest-risk-to-uptime-your-staff.html"
|
||||
[#]: author: "Andy Patrizio https://www.networkworld.com/author/Andy-Patrizio/"
|
||||
|
||||
计算机正常运行最大的威胁是什么?是员工
|
||||
======
|
||||
|
||||
> 一项新研究发现,人为失误是引发停机时间的首要原因。你想象一下那是什么场景。
|
||||
|
||||
![](https://images.idgesg.net/images/article/2018/07/9_how-well-do-you-know-your-staff_head-in-sand-100765388-large.jpg)
|
||||
|
||||
之前有一个很老的笑话:“是人都会犯错,但是要真正把事情搞砸,你还缺台计算机。” 现在情况正好相反了,现如今,数据中心设备的可靠性已经得到了极大的提升,反而是使用设备的人员素质没能跟上,从而给计算机正常运行带来了很大的威胁。
|
||||
|
||||
<ruby>正常运行时间协会<rt>Uptime Institute</rt></ruby>对数千名 IT 专业人员一整年发生的故障事件进行了调查,得出结论表示绝大多数的数据中心故障是由于人为错误造成的,人为错误导致的故障率为 70%-75%。
|
||||
|
||||
而且有些故障很严重。调查发现,超过 30% 的 IT 服务与数据中心运营商经历了他们称之为是“严重服务退化”的停机事故。2019 年有 10% 的受访者称他们最近的事故造成的损失超过 100 万美元。
|
||||
|
||||
在正常运行时间协会在 2019 年 4 月的调查中,60% 的受访者认为,对于最近发生的重大停机事件,他们本可以通过更好的管理/流程或配置进行防止。而对于损失超过 100 万美元的故障事件,这一数字跃升至 74%。
|
||||
|
||||
正常运行时间协会认为,导致故障事件发生的最终的错误不一定是员工,而是令人失望的管理。
|
||||
|
||||
“这个行业仍然严重依赖于人工去完成一些最基础和最重要的工作,易受人为错误的影响,这一点无法避免,也许可做的防错/防灾措施很有限。”正常运行时间协会期刊的主编 Kevin Heslin 在一篇[博客文章][4]中写道。
|
||||
|
||||
“然而,对这些故障问题的快速调查发现,故障持续存在的主要原因不是人为失误,而是由于管理失误导致,如针对员工培训投资不足,相关政策执行不力,管理程序老旧,低估一名合格员工的重要性,这一系列的管理问题导致了故障停机。” Heslin 继续写道。
|
||||
|
||||
正常运行时间协会指出,公司的 IT 基础设施越复杂,特别是分布式特性基础设施,可能会越容易增加简单的错误层出不穷而导致业务中断的风险。同时指出公司需要意识到基础设施越复杂所涉及的风险就越大。
|
||||
|
||||
并警告说,在人员配备方面,不要以超过公司吸引和应用资源来管理基础设施的速度扩大关键 IT 能力,并在影响关键任务操作之前意识到任何人员和技能短缺。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.networkworld.com/article/3444762/the-biggest-risk-to-uptime-your-staff.html
|
||||
|
||||
作者:[Andy Patrizio][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[sthwhl](https://github.com/sthwhl)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://www.networkworld.com/author/Andy-Patrizio/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://www.networkworld.com/article/3223692/what-is-a-data-centerhow-its-changed-and-what-you-need-to-know.html
|
||||
[2]: https://www.networkworld.com/newsletters/signup.html
|
||||
[3]: https://www.networkworld.com/article/3440100/take-the-intelligent-route-with-consumption-based-storage.html?utm_source=IDG&utm_medium=promotions&utm_campaign=HPE20773&utm_content=sidebar " Take the Intelligent Route with Consumption-Based Storage"
|
||||
[4]: https://journal.uptimeinstitute.com/how-to-avoid-outages-try-harder/
|
||||
[5]: https://www.facebook.com/NetworkWorld/
|
||||
[6]: https://www.linkedin.com/company/network-world
|
@ -0,0 +1,71 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (stevenzdg988)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-13018-1.html)
|
||||
[#]: subject: (Top articles for learning Python in 2020)
|
||||
[#]: via: (https://opensource.com/article/19/12/learn-python)
|
||||
[#]: author: (Matthew Broberg https://opensource.com/users/mbbroberg)
|
||||
|
||||
学习 Python 的好文章
|
||||
======
|
||||
|
||||
> 无论你在 Python 编程过程中处于什么阶段,这些 Python 热门文章将会对你有很大帮助。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202101/15/231657xt8085wtyk5yvsz5.jpg)
|
||||
|
||||
2019 年是 Python 的好年景。根据 [GitHub][2] 和 [Stack Overflow][3] 的受欢迎资源程度来看,它正在成为全球第二大流行语言。(LCTT 译注:原文发表于 2019 年底,但是这里提及的文章并没有过时。)
|
||||
|
||||
> “在我们的调查中,Python 作为增长最快的程序设计语言,在程序设计语言中排名再次上升,今年排在 Java 之前,成为第二大最受欢迎的程序设计语言(仅次于 Rust )。”
|
||||
>
|
||||
> — [Stack Overflow Insights][3]
|
||||
|
||||
同样,Python 的读者人数呈跳跃式激增。以下是按主题分组的 2019 年以来最热门的 Python 文章,供你仔细阅读。
|
||||
|
||||
### 为什么选择 Python ?
|
||||
|
||||
在众多的程序设计语言中,是什么使 Python 成为首选呢?从文章的阅读量来看,那就是因为它的灵活性。正如 Jigyasa Grover 解释的那样,Python 开发人员可以使用 [多种范例][4],包括 Seth Kenlon 教程所展示的流行的 [面向对象程序设计][5]。
|
||||
|
||||
如果你是 Python 的长期用户,并且正在寻找 Python 为什么是完美的程序设计语言的高级例子,那么可以看 Moshe Zadka 的 [喜欢 Python 的 5 大理由][6]。如果这还不够的话,你也可以使用功能强大的工具来尝试,无需编写大量代码,例如 Parul Pandey 关于 [图像处理][7] 的教程。
|
||||
|
||||
### 配置 Python
|
||||
|
||||
随着 Python 的受欢迎程度不断提高,使用它的人越来越多。这些新手中的许多人都是在 Mac 操作系统上进行的,并且正在使用 Moshe 和我写的 [Python3 配置向导][8]。
|
||||
|
||||
安装 Python 之后,接下来就是决定利用什么工具编写代码。关于文本编辑器和集成开发环境(IDE),有很多选择,但是读者似乎更喜欢图形界面,在有关该主题的文章中,Stephan Avenwedde 的关于 [Pythonic][9] 和我关于 [JupyterLab][10] 的文章的读者最多。
|
||||
|
||||
在对程序设计语言充满信心的途径上,开发人员将不得不面对众多选择,来管理程序设计语言的版本和项目依赖。幸运的是,László Kiss Kollár 的文章 [Python 包管理][11] 让其变得更加容易。
|
||||
|
||||
当你准备好配置一个具有所有功能的 IDE,以最大限度地利用这门语言时,请一定尝试一下 [linter Black][12],如 Moshe 说的,保持代码的清洁。
|
||||
|
||||
### 小结
|
||||
|
||||
无论你处在 Python 程序设计的哪个阶段,这些热门 Python 文章都将为你提供帮助。如果没有至少一次对测试重要性的认可,我无法对此进行总结,为此,Moshe 提供了另一篇 [关于 tox][13] 的好文章。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/19/12/learn-python
|
||||
|
||||
作者:[Matthew Broberg][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[stevenzdg988](https://github.com/stevenzdg988)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/mbbroberg
|
||||
[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://octoverse.github.com/#top-languages
|
||||
[3]: https://insights.stackoverflow.com/survey/2019
|
||||
[4]: https://opensource.com/article/19/10/python-programming-paradigms
|
||||
[5]: https://opensource.com/article/19/7/get-modular-python-classes
|
||||
[6]: https://opensource.com/article/19/10/why-love-python
|
||||
[7]: https://linux.cn/article-10679-1.html
|
||||
[8]: https://opensource.com/article/19/5/python-3-default-mac
|
||||
[9]: https://opensource.com/article/19/5/graphically-programming-pythonic
|
||||
[10]: https://opensource.com/article/19/5/jupyterlab-python-developers-magic
|
||||
[11]: https://opensource.com/article/19/4/managing-python-packages
|
||||
[12]: https://linux.cn/article-10864-1.html
|
||||
[13]: https://opensource.com/article/19/5/python-tox
|
||||
[14]: https://opensource.com/how-submit-article
|
@ -0,0 +1,453 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (stevenzdg988)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-13047-1.html)
|
||||
[#]: subject: (A beginner's guide to web scraping with Python)
|
||||
[#]: via: (https://opensource.com/article/20/5/web-scraping-python)
|
||||
[#]: author: (Julia Piaskowski https://opensource.com/users/julia-piaskowski)
|
||||
|
||||
利用 Python 爬取网站的新手指南
|
||||
======
|
||||
|
||||
> 通过基本的 Python 工具获得爬取完整 HTML 网站的实践经验。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202101/24/093527skakhvc3kalnuxa1.jpg)
|
||||
|
||||
有很多很棒的书可以帮助你学习 Python ,但是谁真正读了这那些大部头呢?(剧透:反正不是我)。
|
||||
|
||||
许多人觉得教学书籍很有用,但我通常不会从头到尾地阅读一本书来学习。我是通过做一个项目,努力的弄清楚一些内容,然后再读另一本书来学习。因此,暂时丢掉书,让我们一起学习 Python。
|
||||
|
||||
接下来是我的第一个 Python 爬取项目的指南。它对 Python 和 HTML 的假定知识要求很低。这篇文章旨在说明如何使用 Python 的 [requests][2] 库访问网页内容,并使用 [BeatifulSoup4][3] 库以及 JSON 和 [pandas][4] 库解析网页内容。我将简要介绍 [Selenium][5] 库,但我不会深入研究如何使用该库——这个主题值得有自己的教程。最终,我希望向你展示一些技巧和小窍门,以减少网页爬取过程中遇到的问题。
|
||||
|
||||
### 安装依赖
|
||||
|
||||
我的 [GitHub 存储库][6] 中提供了本指南的所有资源。如果需要安装 Python3 的帮助,请查看 [Linux][7]、[Windows][8] 和 [Mac][9] 的教程。
|
||||
|
||||
```
|
||||
$ python3 -m venv
|
||||
$ source venv/bin/activate
|
||||
$ pip install requests bs4 pandas
|
||||
```
|
||||
|
||||
如果你喜欢使用 JupyterLab ,则可以使用 [notebook][10] 运行所有代码。[安装 JupyterLab][11] 有很多方法,这是其中一种:
|
||||
|
||||
```
|
||||
# from the same virtual environment as above, run:
|
||||
$ pip install jupyterlab
|
||||
```
|
||||
|
||||
### 为网站抓取项目设定目标
|
||||
|
||||
现在我们已经安装了依赖项,但是爬取网页需要做什么?
|
||||
|
||||
让我们退一步,确保使目标清晰。下面是成功完成网页爬取项目需求列表:
|
||||
|
||||
* 我们收集的信息,是值得我们花大力气去建立一个有效的网页爬取器的。
|
||||
* 我们所下载的信息是可以通过网页爬取器合法和道德地收集的。
|
||||
* 对如何在 HTML 代码中找到目标信息有一定的了解。
|
||||
* 利用恰当的工具:在此情况下,需要使用 BeautifulSoup 库和 requests 库。
|
||||
* 知道(或愿意去学习)如何解析 JSON 对象。
|
||||
* 有足够的 pandas 数据处理技能。
|
||||
|
||||
关于 HTML 的备注:HTML 是运行在互联网上的“猛兽”,但我们最需要了解的是标签的工作方式。标签是一对由尖括号包围关键词(一般成对出现,其内容在两个标签中间)。比如,这是一个假装的标签,称为 `pro-tip`:
|
||||
|
||||
```
|
||||
<pro-tip> All you need to know about html is how tags work </pro-tip>
|
||||
```
|
||||
|
||||
我们可以通过调用标签 `pro-tip` 来访问其中的信息(`All you need to know…`)。本教程将进一步介绍如何查找和访问标签。要进一步了解 HTML 基础知识,请查看 [本文][12]。
|
||||
|
||||
### 网站爬取项目中要找的是什么
|
||||
|
||||
有些数据利用网站爬取采集比利用其他方法更合适。以下是我认为合适项目的准则:
|
||||
|
||||
没有可用于数据(处理)的公共 API。通过 API 抓取结构化数据会容易得多,(所以没有 API )有助于澄清收集数据的合法性和道德性。而有相当数量的结构化数据,并有规律的、可重复的格式,才能证明这种努力的合理性。网页爬取可能会很痛苦。BeautifulSoup(bs4)使操作更容易,但无法避免网站的个别特殊性,需要进行定制。数据的相同格式化不是必须的,但这确实使事情变得更容易。存在的 “边际案例”(偏离规范)越多,爬取就越复杂。
|
||||
|
||||
免责声明:我没有参加过法律培训;以下内容无意作为正式的法律建议。
|
||||
|
||||
关于合法性,访问大量有价值信息可能令人兴奋,但仅仅因为它是可能的,并不意味着应该这样做。
|
||||
|
||||
值得庆幸的是,有一些公共信息可以指导我们的道德规范和网页爬取工具。大多数网站都有与该网站关联的 [robots.txt][13] 文件,指出允许哪些爬取活动,哪些不被允许。它主要用于与搜索引擎(网页抓取工具的终极形态)进行交互。然而,网站上的许多信息都被视为公共信息。因此,有人将 `robots.txt` 文件视为一组建议,而不是具有法律约束力的文档。 `robots.txt` 文件并不涉及数据的道德收集和使用等主题。
|
||||
|
||||
在开始爬取项目之前,问自己以下问题:
|
||||
|
||||
* 我是否在爬取版权材料?
|
||||
* 我的爬取活动会危害个人隐私吗?
|
||||
* 我是否发送了大量可能会使服务器超载或损坏的请求?
|
||||
* 爬取是否会泄露出我不拥有的知识产权?
|
||||
* 是否有规范网站使用的服务条款,我是否遵循了这些条款?
|
||||
* 我的爬取活动会减少原始数据的价值吗?(例如,我是否打算按原样重新打包数据,或者可能从原始来源中抽取网站流量)?
|
||||
|
||||
当我爬取一个网站时,请确保可以对所有这些问题回答 “否”。
|
||||
|
||||
要深入了解这些法律问题,请参阅 2018 年出版的 Krotov 和 Silva 撰写的[《Web 爬取的合法性和道德性》][14] 和 Sellars 的[《二十年 Web 爬取和计算机欺诈与滥用法案》][15]。
|
||||
|
||||
### 现在开始爬取网站
|
||||
|
||||
经过上述评估,我想出了一个项目。我的目标是爬取爱达荷州所有 Family Dollar 商店的地址。 这些商店在农村地区规模很大,因此我想了解有多少家这样的商店。
|
||||
|
||||
起点是 [Family Dollar 的位置页面][16]
|
||||
|
||||
![爱达荷州 Family Dollar 所在地页面][17]
|
||||
|
||||
首先,让我们在 Python 虚拟环境中加载先决条件。此处的代码将被添加到一个 Python 文件(如果你想要个名称,则为 `scraper.py`)或在 JupyterLab 的单元格中运行。
|
||||
|
||||
```
|
||||
import requests # for making standard html requests
|
||||
from bs4 import BeautifulSoup # magical tool for parsing html data
|
||||
import json # for parsing data
|
||||
from pandas import DataFrame as df # premier library for data organization
|
||||
```
|
||||
|
||||
接下来,我们从目标 URL 中请求数据。
|
||||
|
||||
```
|
||||
page = requests.get("https://locations.familydollar.com/id/")
|
||||
soup = BeautifulSoup(page.text, 'html.parser')
|
||||
```
|
||||
|
||||
BeautifulSoup 将 HTML 或 XML 内容转换为复杂树对象。这是我们将使用的几种常见对象类型。
|
||||
|
||||
* `BeautifulSoup` —— 解析的内容
|
||||
* `Tag` —— 标准 HTML 标记,这是你将遇到的 `bs4` 元素的主要类型
|
||||
* `NavigableString` —— 标签内的文本字符串
|
||||
* `Comment` —— NavigableString 的一种特殊类型
|
||||
|
||||
当我们查看 `requests.get()` 输出时,还有更多要考虑的问题。我仅使用 `page.text()` 将请求的页面转换为可读的内容,但是还有其他输出类型:
|
||||
|
||||
* `page.text()` 文本(最常见)
|
||||
* `page.content()` 逐字节输出
|
||||
* `page.json()` JSON 对象
|
||||
* `page.raw()` 原始套接字响应(对你没啥用)
|
||||
|
||||
我只在使用拉丁字母的纯英语网站上操作。 `requests` 中的默认编码设置可以很好地解决这一问题。然而,除了纯英语网站之外,就是更大的互联网世界。为了确保 `requests` 正确解析内容,你可以设置文本的编码:
|
||||
|
||||
```
|
||||
page = requests.get(URL)
|
||||
page.encoding = 'ISO-885901'
|
||||
soup = BeautifulSoup(page.text, 'html.parser')
|
||||
```
|
||||
|
||||
仔细研究 `BeautifulSoup` 标签,我们看到:
|
||||
|
||||
* `bs4` 元素 `tag` 捕获的是一个 HTML 标记。
|
||||
* 它具有名称和属性,可以像字典一样访问:`tag['someAttribute']`。
|
||||
* 如果标签具有相同名称的多个属性,则仅访问第一个实例。
|
||||
* 可通过 `tag.contents` 访问子标签。
|
||||
* 所有标签后代都可以通过 `tag.contents` 访问。
|
||||
* 你始终可以使用以下字符串:`re.compile("your_string")` 访问一个字符串的所有内容,而不是浏览 HTML 树。
|
||||
|
||||
### 确定如何提取相应内容
|
||||
|
||||
警告:此过程可能令人沮丧。
|
||||
|
||||
网站爬取过程中的提取可能是一个令人生畏的充满了误区的过程。我认为解决此问题的最佳方法是从一个有代表性的示例开始然后进行扩展(此原理对于任何编程任务都是适用的)。查看页面的 HTML 源代码至关重要。有很多方法可以做到这一点。
|
||||
|
||||
你可以在终端中使用 Python 查看页面的整个源代码(不建议使用)。运行此代码需要你自担风险:
|
||||
|
||||
```
|
||||
print(soup.prettify())
|
||||
```
|
||||
|
||||
虽然打印出页面的整个源代码可能适用于某些教程中显示的玩具示例,但大多数现代网站的页面上都有大量内容。甚至 404 页面也可能充满了页眉、页脚等代码。
|
||||
|
||||
通常,在你喜欢的浏览器中通过 “查看页面源代码” 来浏览源代码是最容易的(单击右键,然后选择 “查看页面源代码” )。这是找到目标内容的最可靠方法(稍后我将解释原因)。
|
||||
|
||||
![Family Dollar 页面源代码][18]
|
||||
|
||||
在这种情况下,我需要在这个巨大的 HTML 海洋中找到我的目标内容 —— 地址、城市、州和邮政编码。通常,对页面源(`ctrl+F`)的简单搜索就会得到目标位置所在的位置。一旦我实际看到目标内容的示例(至少一个商店的地址),便会找到将该内容与其他内容区分开的属性或标签。
|
||||
|
||||
首先,我需要在爱达荷州 Family Dollar 商店中收集不同城市的网址,并访问这些网站以获取地址信息。这些网址似乎都包含在 `href` 标记中。太棒了!我将尝试使用 `find_all` 命令进行搜索:
|
||||
|
||||
```
|
||||
dollar_tree_list = soup.find_all('href')
|
||||
dollar_tree_list
|
||||
```
|
||||
|
||||
搜索 `href` 不会产生任何结果,该死。这可能是因为 `href` 嵌套在 `itemlist` 类中而失败。对于下一次尝试,请搜索 `item_list`。由于 `class` 是 Python 中的保留字,因此使用 `class_` 来作为替代。`soup.find_all()` 原来是 `bs4` 函数的瑞士军刀。
|
||||
|
||||
```
|
||||
dollar_tree_list = soup.find_all(class_ = 'itemlist')
|
||||
for i in dollar_tree_list[:2]:
|
||||
print(i)
|
||||
```
|
||||
|
||||
有趣的是,我发现搜索一个特定类的方法一般是一种成功的方法。通过找出对象的类型和长度,我们可以了解更多有关对象的信息。
|
||||
|
||||
```
|
||||
type(dollar_tree_list)
|
||||
len(dollar_tree_list)
|
||||
```
|
||||
|
||||
可以使用 `.contents` 从 BeautifulSoup “结果集” 中提取内容。这也是创建单个代表性示例的好时机。
|
||||
|
||||
```
|
||||
example = dollar_tree_list[2] # a representative example
|
||||
example_content = example.contents
|
||||
print(example_content)
|
||||
```
|
||||
|
||||
使用 `.attr` 查找该对象内容中存在的属性。注意:`.contents` 通常会返回一个项目的精确的列表,因此第一步是使用方括号符号为该项目建立索引。
|
||||
|
||||
```
|
||||
example_content = example.contents[0]
|
||||
example_content.attrs
|
||||
```
|
||||
|
||||
现在,我可以看到 `href` 是一个属性,可以像字典项一样提取它:
|
||||
|
||||
```
|
||||
example_href = example_content['href']
|
||||
print(example_href)
|
||||
```
|
||||
|
||||
### 整合网站抓取工具
|
||||
|
||||
所有的这些探索为我们提供了前进的路径。这是厘清上面逻辑的一个清理版本。
|
||||
|
||||
```
|
||||
city_hrefs = [] # initialise empty list
|
||||
|
||||
for i in dollar_tree_list:
|
||||
cont = i.contents[0]
|
||||
href = cont['href']
|
||||
city_hrefs.append(href)
|
||||
|
||||
# check to be sure all went well
|
||||
for i in city_hrefs[:2]:
|
||||
print(i)
|
||||
```
|
||||
|
||||
输出的内容是一个关于抓取爱达荷州 Family Dollar 商店 URL 的列表。
|
||||
|
||||
也就是说,我仍然没有获得地址信息!现在,需要抓取每个城市的 URL 以获得此信息。因此,我们使用一个具有代表性的示例重新开始该过程。
|
||||
|
||||
```
|
||||
page2 = requests.get(city_hrefs[2]) # again establish a representative example
|
||||
soup2 = BeautifulSoup(page2.text, 'html.parser')
|
||||
```
|
||||
|
||||
![Family Dollar 地图和代码][19]
|
||||
|
||||
地址信息嵌套在 `type="application/ld+json"` 里。经过大量的地理位置抓取之后,我开始认识到这是用于存储地址信息的一般结构。幸运的是,`soup.find_all()` 开启了利用 `type` 搜索。
|
||||
|
||||
```
|
||||
arco = soup2.find_all(type="application/ld+json")
|
||||
print(arco[1])
|
||||
```
|
||||
|
||||
地址信息在第二个列表成员中!原来如此!
|
||||
|
||||
使用 `.contents` 提取(从第二个列表项中)内容(这是过滤后的合适的默认操作)。同样,由于输出的内容是一个列表,因此我为该列表项建立了索引:
|
||||
|
||||
```
|
||||
arco_contents = arco[1].contents[0]
|
||||
arco_contents
|
||||
```
|
||||
|
||||
喔,看起来不错。此处提供的格式与 JSON 格式一致(而且,该类型的名称中确实包含 “json”)。 JSON 对象的行为就像是带有嵌套字典的字典。一旦你熟悉利用其去工作,它实际上是一种不错的格式(当然,它比一长串正则表达式命令更容易编程)。尽管从结构上看起来像一个 JSON 对象,但它仍然是 `bs4` 对象,需要通过编程方式转换为 JSON 对象才能对其进行访问:
|
||||
|
||||
```
|
||||
arco_json = json.loads(arco_contents)
|
||||
```
|
||||
|
||||
```
|
||||
type(arco_json)
|
||||
print(arco_json)
|
||||
```
|
||||
|
||||
在该内容中,有一个被调用的 `address` 键,该键要求地址信息在一个比较小的嵌套字典里。可以这样检索:
|
||||
|
||||
```
|
||||
arco_address = arco_json['address']
|
||||
arco_address
|
||||
```
|
||||
|
||||
好吧,请大家注意。现在我可以遍历存储爱达荷州 URL 的列表:
|
||||
|
||||
```
|
||||
locs_dict = [] # initialise empty list
|
||||
|
||||
for link in city_hrefs:
|
||||
locpage = requests.get(link) # request page info
|
||||
locsoup = BeautifulSoup(locpage.text, 'html.parser')
|
||||
# parse the page's content
|
||||
locinfo = locsoup.find_all(type="application/ld+json")
|
||||
# extract specific element
|
||||
loccont = locinfo[1].contents[0]
|
||||
# get contents from the bs4 element set
|
||||
locjson = json.loads(loccont) # convert to json
|
||||
locaddr = locjson['address'] # get address
|
||||
locs_dict.append(locaddr) # add address to list
|
||||
```
|
||||
|
||||
### 用 Pandas 整理我们的网站抓取结果
|
||||
|
||||
我们在字典中装载了大量数据,但是还有一些额外的无用项,它们会使重用数据变得比需要的更为复杂。要执行最终的数据组织,我们需要将其转换为 Pandas 数据框架,删除不需要的列 `@type` 和 `country`,并检查前五行以确保一切正常。
|
||||
|
||||
```
|
||||
locs_df = df.from_records(locs_dict)
|
||||
locs_df.drop(['@type', 'addressCountry'], axis = 1, inplace = True)
|
||||
locs_df.head(n = 5)
|
||||
```
|
||||
|
||||
确保保存结果!!
|
||||
|
||||
```
|
||||
df.to_csv(locs_df, "family_dollar_ID_locations.csv", sep = ",", index = False)
|
||||
```
|
||||
|
||||
我们做到了!所有爱达荷州 Family Dollar 商店都有一个用逗号分隔的列表。多令人兴奋。
|
||||
|
||||
### Selenium 和数据抓取的一点说明
|
||||
|
||||
[Selenium][5] 是用于与网页自动交互的常用工具。为了解释为什么有时必须使用它,让我们来看一个使用 Walgreens 网站的示例。 “检查元素” 提供了浏览器显示内容的代码:
|
||||
|
||||
![Walgreens 位置页面和代码][20]
|
||||
|
||||
虽然 “查看页面源代码” 提供了有关 `requests` 将获得什么内容的代码:
|
||||
|
||||
![Walgreens 源代码][21]
|
||||
|
||||
如果这两个不一致,是有一些插件可以修改源代码 —— 因此,应在将页面加载到浏览器后对其进行访问。`requests` 不能做到这一点,但是 Selenium 可以做到。
|
||||
|
||||
Selenium 需要 Web 驱动程序来检索内容。实际上,它会打开 Web 浏览器,并收集此页面的内容。Selenium 功能强大 —— 它可以通过多种方式与加载的内容进行交互(请阅读文档)。使用 Selenium 获取数据后,继续像以前一样使用 BeautifulSoup:
|
||||
|
||||
```
|
||||
url = "https://www.walgreens.com/storelistings/storesbycity.jsp?requestType=locator&state=ID"
|
||||
driver = webdriver.Firefox(executable_path = 'mypath/geckodriver.exe')
|
||||
driver.get(url)
|
||||
soup_ID = BeautifulSoup(driver.page_source, 'html.parser')
|
||||
store_link_soup = soup_ID.find_all(class_ = 'col-xl-4 col-lg-4 col-md-4')
|
||||
```
|
||||
|
||||
对于 Family Dollar 这种情形,我不需要 Selenium,但是当呈现的内容与源代码不同时,我确实会保留使用 Selenium。
|
||||
|
||||
### 小结
|
||||
|
||||
总之,使用网站抓取来完成有意义的任务时:
|
||||
|
||||
* 耐心一点
|
||||
* 查阅手册(它们非常有帮助)
|
||||
|
||||
如果你对答案感到好奇:
|
||||
|
||||
![Family Dollar 位置图][23]
|
||||
|
||||
美国有很多 Family Dollar 商店。
|
||||
|
||||
完整的源代码是:
|
||||
|
||||
```
|
||||
import requests
|
||||
from bs4 import BeautifulSoup
|
||||
import json
|
||||
from pandas import DataFrame as df
|
||||
|
||||
page = requests.get("https://www.familydollar.com/locations/")
|
||||
soup = BeautifulSoup(page.text, 'html.parser')
|
||||
|
||||
# find all state links
|
||||
state_list = soup.find_all(class_ = 'itemlist')
|
||||
|
||||
state_links = []
|
||||
|
||||
for i in state_list:
|
||||
cont = i.contents[0]
|
||||
attr = cont.attrs
|
||||
hrefs = attr['href']
|
||||
state_links.append(hrefs)
|
||||
|
||||
# find all city links
|
||||
city_links = []
|
||||
|
||||
for link in state_links:
|
||||
page = requests.get(link)
|
||||
soup = BeautifulSoup(page.text, 'html.parser')
|
||||
familydollar_list = soup.find_all(class_ = 'itemlist')
|
||||
for store in familydollar_list:
|
||||
cont = store.contents[0]
|
||||
attr = cont.attrs
|
||||
city_hrefs = attr['href']
|
||||
city_links.append(city_hrefs)
|
||||
# to get individual store links
|
||||
store_links = []
|
||||
|
||||
for link in city_links:
|
||||
locpage = requests.get(link)
|
||||
locsoup = BeautifulSoup(locpage.text, 'html.parser')
|
||||
locinfo = locsoup.find_all(type="application/ld+json")
|
||||
for i in locinfo:
|
||||
loccont = i.contents[0]
|
||||
locjson = json.loads(loccont)
|
||||
try:
|
||||
store_url = locjson['url']
|
||||
store_links.append(store_url)
|
||||
except:
|
||||
pass
|
||||
|
||||
# get address and geolocation information
|
||||
stores = []
|
||||
|
||||
for store in store_links:
|
||||
storepage = requests.get(store)
|
||||
storesoup = BeautifulSoup(storepage.text, 'html.parser')
|
||||
storeinfo = storesoup.find_all(type="application/ld+json")
|
||||
for i in storeinfo:
|
||||
storecont = i.contents[0]
|
||||
storejson = json.loads(storecont)
|
||||
try:
|
||||
store_addr = storejson['address']
|
||||
store_addr.update(storejson['geo'])
|
||||
stores.append(store_addr)
|
||||
except:
|
||||
pass
|
||||
|
||||
# final data parsing
|
||||
stores_df = df.from_records(stores)
|
||||
stores_df.drop(['@type', 'addressCountry'], axis = 1, inplace = True)
|
||||
stores_df['Store'] = "Family Dollar"
|
||||
|
||||
df.to_csv(stores_df, "family_dollar_locations.csv", sep = ",", index = False)
|
||||
```
|
||||
|
||||
作者注释:本文改编自 2020 年 2 月 9 日在俄勒冈州波特兰的[我在 PyCascades 的演讲][24]。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/5/web-scraping-python
|
||||
|
||||
作者:[Julia Piaskowski][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[stevenzdg988](https://github.com/stevenzdg988)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/julia-piaskowski
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/bus_html_code.png?itok=VjUmGsnl (HTML code)
|
||||
[2]: https://requests.readthedocs.io/en/master/
|
||||
[3]: https://beautiful-soup-4.readthedocs.io/en/latest/
|
||||
[4]: https://pandas.pydata.org/
|
||||
[5]: https://www.selenium.dev/
|
||||
[6]: https://github.com/jpiaskowski/pycas2020_web_scraping
|
||||
[7]: https://opensource.com/article/20/4/install-python-linux
|
||||
[8]: https://opensource.com/article/19/8/how-install-python-windows
|
||||
[9]: https://opensource.com/article/19/5/python-3-default-mac
|
||||
[10]: https://github.com/jpiaskowski/pycas2020_web_scraping/blob/master/example/Familydollar_location_scrape-all-states.ipynb
|
||||
[11]: https://jupyterlab.readthedocs.io/en/stable/getting_started/installation.html
|
||||
[12]: https://opensource.com/article/20/4/build-websites
|
||||
[13]: https://www.contentkingapp.com/academy/robotstxt/
|
||||
[14]: https://www.researchgate.net/publication/324907302_Legality_and_Ethics_of_Web_Scraping
|
||||
[15]: https://papers.ssrn.com/sol3/papers.cfm?abstract_id=3221625
|
||||
[16]: https://locations.familydollar.com/id/
|
||||
[17]: https://opensource.com/sites/default/files/uploads/familydollar1.png (Family Dollar Idaho locations page)
|
||||
[18]: https://opensource.com/sites/default/files/uploads/familydollar2.png (Family Dollar page source code)
|
||||
[19]: https://opensource.com/sites/default/files/uploads/familydollar3.png (Family Dollar map and code)
|
||||
[20]: https://opensource.com/sites/default/files/uploads/walgreens1.png (Walgreens location page and code)
|
||||
[21]: https://opensource.com/sites/default/files/uploads/walgreens2.png (Walgreens source code)
|
||||
[22]: https://www.walgreens.com/storelistings/storesbycity.jsp?requestType=locator\&state=ID
|
||||
[23]: https://opensource.com/sites/default/files/uploads/family_dollar_locations.png (Family Dollar locations map)
|
||||
[24]: https://2020.pycascades.com/talks/adventures-in-babysitting-webscraping-for-python-and-html-novices/
|
@ -0,0 +1,74 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (wxy)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-12999-1.html)
|
||||
[#]: subject: (A minimalist Mac terminal for Linux fans)
|
||||
[#]: via: (https://opensource.com/article/20/6/iterm2-mac)
|
||||
[#]: author: (Lisa Seelye https://opensource.com/users/lisa)
|
||||
|
||||
为 Linux 爱好者打造的极简 Mac 终端
|
||||
======
|
||||
|
||||
> 以下是我如何通过很多微妙复杂的方式来保持终端的简单和我的点文件的安全。
|
||||
|
||||
![咖啡和笔记本][1]
|
||||
|
||||
我要向大家坦白。我成为 Mac 用户已经有 10 多年了。起初,鉴于我强大的 Linux 背景,我觉得有点惭愧,但 Mac 给了我一个类似 Unix 的 Shell 和一个伟大的窗口管理器。因为这段历史,我有一个合二为一的功能,它运行在 macOS 上,但又为 Linux 用户所熟悉。没有理由它不能移植到 Linux 上(而且它已经移植了!)。
|
||||
|
||||
### 在 Mac 上使用 iTerm2
|
||||
|
||||
很长时间以来,我首选的终端是基本的内置 Term.app,但我最近改用了 [iTerm2][2],因为它有更好的自定义和配置文件支持。对我来说,它的一个主要优点是可以轻松地在 Mac 之间移植配置。对于日常使用,我更喜欢 Solarized Dark 主题;但对于演示文稿,我有一个单独的配置文件,可以放大文本,并使用色彩更鲜艳的纯黑色背景。
|
||||
|
||||
要使 iTerm2 可用,我首先要做的是配置 `Ctrl+Left` 和 `Ctrl+Right` 箭头,使其尊重经典的终端行为,即跳转到单词边界的开始和结束。要做到这一点,请导航到 “Preferences > Profiles > Your Profile > Keys” 并输入以下内容:
|
||||
|
||||
* 键盘快捷键:`^←`
|
||||
* 行动:发送 Escape 序列
|
||||
* Esc+:`b`
|
||||
|
||||
然后是另一个:
|
||||
|
||||
* 键盘快捷键:`^→`
|
||||
* 行动:发送 Escape 序列
|
||||
* Esc+:`f`
|
||||
|
||||
了解更多关于 [iTerm2][3] 的内容,享受自定义体验。
|
||||
|
||||
### 一个简单的命令提示符
|
||||
|
||||
我是那种无聊的终端提示符用户。我不想在其中包含 Git 目录或退出代码,我也只用单行提示符。我唯一使用的花哨组件是 [kubectx][4] ,它包括当前的 Kubernetes 上下文。作为一位 [OpenShift Dedicated][5] 的站点可靠性工程师(SRE),我必须在运行命令时有相应的上下文,而 `kubectx` 让我在打字时很容易知道自己在哪里。所以,我的 Bash PS1 就是无聊的 `username@host cwd $`,免除了 Kubernetes 上下文前缀。(LCTT 译注:如果想将 Kubernetes 上下文和名字空间显示在 PS1,可以看看 [kube-ps1](https://github.com/jonmosco/kube-ps1)。)
|
||||
|
||||
毫无疑问,与我见过的一些花哨的终端相比,我是偏向于极简的。有些人喜欢透明背景,有些人则喜欢他们的提示符上有很多信息 —— 从时间到退出代码以及其他一切。我觉得这些在我的终端上会让人分心,所以我很喜欢远离的那些设置。
|
||||
|
||||
### 精美复杂的点文件
|
||||
|
||||
与我的极简主义终端相比,很容易看出我在哪里投入了最大的努力:部署我的[点文件][6],包括我的 `.bash_profile` 和我的整体 Mac 设置。
|
||||
|
||||
我使用通过 GitHub 托管的 [一系列 Makefile][7] 来管理我的 Mac 设置。这将会拉取我的[点文件专用部署机制][8],它也在 GitHub 上。你要问为什么要围绕安全做这些工具?IT 专业人士和业余爱好者都需要一种强大的方式来将安全的数据片段放在新系统上。也许你想要你的 SSH 配置是隐藏的,或者你通过第三方系统部署凭证。我发现把我的安全数据和其他一切数据放在一起是很有用的,我用 [Ansible Vault][9] 解决了这个问题。我所有的机密信息都存储在 Git 中,用 Ansible Vault 加密。解密是用 Makefile 处理的。
|
||||
|
||||
无论是第一次安装还是更新现有的点文件,我(当然)都必须有 Ansible Vault,为了避免到处安装,我把它放在一个用 Docker 运行的容器里,这样我就到处都安装好了。我把解密口令放到一个文件中, `run make`,然后用 `make clean` 清理一切。你可以通过[探索这些点文件][8]来了解更多)。
|
||||
|
||||
我想说的是,这种管理方案可能过于夸张,而有些人喜欢复杂的终端提示。所以,也许在权衡之下,一切都会变得平衡。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/6/iterm2-mac
|
||||
|
||||
作者:[Lisa Seelye][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/lisa
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/coffee_cafe_brew_laptop_desktop.jpg?itok=G-n1o1-o (Coffee and laptop)
|
||||
[2]: https://www.iterm2.com/
|
||||
[3]: https://www.iterm2.com/documentation.html
|
||||
[4]: https://github.com/ahmetb/kubectx
|
||||
[5]: https://www.openshift.com/products/dedicated/
|
||||
[6]: https://opensource.com/article/19/3/move-your-dotfiles-version-control
|
||||
[7]: https://github.com/lisa/mac-setup
|
||||
[8]: https://github.com/lisa/dotrc
|
||||
[9]: https://docs.ansible.com/ansible/latest/user_guide/vault.html
|
@ -0,0 +1,193 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (FSSlc)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-12987-1.html)
|
||||
[#]: subject: (How to Check Dependencies of a Package in Ubuntu/Debian-based Linux Distributions)
|
||||
[#]: via: (https://itsfoss.com/check-dependencies-package-ubuntu/)
|
||||
[#]: author: (Abhishek Prakash https://itsfoss.com/author/abhishek/)
|
||||
|
||||
如何在基于 Ubuntu 或 Debian 的 Linux 发行版中查看一个软件包的依赖
|
||||
======
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202101/06/112738sv0dmjojmjokpxt0.jpg)
|
||||
|
||||
在 Ubuntu 或 Debian 中通过命令行来安装应用是一件很简单的事,你只需要执行 `apt install package_name` 就可以了。
|
||||
|
||||
但如果你想在安装一个软件包之前或之后知晓这个软件包的依赖,那该怎么办呢?
|
||||
|
||||
在本教程中,我将向你展示多种方法来在 Ubuntu 或其他使用 [APT 包管理器][1] 的 Debian 系 Linux 发行版中查看一个软件包的依赖。
|
||||
|
||||
### 什么是 Ubuntu 中的包依赖?
|
||||
|
||||
当你在 Linux 中安装一个软件包,有时这个软件包还需要其他的软件包来使它工作正常。这些额外的软件包就叫作这个包的依赖。假如这些软件包之前没有在系统中被安装,那么这些依赖在安装这个软件包的同时会被自动安装上。
|
||||
|
||||
举个例子,用来转换视频格式的 GUI 工具 [HandBrake][2] 需要 [FFmpeg][3]、[GStreamer][4] 软件包。所以对于 HandBrake 来说, FFmpeg 和 GStreamer 就是它的包依赖。
|
||||
|
||||
假如在你的系统上这些软件包没有被安装,则当你 [在 Ubuntu 上安装 HandBrake][5] 时,就会自动安装上它们。
|
||||
|
||||
### 在 Ubuntu 和基于 Debian 的发行版中查看一个软件包的依赖
|
||||
|
||||
正如在 Linux 上经常发生的那样,有多种方法来达到相同的目标。下面让我们一起瞧瞧查看一个软件包依赖的多种方法。
|
||||
|
||||
#### 使用 apt show 来查看依赖
|
||||
|
||||
你可以使用 [apt show 命令][6] 来展示一个包的详细信息。其中依赖信息就是其中一部分,你可以在以 “Depends” 打头的那些行中看到它们。
|
||||
|
||||
例如,下面展示的是使用 `apt show` 展示 [ubuntu-restricted-extras][7] 这个包的详细信息:
|
||||
|
||||
```
|
||||
abhishek@itsfoss:~$ apt show ubuntu-restricted-extras
|
||||
Package: ubuntu-restricted-extras
|
||||
Version: 67
|
||||
Priority: optional
|
||||
Section: multiverse/metapackages
|
||||
Origin: Ubuntu
|
||||
Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
|
||||
Bugs: https://bugs.launchpad.net/ubuntu/+filebug
|
||||
Installed-Size: 14.3 kB
|
||||
Depends: ubuntu-restricted-addons
|
||||
Recommends: libavcodec-extra, ttf-mscorefonts-installer, unrar
|
||||
Download-Size: 3,200 B
|
||||
APT-Manual-Installed: yes
|
||||
APT-Sources: http://us.archive.ubuntu.com/ubuntu focal/multiverse amd64 Packages
|
||||
Description: Commonly used media codecs and fonts for Ubuntu
|
||||
This collection of packages includes:
|
||||
- MP3 and other audio codec software to play various audio formats
|
||||
(GStreamer plugins)
|
||||
- software to install the Microsoft Web fonts
|
||||
- the Adobe Flash plugin
|
||||
- LAME, software to create compressed audio files.
|
||||
.
|
||||
This software does not include libdvdcss2, and will not let you play
|
||||
encrypted DVDs. For more information, see
|
||||
https://help.ubuntu.com/community/RestrictedFormats/PlayingDVDs
|
||||
.
|
||||
These software packages are from the Multiverse channel, restricted by
|
||||
copyright or legal issues in some countries. For more information, see
|
||||
http://www.ubuntu.com/ubuntu/licensing
|
||||
```
|
||||
|
||||
如你所见,`ubuntu-restricted-extras` 包依赖于 `ubuntu-restricted-addons` 这个软件包。
|
||||
|
||||
但你得小心的是依赖包还可能依赖于其他包,这样一直循环往复直到尽头。但幸好 APT 包管理器可以为你处理这些复杂的依赖关系,自动地安装所有的依赖(大多数情况下)。
|
||||
|
||||
> **什么是推荐包?**
|
||||
>
|
||||
> 你注意到了上面结果输出中以 “Recommends” 开头的那些行了吗?
|
||||
>
|
||||
> 推荐包不是软件包的直接依赖,但它们可以开启软件包的一些额外功能。
|
||||
>
|
||||
> 正如你上面看到的那样, `ubuntu-restricted-extras` 包有 `ttf-mscorefonts-installer` 这个推荐包,用来在 Ubuntu 上安装 Microsoft 的字体。
|
||||
>
|
||||
> 这些推荐包也会默认被一同安装上,假如你想显式地禁止这些推荐包的安装,你可以像下面这样使用 `–-no-install-recommends` 选项。
|
||||
>
|
||||
> ```
|
||||
> sudo apt install --no-install-recommends package_name
|
||||
> ```
|
||||
|
||||
#### 使用 apt-cache 来直接获取依赖信息
|
||||
|
||||
上面通过 `apt show` 的方式会获取到大量信息,假如你想在脚本中获取到依赖信息,那么 `apt-cache` 命令将会给你一个更好且更简洁的输出结果。
|
||||
|
||||
```
|
||||
apt-cache depends package_name
|
||||
```
|
||||
|
||||
下面的输出看起来更加干净,不是吗?
|
||||
|
||||
![][8]
|
||||
|
||||
#### 使用 dpkg 来查看一个 DEB 文件的依赖
|
||||
|
||||
`apt` 和 `apt-cache` 都作用于软件仓库中的软件包,但假如你下载了一个 DEB 文件,那么这两个命令就不起作用了。
|
||||
|
||||
在这种情形下,你可以使用 `dpkg` 命令的 `-I` 或 `--info` 选项。
|
||||
|
||||
```
|
||||
dpkg -I path_to_deb_file
|
||||
```
|
||||
|
||||
依赖信息就可以在以 “Depends” 开头的那些行中找到。
|
||||
|
||||
![][9]
|
||||
|
||||
#### 使用 apt-rdepends 来查看依赖及依赖的依赖
|
||||
|
||||
假如你想查看更多关于依赖的信息,那么你可以使用 `apt-rdepends` 工具。这个工具可以创建完整的依赖树。这样你就可以得到一个软件包的依赖以及这些依赖的依赖。
|
||||
|
||||
它不是一个常规的 `apt` 命令,所以你需要从 universe 软件仓库中安装上它:
|
||||
|
||||
```
|
||||
sudo apt install apt-rdepends
|
||||
```
|
||||
|
||||
这个命令的输出通常很多,取决于依赖树的大小。
|
||||
|
||||
```
|
||||
Reading package lists... Done
|
||||
Building dependency tree
|
||||
Reading state information... Done
|
||||
shutter
|
||||
Depends: procps
|
||||
Depends: xdg-utils
|
||||
imagemagick
|
||||
Depends: imagemagick-6.q16 (>= 8:6.9.2.10+dfsg-2~)
|
||||
imagemagick-6.q16
|
||||
Depends: hicolor-icon-theme
|
||||
Depends: libc6 (>= 2.4)
|
||||
Depends: libmagickcore-6.q16-6 (>= 8:6.9.10.2)
|
||||
Depends: libmagickwand-6.q16-6 (>= 8:6.9.10.2)
|
||||
hicolor-icon-theme
|
||||
libc6
|
||||
Depends: libcrypt1 (>= 1:4.4.10-10ubuntu4)
|
||||
Depends: libgcc-s1
|
||||
libcrypt1
|
||||
Depends: libc6 (>= 2.25)
|
||||
```
|
||||
|
||||
`apt-rdepends` 工具的功能非常多样,它还可以用来计算反向依赖。这意味着你可以查看某个特定的包被哪些软件包依赖。
|
||||
|
||||
```
|
||||
apt-rdepends -r package_name
|
||||
```
|
||||
|
||||
输出可能会非常多,因为它将打印出反向依赖树。
|
||||
|
||||
```
|
||||
abhishek@itsfoss:~$ apt-rdepends -r ffmpeg
|
||||
Reading package lists... Done
|
||||
Building dependency tree
|
||||
Reading state information... Done
|
||||
ffmpeg
|
||||
Reverse Depends: ardour-video-timeline (>= 1:5.12.0-3ubuntu4)
|
||||
Reverse Depends: deepin-screen-recorder (5.0.0-1build2)
|
||||
Reverse Depends: devede (4.15.0-2)
|
||||
Reverse Depends: dvd-slideshow (0.8.6.1-1)
|
||||
Reverse Depends: green-recorder (>= 3.2.3)
|
||||
```
|
||||
|
||||
我希望这个快速的教程可以帮助你提高一点儿你的命令行知识。为了知晓更多类似小知识点,请保持关注。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://itsfoss.com/check-dependencies-package-ubuntu/
|
||||
|
||||
作者:[Abhishek Prakash][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[FSSlc](https://github.com/FSSlc)
|
||||
校对:[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://wiki.debian.org/Apt
|
||||
[2]: https://itsfoss.com/handbrake/
|
||||
[3]: https://ffmpeg.org/
|
||||
[4]: https://gstreamer.freedesktop.org/
|
||||
[5]: https://itsfoss.com/install-handbrake-ubuntu/
|
||||
[6]: https://itsfoss.com/apt-search-command/
|
||||
[7]: https://itsfoss.com/install-media-codecs-ubuntu/
|
||||
[8]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/08/apt-check-dependencies-ubuntu.png?resize=800%2C297&ssl=1
|
||||
[9]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2020/08/check-dpendencies-of-deb-package.png?resize=800%2C432&ssl=1
|
@ -0,0 +1,287 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (wxy)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-12988-1.html)
|
||||
[#]: subject: (Level up your shell history with Loki and fzf)
|
||||
[#]: via: (https://opensource.com/article/20/10/shell-history-loki-fzf)
|
||||
[#]: author: (Ed Welch https://opensource.com/users/ewelch)
|
||||
|
||||
用 Loki 和 fzf 进阶你的 Shell 历史记录
|
||||
======
|
||||
|
||||
> Loki 扩展了 Prometheus 用于度量监测和日志聚合的模型。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202101/06/155012r4khll9zlqgx79fs.jpg)
|
||||
|
||||
[Loki][2] 是一个 Apache 2.0 许可的开源日志聚合框架,由 Grafana 实验室设计,并在不断发展的社区的巨大支持之下建立。它也是我每天为之努力的项目。在这篇文章中,我将不只是谈论 Loki 如何工作,而是提供一个实际操作的介绍,以解决实际问题。
|
||||
|
||||
### 问题:一个持久的集中式 Shell 历史记录
|
||||
|
||||
我喜欢我的 shell 历史,一直是 `CTRL+R` 的狂热用户。大约一年前,我的终端生活发生了翻天覆地的变化,我的同行 Dieter Plaetinck 向我介绍了命令行模糊查找器 [fzf][3]。
|
||||
|
||||
突然间,在命令中搜索就从这样:
|
||||
|
||||
![在 Loki 和 fzf 之前][4]
|
||||
|
||||
变成了这样:
|
||||
|
||||
![在 Loki 和 fzf 之后][6]
|
||||
|
||||
虽然 `fzf` 极大地提高了我的生活质量,但围绕着我的 shell 历史记录,还是缺少了一些片段:
|
||||
|
||||
* 终端突然关闭、电脑崩溃、死机、整盘加密密钥被遗忘等情况下会丢失 shell 历史记录。
|
||||
* 想从我的所有电脑上访问我的 shell 历史记录。
|
||||
|
||||
我认为我的 shell 历史记录是文件:它是一个重要的故事,我不想失去。将 Loki 与我的 shell 历史结合起来,有助于解决这些问题和更多问题。
|
||||
|
||||
### 关于 Loki
|
||||
|
||||
Loki 采用了开源 [Prometheus][7] 项目用于度量的直观的标签模型,并将其扩展到日志聚合的世界。这使得开发人员和运维人员能够使用相同的标签集在他们的度量和日志之间无缝切换。即使你没有使用 Prometheus,也有很多理由说明 Loki 可能很适合你的日志存储需求:
|
||||
|
||||
* **低开销:** Loki 不做全文日志索引;它只创建你放在日志上的标签的索引。保持小的索引大大降低了 Loki 的运维要求。我在 [树莓派][8] 上运行我的 loki-shell 项目,该项目使用 Loki 来存储 shell 历史记录,只使用了 50MB 多一点的内存。
|
||||
* *成本低:**日志内容被压缩并存储在对象存储中,如 Amazon S3、Google 云存储、Azure Blob,甚至可以直接存储在文件系统中。我们的目标是使用价格低廉且持久的存储。
|
||||
* **灵活性:** Loki 以单个二进制文件的形式提供,可以直接下载并运行,也可以作为 Docker 镜像在任何容器环境中运行。在 Kubernetes 中可以用一个 [Helm 海图][9] 快速上手。如果你对日志工具的要求很高,可以看看运行在 Grafana 实验室的 [生产环境][10]。它使用开源的 [Jsonnet][11] 和 [Tanka][12] 部署了同样的 Loki 镜像作为离散的构件,以实现大规模的水平扩展、高可用性、复制、读写路径的分别扩展、高度可并行的查询等。
|
||||
|
||||
总而言之,Loki 的方法是保留一个关于你的日志元数据的小索引(标签),并将未索引的、压缩的日志内容存储在廉价的对象存储中,以使操作更容易和更便宜。该应用程序被构建为单进程运行,并很容易演变成一个高可用的分布式系统。你可以通过并行化和查询的分片,在较大的日志工作负载上获得较高的查询性能 —— 有点像为你的日志设计的 MapReduce。
|
||||
|
||||
此外,这个功能是任何人都可以免费使用的。与其 [Grafana][13] 开放观测性平台一样,Grafana 实验室致力于将 Loki 打造成一个任何人都可以使用的全功能、全开放的日志聚合软件。
|
||||
|
||||
### 开始吧
|
||||
|
||||
我在树莓派上运行 Loki,并将我的 shell 历史记录异地存储在 S3 bucket 中。
|
||||
|
||||
当我按下 `CTRL+R`,Loki 的 [LogCLI][14] 命令行界面会发起几个批处理请求,传输至 `fzf`。下面是一个例子,上半部分显示的是树莓派上的 Loki 服务器日志。
|
||||
|
||||
![树莓派上 Loki 服务器的日志][15]
|
||||
|
||||
准备试试?下面的指南将帮助你设置和运行 Loki,与你的 shell 历史记录集成。为了让本教程保持简洁,此设置将 Loki 本地运行在你的计算机上,并在文件系统上存储所有文件。
|
||||
|
||||
在 [loki-shell 的 GitHub 版本库][16],你可以找到所有这一切,以及如何设置一个更复杂的安装的信息。
|
||||
|
||||
请注意,本教程不会改变任何围绕你的历史记录的现有行为,所以 _你现有的 shell 历史记录命令和历史记录设置不会被触动_。相反,这将用 Bash 中的 `$PROMPT_COMMAND` 和 Zsh 中的 `precmd` 复制命令历史记录到 Loki。在 `CTRL+R` 方面,它重载了 `fzf` 用来访问 `CTRL+R` 命令的函数。因此试一试是安全的,如果你觉得不喜欢它,只需按照 GitHub 版本库中的 [卸载步骤][17] 来删除所有痕迹。你的 shell 历史记录不会被触及。
|
||||
|
||||
#### 第一步:安装 fzf
|
||||
|
||||
安装 `fzf` 有几种方法,但我更喜欢 [Git 方法][18]:
|
||||
|
||||
```
|
||||
git clone --depth 1 https://github.com/junegunn/fzf.git ~/.fzf
|
||||
~/.fzf/install
|
||||
```
|
||||
|
||||
对所有的问题提示说 `yes`。
|
||||
|
||||
如果你已经安装了 `fzf`,确保你已经启用了键绑定(即,确保当你输入 `CTRL+R` 时,`fzf` 会弹出)。如果有必要的话,你可以重新运行 `fzf` 安装过程来启用键绑定。
|
||||
|
||||
#### 第二步:安装 loki-shell
|
||||
|
||||
和 `fzf` 一样,loki-shell 也有一个 Git 版本库和安装脚本:
|
||||
|
||||
```
|
||||
git clone --depth 1 https://github.com/slim-bean/loki-shell.git ~/.loki-shell
|
||||
~/.loki-shell/install
|
||||
```
|
||||
|
||||
首先,该脚本创建了 `~/.loki-shell` 目录,所有的文件都将保存在该目录下(包括 Loki 数据),接下来,它将下载 [Promtail][19]、LogCLI 和 Loki 的二进制文件。
|
||||
|
||||
然后它会问:
|
||||
|
||||
```
|
||||
Do you want to install Loki? ([y]/n)
|
||||
```
|
||||
|
||||
如果你已经为 Loki-shell 运行了一个集中化的 Loki,你可以回答 `n`;然而,对于本教程,回答 `y` 或按回车键。
|
||||
|
||||
在本地运行 Loki 有两种方式:作为一个 Docker 镜像或作为一个单一的二进制文件(支持添加为 systemd 服务)。如果可以,我建议使用 Docker,因为我认为它稍微简化了操作,但这两者都可以工作。
|
||||
|
||||
##### 使用 Docker 运行
|
||||
|
||||
将 Loki 作为 Docker 镜像运行:
|
||||
|
||||
```
|
||||
[y] to run Loki in Docker, [n] to run Loki as a binary ([y]/n) y
|
||||
Error: No such object: loki-shell
|
||||
Error response from daemon: No such container: loki-shell
|
||||
Error: No such container: loki-shell
|
||||
54843ff3392f198f5cac51a6a5071036f67842bbc23452de8c3efa392c0c2e1e
|
||||
```
|
||||
|
||||
如果这是你第一次运行这个安装程序,你可以忽略错误信息。这个脚本将停止和替换运行的 Loki 容器,如果版本不匹配,你可以重新运行此脚本升级 Loki。
|
||||
|
||||
就是这样!Loki 现在作为一个 Docker 容器运行了。
|
||||
|
||||
Loki 的数据将存储在 `~/.loki-shell/data` 中。
|
||||
|
||||
由于带着 `-restart=unless-stopped` 标志运行该镜像,所以它会在系统重启时重启该服务,但如果你运行 `docker stop loki-shell` 则会保持停止。
|
||||
|
||||
(如果你使用的是 Docker,你可以跳到 “Shell 集成”一节。)
|
||||
|
||||
##### 以二进制文件运行
|
||||
|
||||
在 Linux 系统上运行二进制文件的方法有很多。这个脚本可以安装一个 systemd 服务。如果你没有 systemd,你也可以使用二进制安装:
|
||||
|
||||
```
|
||||
[y] to run Loki in Docker, [n] to run Loki as a binary ([y]/n) n
|
||||
|
||||
Run Loki with systemd? ([y]/n) n
|
||||
|
||||
This is as far as this script can take you
|
||||
You will need to setup an auto-start for Loki
|
||||
It can be run with this command: /home/username/.loki-shell/bin/loki -config.file=/home/username/.loki-shell/config/loki-binary-config.yaml
|
||||
```
|
||||
|
||||
脚本会输出你需要用来运行 Loki 的命令,你可以自己设置一个 init 脚本或其他方法来自动启动它。
|
||||
|
||||
如果你想的话,你可以直接运行该命令,从你当前的 shell 运行 Loki。
|
||||
|
||||
如果你有 systemd,你可以选择让脚本安装 systemd 服务或显示出你自己运行它的命令:
|
||||
|
||||
```
|
||||
Run Loki with systemd? ([y]/n) y
|
||||
|
||||
Installing the systemd service requires root permissions.
|
||||
[y] to run these commands with sudo [n] to print out the commands and you can run them yourself. ([y]/n) n
|
||||
sudo cp /home/ed/.loki-shell/config/loki-shell.service /etc/systemd/system/loki-shell.service
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable loki-shell
|
||||
sudo systemctl start loki-shell
|
||||
Copy these commands and run them when the script finishes. (press enter to continue)
|
||||
```
|
||||
|
||||
##### Shell 集成
|
||||
|
||||
无论你如何安装 Loki,你现在应该看到一个提示:
|
||||
|
||||
```
|
||||
Enter the URL for your Loki server or press enter for default (http://localhost:4100)
|
||||
```
|
||||
|
||||
如果你已经设置了一个中心化的 Loki,你应在这里输入其 URL。然而,这个演示只是使用了默认的 URL,所以你可以按回车键。
|
||||
|
||||
它会输出很多文本来解释添加到你的 `~.bashrc` 或 `~.zshrc`(或两者)的所有条目。
|
||||
|
||||
好了!
|
||||
|
||||
```
|
||||
Finished. Restart your shell or reload config file.
|
||||
source ~/.bashrc # bash
|
||||
source ~/.zshrc # zsh
|
||||
```
|
||||
#### 第三步:试试吧!
|
||||
|
||||
开始使用你的 shell,并使用 `CTRL+R` 查看你的命令。
|
||||
|
||||
打开多个终端窗口,在一个窗口中输入命令,在另一个窗口中输入 `CTRL+R`,你会看到你的命令立即可用。
|
||||
|
||||
另外,请注意,当你在终端之间切换并输入命令时,使用 `CTRL+R` 可以立即使用它们,但向上箭头的操作在终端之间不受影响。(如果你安装了 Oh My Zsh,情况可能就不一样了,因为它会自动将所有命令追加到历史记录中。)
|
||||
|
||||
多次按下 `CTRL+R` 可以在按时间排序和按相关性排序之间切换。
|
||||
|
||||
请注意,此配置将只显示当前主机的查询历史记录,即使你正在从多个主机向 Loki 发送 shell 数据。我认为默认情况下这是最合理的。如果你想改变这种行为,有很多地方可以调整;请参见 loki-shell 版本库了解更多。
|
||||
|
||||
它还安装了一个名为 `hist` 的别名。
|
||||
|
||||
```
|
||||
alias hist="$HOME/.loki-shell/bin/logcli --addr=$LOKI_URL"
|
||||
```
|
||||
|
||||
LogCLI 可以用来直接在 Loki 上查询和搜索你的历史,也允许你搜索其他主机。查看 LogCLI 的入门指南,了解更多关于查询的信息。
|
||||
|
||||
Loki 的日志查询语言(LogQL)提供了度量查询,可以让你做一些有趣的事情,例如,我可以看到在过去 30 天里我发出了多少次 `kc` 命令(我对 `kubectl` 的别名)。
|
||||
|
||||
![计数一个命令的使用次数][20]
|
||||
|
||||
### 额外增强
|
||||
|
||||
安装 Grafana,摆弄一下你的 shell 历史记录。
|
||||
|
||||
```
|
||||
docker run -d -p 3000:3000 --name=grafana grafana/grafana
|
||||
```
|
||||
|
||||
打开 Web 浏览器,访问 `http://localhost:3000`,使用默认的 `admin`/`admin` 用户名和密码登录。
|
||||
|
||||
在左边,导航到“<ruby>配置<rt>Configuration</rt></ruby>-><ruby>数据源<rt>Datasources</rt></ruby>”,点击“<ruby>添加数据源<rt>Add Datasource</rt></ruby>”按钮,然后选择 “Loki”。
|
||||
|
||||
对于 URL,你应该可以使用 `http://localhost:4100`(然而,在我的 WSL2 机器上,我必须使用计算机的实际 IP 地址)。
|
||||
|
||||
单击“<ruby>保存并测试<rt>Save and Test</rt></ruby>”。你应该看到连接了数据源并找到了标签。
|
||||
|
||||
点击左边的“<ruby>管理器<rt>Explore</rt></ruby>”图标,确保选择 Loki 数据源,并尝试这个查询:
|
||||
|
||||
```
|
||||
{job="shell"}
|
||||
```
|
||||
|
||||
如果发送 shell 命令的主机较多,可以使用“<ruby>主机<rt>Host</rt></ruby>”标签将结果限制在某个主机上:
|
||||
|
||||
```
|
||||
{job="shell", hostname="myhost"}.
|
||||
```
|
||||
|
||||
你也可以用过滤表达式寻找特定的命令:
|
||||
|
||||
```
|
||||
{job="shell"} |= "docker"
|
||||
```
|
||||
|
||||
或者你可以从日志中探索度量的世界,看看你使用 shell 的频率:
|
||||
|
||||
```
|
||||
rate({job="shell"}[1m])
|
||||
```
|
||||
|
||||
![计算过去 20 天内 shell 的使用情况][21]
|
||||
|
||||
想从一个事件中重建一个时间线?你可以通过特定的命令进行过滤,查看它的运行时间:
|
||||
|
||||
![计算命令的使用次数][22]
|
||||
|
||||
要想知道你还能做什么,并了解更多关于 Loki 查询语言的信息,请查看 LogQL 指南。
|
||||
|
||||
### 总结
|
||||
|
||||
更多的想法、故障排除和更新,请关注该 GitHub 版本库。这仍然是一项正在进行中的工作,所以请在那里报告发现的任何问题。
|
||||
|
||||
要了解更多关于 Loki 的信息,请查看文档、博客文章和该 GitHub 版本库,或者在 Grafana Cloud 中试用。
|
||||
|
||||
* * *
|
||||
|
||||
特别感谢我的同事 Jack Baldry 为这个想法播下的种子。我有 Loki 的知识来实现这个想法,但如果不是他的建议,我想我永远也不会做到这一点。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/10/shell-history-loki-fzf
|
||||
|
||||
作者:[Ed Welch][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/ewelch
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/chaos_engineer_monster_scary_devops_gear_kubernetes.png?itok=GPYLvfVh (Gears above purple clouds)
|
||||
[2]: https://github.com/grafana/loki
|
||||
[3]: https://github.com/junegunn/fzf
|
||||
[4]: https://opensource.com/sites/default/files/uploads/before.gif (Before Loki and fzf)
|
||||
[5]: https://creativecommons.org/licenses/by-sa/4.0/
|
||||
[6]: https://opensource.com/sites/default/files/uploads/with_fzf.gif (After Loki and fzf)
|
||||
[7]: https://prometheus.io/
|
||||
[8]: https://www.raspberrypi.org/
|
||||
[9]: https://helm.sh/docs/topics/charts/
|
||||
[10]: https://grafana.com/docs/loki/latest/installation/tanka/
|
||||
[11]: https://jsonnet.org
|
||||
[12]: https://tanka.dev/
|
||||
[13]: https://grafana.com/
|
||||
[14]: https://grafana.com/docs/loki/latest/getting-started/logcli/
|
||||
[15]: https://opensource.com/sites/default/files/uploads/example_logcli.gif (Logs of the Loki server on Raspberry Pi)
|
||||
[16]: https://github.com/slim-bean/loki-shell
|
||||
[17]: https://github.com/slim-bean/loki-shell/blob/master/uninstall
|
||||
[18]: https://github.com/junegunn/fzf#using-git
|
||||
[19]: https://grafana.com/docs/loki/latest/clients/promtail/
|
||||
[20]: https://opensource.com/sites/default/files/uploads/count_kc.png (Counting use of a command)
|
||||
[21]: https://opensource.com/sites/default/files/uploads/last_20.png (Counting use of the shell over previous 20 days)
|
||||
[22]: https://opensource.com/sites/default/files/uploads/command_hist.png (Counting use of a command)
|
186
published/20201015 Learn Python by creating a video game.md
Normal file
186
published/20201015 Learn Python by creating a video game.md
Normal file
@ -0,0 +1,186 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (stevenzdg988)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-13031-1.html)
|
||||
[#]: subject: (Learn Python by creating a video game)
|
||||
[#]: via: (https://opensource.com/article/20/10/learn-python-ebook)
|
||||
[#]: author: (Seth Kenlon https://opensource.com/users/seth)
|
||||
|
||||
通过创建视频游戏来学习 Python
|
||||
======
|
||||
|
||||
> 使用我们的新电子书中的分步说明,以有趣的方式了解 Python。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202101/18/234525jdrrv6o6gkhkdq1k.jpg)
|
||||
|
||||
Python 是目前最流行的程序设计语言之一。不管是为了工作还是娱乐为目的学习 Python,它都是一门功能强大且非常有用的编程语言。你可以创建应用程序来帮助你完成日常任务,创建你和朋友们喜欢玩的游戏,创建用于处理数据的脚本,创建用于生成或分析信息的应用程序等等。
|
||||
|
||||
无论你计划使用程序设计语言做什么,我们都认为通过创建游戏来学习比通过处理数字或变换字符串来学习更为有趣。然而,如果你完全是一个编程的新手,当你能看到代码在视频游戏等熟悉的环境中工作时,你会更容易理解为什么要用代码做某事。
|
||||
|
||||
你可能不会选择 [Python][2] 作为最好的编程语言(每个人对此都有自己的答案),但它不是一门令人恐惧的编程语言。 Python 可以使用很多关键字(例如 `is` 和 `is not`)代替符号(例如 `=` 和 `!=`)。它还能管理许多低级任务,因此你通常不必担心数据类型和垃圾收集之类的事情。通常,这意味着你马上就可以开始编写代码,而不会像在 [C][3] 或 [Java][4] 那样的复杂编程语言面前遇到挫折。
|
||||
|
||||
为了帮助你学习 Python,我们编写了一本电子书,教你如何使用 Python 创建平台类视频游戏。在制作视频游戏的同时逐步通过课程学习 Python。另外一个好处是,你还将学习编程逻辑、语法、运算符等更多的内容。你可以在学习过程中立即看到结果,因此你学到的所有内容都会得到及时巩固。
|
||||
|
||||
### 一分钟上手 Python
|
||||
|
||||
Python 是一种用途广泛的编程语言,这意味着它(与大多数语言一样)提供了函数来对数字和字符做处理的“简单技巧”。Linux 操作系统用户已经安装了 Python。 Mac 操作系统用户使用的是较旧版本的 Python,但是你可以从 Python.org 网站 [安装最新版本][5]。Windows 操作系统用户可以从这篇 [在 Windows 上安装 Python][6] 的文章中学习如何安装 Python。
|
||||
|
||||
安装完成后,你可以启动交互式 Python Shell 进行算术运算:
|
||||
|
||||
```
|
||||
$ python3
|
||||
>>> 5+6
|
||||
11
|
||||
>>> 11/2
|
||||
5.5
|
||||
>>> 11//2
|
||||
5
|
||||
>>> 11%2
|
||||
1
|
||||
```
|
||||
|
||||
从该示例可以了解,需要一些特殊的符号,但学过数学的人都最熟悉不过了。也许你不喜欢数字,而更喜欢字母:
|
||||
|
||||
```
|
||||
$ python3
|
||||
>>> string = "hello world"
|
||||
>>> print(string)
|
||||
hello world
|
||||
>>> print(string.upper())
|
||||
HELLO WORLD
|
||||
>>> print(string[0])
|
||||
h
|
||||
>>> print(string[1])
|
||||
e
|
||||
>>> print(string[2])
|
||||
l
|
||||
>>> print(string[3])
|
||||
l
|
||||
>>> print(string[4])
|
||||
o
|
||||
```
|
||||
|
||||
同样,相对地说基础的任务有特殊的符号表示法,但是即使没有说明,你也可能已经发现 `[0]` 和 `[1]` 符号表示法是将数据“切片”并且利用 `print` 函数将其中的数据显示在屏幕上。
|
||||
|
||||
### 五分钟用上 Pygame
|
||||
|
||||
如果你只想使用 Python 来创建一个视频游戏或任何超越基本计算的项目,这可能需要投入大量的学习、努力和时间。幸运的是,Python 诞生已有二十年了,开发者已经开发了代码库来帮助你(相对)轻松地完成典型的程序壮举。[Pygame][7] 是一套用于创建视频游戏的代码模块。它 [不是唯一的这种类库][8],但是它是最古老的(不论好坏),因此在线上有很多文档和示例。
|
||||
|
||||
首先学习 [推荐的 Python 虚拟环境工作流程][9]:
|
||||
|
||||
```
|
||||
$ python3 -m venv mycode/venv
|
||||
$ cd mycode
|
||||
$ source ./venv/bin/activate
|
||||
(venv)$
|
||||
```
|
||||
|
||||
进入虚拟环境后,可以安全地将 Pygame 安装到项目文件夹中:
|
||||
|
||||
```
|
||||
(venv)$ echo "pygame" >> requirements.txt
|
||||
(venv)$ python -m pip install -r requirements.txt
|
||||
[...] Installing collected packages: pygame
|
||||
Successfully installed pygame-x.y.z
|
||||
```
|
||||
|
||||
现在你已经安装了 Pygame,就可以创建一个简单的演示应用程序。它比你想象的要容易。Python 可以进行所谓的面向对象编程(OOP),这是一个漂亮的计算机科学术语,用于描述当代码结构化时,就像你在使用代码创建物理对象一样。然而,程序员并没有受到迷惑。他们知道在编写代码时并不是真的在制造物理对象,但是这样有助于想象,因为这样你就可以了解编程世界的局限性。
|
||||
|
||||
例如,如果你被困在一个荒岛上并想要一杯咖啡,那么你就必须收集一些黏土,做一个杯子,然后烘烤它。如果你足够聪明,先创建一个模具,以便每当需要另一个杯子时,都可以从模板中快速创建一个新杯子。即使每个杯子都来自相同的模板,它们在物理上也是独立的:如果一个杯子破裂,你还会有另一个杯子。你可以通过添加颜色或蚀刻使每个咖啡杯显得独一无二。
|
||||
|
||||
在 Pygame 和许多编程任务中,你都会使用类似的逻辑。在定义之前,它不会出现在你的编程项目中。下面是如何在 Python 和 Pygame 程序中让咖啡杯出现。
|
||||
|
||||
#### 使用 Pygame 进行面向对象编程
|
||||
|
||||
创建一个名为 `main.py` 的文件,并输入以下代码用以启动 Pygame 模块,并使用 Pygame 模板创建一个窗口:
|
||||
|
||||
```
|
||||
import pygame
|
||||
|
||||
pygame.init()
|
||||
|
||||
screen = pygame.display.set_mode((960,720))
|
||||
```
|
||||
|
||||
就像你可能在现实生活中使用模板来创建对象一样,你也可以使用 Pygame 提供的模板来创建一个<ruby>妖精<rt>sprite</rt></ruby>(这是 Pygame 的视觉游戏对象术语)。在面向对象的编程中,`class` 表示对象的模板。在你的文档中输入以下代码:
|
||||
|
||||
```
|
||||
class Cup(pygame.sprite.Sprite):
|
||||
def __init__(self):
|
||||
pygame.sprite.Sprite.__init__(self)
|
||||
|
||||
# image
|
||||
img = pygame.image.load('coffeecup.png').convert()
|
||||
self.image = img
|
||||
|
||||
# volume
|
||||
self.rect = self.image.get_rect()
|
||||
self.rect.x = 10
|
||||
self.rect.y = 10
|
||||
```
|
||||
|
||||
该代码块使用 Pygame 的 `sprite` 模板设计一个咖啡杯子妖精。由于 `self.image` 的存在,你的咖啡杯妖精有一个图像,而 `self.rect` 则赋予了它体积(宽度和高度)。这些是 Pygame 期望妖精拥有的属性,但是如果你要创建一个可玩的视频游戏,则可以为其指定任何其他所需的属性,例如健康点和得分。
|
||||
|
||||
到目前为止,你所要做的就是创建一个窗口和一个用于咖啡杯的 _模板_ 。你的游戏实际上还没有一个杯子。
|
||||
|
||||
你的代码的最后一部分必须使用模板来生成杯子并将其添加到游戏世界中。如你所知,计算机运行速度非常快,因此从技术上讲,你到目前为止创建的代码只会运行一毫秒左右。编写图形计算机应用程序时,无论计算机是否认为已完成规定的任务,都必须强制其保持打开状态。程序员使用 _无限循环_ 来执行此操作,该循环在 Python 中由 `while True` 语句表示(`True` 始终为真,因此循环永远不会结束)。
|
||||
|
||||
无限循环可以确保你的应用程序保持打开状态足够长的时间,以使计算机用户可以查看和使用该应用程序:
|
||||
|
||||
```
|
||||
cup = Cup()
|
||||
|
||||
while True:
|
||||
pygame.display.update()
|
||||
screen.blit(cup.image, cup.rect)
|
||||
```
|
||||
|
||||
此代码示例从模板 `Cup` 创建杯子,然后使用 Pygame 函数更新显示。最后,使用 Pygame 的 `blit` 函数在其边框内绘制杯子的图像。
|
||||
|
||||
#### 获取图形
|
||||
|
||||
在成功运行代码之前,你需要为咖啡杯准备一个图形。你可以在 [FreeSVG.org][11] 上找到许多 [公用创作][10] 咖啡杯图形。我用了 [这个][12]。将图形保存在项目目录中,并将其命名为 `coffeecup.png`。
|
||||
|
||||
#### 运行游戏
|
||||
|
||||
启动应用程序:
|
||||
|
||||
```
|
||||
(venv)$ python ./main.py
|
||||
```
|
||||
|
||||
![Pygame 中的咖啡杯][13]
|
||||
|
||||
- [下载 Python 游戏电子书][15]
|
||||
|
||||
Pygame 是一个功能强大的框架,除了在屏幕上绘制咖啡杯之外,你还可以做更多的事情。[下载我们的免费电子书][15] 更好地了解 Pygame 和 Python。
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/10/learn-python-ebook
|
||||
|
||||
作者:[Seth Kenlon][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[stevenzdg988](https://github.com/stevenzdg988)
|
||||
校对:[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/arcade_game_gaming.jpg?itok=84Rjk_32 (Arcade games)
|
||||
[2]: https://www.python.org/
|
||||
[3]: https://opensource.com/article/20/8/c-programming-cheat-sheet
|
||||
[4]: https://opensource.com/resources/java
|
||||
[5]: https://www.python.org/downloads/mac-osx
|
||||
[6]: https://opensource.com/article/19/8/how-install-python-windows
|
||||
[7]: https://www.pygame.org/news
|
||||
[8]: https://opensource.com/article/18/4/easy-2d-game-creation-python-and-arcade
|
||||
[9]: https://opensource.com/article/20/9/venv-python
|
||||
[10]: https://opensource.com/article/20/1/what-creative-commons
|
||||
[11]: http://freesvg.org
|
||||
[12]: https://freesvg.org/1548870028
|
||||
[13]: https://opensource.com/sites/default/files/uploads/pygame-cup.jpg (Coffee cup in Pygame)
|
||||
[14]: https://creativecommons.org/licenses/by-sa/4.0/
|
||||
[15]: https://opensource.com/downloads/python-gaming-ebook
|
@ -0,0 +1,111 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (mengxinayan)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-12965-1.html)
|
||||
[#]: subject: (How the Linux kernel handles interrupts)
|
||||
[#]: via: (https://opensource.com/article/20/10/linux-kernel-interrupts)
|
||||
[#]: author: (Stephan Avenwedde https://opensource.com/users/hansic99)
|
||||
|
||||
Linux 内核如何处理中断
|
||||
======
|
||||
|
||||
> 中断是计算机处理数据的关键部分。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202012/29/063805o5taf82ftgz85e22.jpg)
|
||||
|
||||
中断是现代 CPU 工作方式中重要的部分。例如:当你每次在键盘上按下一个按键后,CPU 会被中断以使得 PC 读取用户键盘的输入。这个过程发生得相当快,以致于在使用体验上你不会感到任何变化或损害。
|
||||
|
||||
此外,键盘并不是导致中断的唯一组件。一般来说,有三种类型的事件会导致 CPU 发生中断:硬件中断、软件中断和异常。在具体介绍不同类型的中断前,我需要先定义一些术语。
|
||||
|
||||
### 定义
|
||||
|
||||
<ruby>中断请求<rt>interrupt request</rt></ruby>(IRQ)是由<ruby>可编程的中断控制器<rt>programmable interrupt controlle</rt></ruby>(PIC)发起的,其目的是为了中断 CPU 和执行<ruby>中断服务程序<rt>interrupt service routine</rt></ruby>(ISR)。中断服务程序(ISR)是一个小的程序,用来处理具体的数据,其具体的处理方式依赖于造成中断请求(IRQ)的原因。之前正在运行的进程在中断服务程序(ISR)运行结束前都会被中断。
|
||||
|
||||
在过去,中断请求由单独的芯片处理(中断控制器芯片 PIC),I/O 设备直接与中断控制器(PIC)相连。中断控制器(PIC)管理着多种硬件的中断请求(IRQ),并且可以直接与 CPU 通信。当一个中断请求(IRQ)产生后,中断控制器(PIC)向 CPU 写入数据,并且触发中断请求引脚(INTR)。
|
||||
|
||||
现如今,中断请求(IRQ)由 CPU 中的<ruby>高级可编程中断控制器<rt>advanced programmable interrupt controller</rt></ruby>(APIC)部分来处理。每个核中都拥有属于自己的高级可编程中断控制器。
|
||||
|
||||
### 中断的类型
|
||||
|
||||
正如我前文中提到的,中断可以根据其来源分为三种类型。
|
||||
|
||||
#### 硬件中断
|
||||
|
||||
当一个硬件设备想要告诉 CPU 某一需要处理的数据已经准备好后(例如:当键盘被按下或者一个数据包到了网络接口处),它将会发送一个中断请求(IRQ)来告诉 CPU 数据是可用的。接下来会调用在内核启动时设备驱动注册的对应的中断服务程序(ISR)。
|
||||
|
||||
#### 软件中断
|
||||
|
||||
当你在播放一个视频时,音频和视频是同步播放是相当重要的,这样音乐的速度才不会变化。这是由软件中断实现的,由精确的计时器系统(称为 [jiffies][2])重复发起的。这个计时器会使得你的音乐播放器同步。软件中断也可以被特殊的指令所调用,来读取或写入数据到硬件设备。
|
||||
|
||||
当系统需要实时性时(例如在工业应用中),软件中断会变得重要。你可以在 Linux 基金会的文章中找到更多相关信息:[面向嵌入式开发者的实时 Linux 介绍][3]。
|
||||
|
||||
#### 异常
|
||||
|
||||
<ruby>异常<rt>exception</rt></ruby>是你可能之前就知道的中断类型。当 CPU 执行一些将会导致除零或缺页错误的指令时,任何其他运行中的程序都会被中断。在这种情况下,你会被一个弹窗提醒,或在控制台输出中看到**<ruby>段错误<rt>segmentation fault</rt></ruby>(<ruby>核心已转储<rt>core dumped</rt></ruby>)**。但并不是所有异常都是由指令错误引起的。
|
||||
|
||||
异常可以进一步分为<ruby>错误<rt>Fault</rt></ruby>、<ruby>陷阱<rt>Trap</rt></ruby>和<ruby>终止<rt>Abort</rt></ruby>。
|
||||
|
||||
* **错误**:错误是系统可以纠正的异常。例如当一个进程尝试访问某个已经被换出到硬盘的页时。当请求的地址在进程的地址空间中,并且满足访问权限时,如果页不在内存(RAM)中,将会产生一个中断请求(IRQ),并开始启用**缺页异常处理程序**把所需的页加载到内存中。如果操作成功执行,程序将继续运行。
|
||||
* **陷阱**:陷阱主要用在调试中。如果你在某个程序中设置了一个断点,你就插入了一条可以触发陷阱执行的特殊指令。陷阱可以触发上下文切换来允许你的调试器读取和展示局部变量的值。之后程序可以继续运行。陷阱同样也是运行系统调用的方式(如杀死一个进程)
|
||||
* **终止**:终止是由系统表中的硬件错误或值不一致而导致的。终止不会报告造成异常的指令的所在位置。这是最严重的中断,终止将会调用系统的**终止异常处理程序**来结束造成异常的进程。
|
||||
|
||||
### 动手实践
|
||||
|
||||
中断请求按照高级可编程中断控制器(APIC)中的优先级高低排序(0是最高优先级)。前 32 个中断(0~31)是由 CPU 指定的固定序列。你可以在 [OsDev 异常][4] 页面找到关于它们的概述。随后的中断请求可以以不同的方式进行分配。<ruby>中断描述表<rt>interrupt descriptor table</rt></ruby>(IDT)中记录了中断请求(IRQ)和中断服务程序(ISR)的对应关系。Linux 中定义了从 0 到 256 的 IRQ 向量。
|
||||
|
||||
为了打印出在你的系统中已注册的中断,打开一个终端并输入:
|
||||
|
||||
```
|
||||
cat /proc/interrupts
|
||||
```
|
||||
|
||||
你应该会看到类似如下图的结果:
|
||||
|
||||
![注册的中断列表][5]
|
||||
|
||||
*内核版本为5.6.6中注册的中断 (Stephan Avenwedde, [CC BY-SA 4.0][6])*
|
||||
|
||||
从左到右各列的含义依次为:中断向量号、每个 CPU(0~n)中断发生次数、硬件来源、硬件源通道信息、以及造成中断请求的设备名。
|
||||
|
||||
在表的末尾,有一些非数字的中断。它们是特定于体系结构的中断,如<ruby>本地计时器中断<rt>local timer interrupt</rt></ruby>(LOC)的中断请求(IRQ)号为 236。其中一些在 Linux 内核源树中的[Linux IRQ 向量布局][7]中指定。
|
||||
|
||||
![特定于体系结构的中断][8]
|
||||
|
||||
*特定于体系结构的中断 (Stephan Avenwedde, [CC BY-SA 4.0][6])*
|
||||
|
||||
如果要实时获取该表,请运行如下命令:
|
||||
|
||||
```
|
||||
watch -n1 "cat /proc/interrupts"
|
||||
```
|
||||
|
||||
### 总结
|
||||
|
||||
正确的中断请求(IRQ)处理对于硬件、驱动和软件的正常交互是必要的。幸运地是,Linux 内核很好地完成了它,一个 PC 的普通用户几乎不会注意到内核的整个中断处理过程。
|
||||
|
||||
中断相当复杂,本文仅仅是一个关于中断的概述。如果想要深入了解该主题可以阅读 [Linux Inside 电子书][9](CC BY-NC-SA 4.0)和 [Linux 内核教程][10] 仓库。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/10/linux-kernel-interrupts
|
||||
|
||||
作者:[Stephan Avenwedde][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[萌新阿岩](https://github.com/mengxinayan)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/hansic99
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/car-penguin-drive-linux-yellow.png?itok=twWGlYAc (Penguin driving a car with a yellow background)
|
||||
[2]: https://elinux.org/Kernel_Timer_Systems
|
||||
[3]: https://www.linuxfoundation.org/blog/2013/03/intro-to-real-time-linux-for-embedded-developers/
|
||||
[4]: https://wiki.osdev.org/Exceptions
|
||||
[5]: https://opensource.com/sites/default/files/uploads/proc_interrupts_1.png (Registered interrupts list)
|
||||
[6]: https://creativecommons.org/licenses/by-sa/4.0/
|
||||
[7]: https://github.com/torvalds/linux/blob/master/arch/x86/include/asm/irq_vectors.h
|
||||
[8]: https://opensource.com/sites/default/files/uploads/proc_interrupts_2.png (Architecture-specific interrupts)
|
||||
[9]: https://0xax.gitbooks.io/linux-insides/content/Interrupts/
|
||||
[10]: https://linux-kernel-labs.github.io/refs/heads/master/lectures/interrupts.html#
|
300
published/202012/20201214 Set up an Ansible lab in 20 minutes.md
Normal file
300
published/202012/20201214 Set up an Ansible lab in 20 minutes.md
Normal file
@ -0,0 +1,300 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (wxy)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-12970-1.html)
|
||||
[#]: subject: (Set up an Ansible lab in 20 minutes)
|
||||
[#]: via: (https://opensource.com/article/20/12/ansible-lab)
|
||||
[#]: author: (Mike Calizo https://opensource.com/users/mcalizo)
|
||||
|
||||
20 分钟建立一个 Ansible 实验室
|
||||
======
|
||||
|
||||
> 建立一个支持学习和实验新软件的环境。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202012/31/112636h6ck5qd60d44t0mm.jpg)
|
||||
|
||||
能够构建和拆解公有云环境是非常有用的,但我们大多数人都不能轻松访问公有云。退而求其次的最好办法就是在本地机器上建立一个实验室,但即使在本地机器上运行也会带来性能、灵活性和其他挑战。大多数时候,本地机器上额外的工作负载会干扰我们日常的工作,它们当然也会影响你提供一个现成的环境来玩耍和实验新软件。
|
||||
|
||||
几年前,当我和我的团队开始学习 [Ansible][2] 时,我们就遇到了这个挑战。我们找不到一个可以单独使用的环境,我们对这种情况的失望导致我们中的一些人停止了实验。我们知道需要找到一个解决方案。
|
||||
|
||||
我们花了很多时间研究各种方案,得出了一套工具,使我们的好奇心能够在我们完全控制的环境中学习。我们可以在本地机器上轮换和拆解实验室环境,而不需要访问内部实验室或公共云。
|
||||
|
||||
本文将解释如何在 20 分钟内以完全自动化的方式在本地机器上部署自己的实验室环境。
|
||||
|
||||
你可以在我的 [GitHub 仓库][3]中找到这个练习的所有代码。
|
||||
|
||||
### 工具和软件
|
||||
|
||||
本方案使用以下工具和软件:
|
||||
|
||||
* [Ansible][4] 是我们选择的自动化工具,因为它易于使用,而且足够灵活,可以满足实验室的要求。
|
||||
* [Vagrant][5] 易于使用,用于构建和维护虚拟机。
|
||||
* [VirtualBox][6] 是一个托管管理程序,可以在 Windows 和 Linux 环境中使用。
|
||||
* [Fedora v30+][7] 是我本地机器上的操作系统。
|
||||
|
||||
你必须进行以下设置才能建立环境:
|
||||
|
||||
* 一个互联网连接
|
||||
* 在 BIOS 中启用虚拟化技术支持(以下是在我的联想笔记本上的[过程][8])
|
||||
* Vagrant v2.2.9
|
||||
* 最新版本的 Ansible
|
||||
* 最新版本的 VirtualBox
|
||||
* Fedora v30+ 宿主机操作系统
|
||||
|
||||
### 这个实验室环境有什么?
|
||||
|
||||
这个项目旨在部署一个带有 Ansible 引擎和多个 Linux 节点的 Ansible 主机,以及一些预加载和预配置的应用程序(httpd 和 MySQL)。它还启用了 [Cockpit][9],这样你就可以在测试过程中监控虚拟机(VM)的状态。使用预部署的应用程序的原因是为了提高效率(所以你不必花时间安装这些组件)。这样你就可以专注于创建角色和剧本,并针对上述工具部署的环境进行测试。
|
||||
|
||||
我们确定,对于我们的用例来说,最好的方案是多机 Vagrant 环境。Vagrant 文件创建了三个 CentOS 虚拟机,以模拟两个目标主机和一个 Ansible 控制机。
|
||||
|
||||
* Host1: 没有图形用户界面(GUI),安装 httpd 和 MySQL
|
||||
* Host2: 没有 GUI,安装了 httpd 和 MySQL
|
||||
* Ansible-host:没有 GUI,安装了 Ansible 引擎
|
||||
|
||||
### 启用多个管理程序
|
||||
|
||||
如果使用了多个管理程序,一些管理程序可能不允许你拉起虚拟机。要解决这个问题,请遵循以下步骤(基于 Vagrant 的[安装][10]说明)。
|
||||
|
||||
首先,找出管理程序的名称:
|
||||
|
||||
```
|
||||
$ lsmod | grep kvm
|
||||
kvm_intel 204800 6
|
||||
kvm 593920 1 kvm_intel
|
||||
irqbypass 16384 1 kvm
|
||||
```
|
||||
|
||||
我感兴趣的是 `kvm_intel`,但你可能需要另一个(比如 `kvm_amd`)。
|
||||
|
||||
以 root 身份运行以下内容,将该管理程序列入黑名单:
|
||||
|
||||
```
|
||||
$ echo 'blacklist kvm-intel' >> /etc/modprobe.d/blacklist.conf
|
||||
```
|
||||
|
||||
重新启动你的机器并尝试再次运行 Vagrant。
|
||||
|
||||
### Vagrant 文件
|
||||
|
||||
```
|
||||
cat Vagrantfile
|
||||
```
|
||||
|
||||
```
|
||||
# -*- mode: ruby -*-
|
||||
# vi: set ft=ruby :
|
||||
|
||||
Vagrant.configure("2") do |config|
|
||||
# Define VMs with static private IP addresses, vcpu, memory and vagrant-box.
|
||||
boxes = [
|
||||
{
|
||||
:name => "web1.demo.com", ⇒ Host1 this is one of the target nodes
|
||||
:box => "centos/8", ⇒ OS version
|
||||
:ram => 1024, ⇒ Allocated memory
|
||||
:vcpu => 1, ⇒ Allocated CPU
|
||||
:ip => "192.168.29.2" ⇒ Allocated IP address of the node
|
||||
},
|
||||
{
|
||||
:name => "web2.demo.com", ⇒ Host2 this is one of the target nodes
|
||||
:box => "centos/8",
|
||||
:ram => 1024,
|
||||
:vcpu => 1,
|
||||
:ip => "192.168.29.3"
|
||||
},
|
||||
{
|
||||
:name => "ansible-host", ⇒ Ansible Host with Ansible Engine
|
||||
:box => "centos/8",
|
||||
:ram => 8048,
|
||||
:vcpu => 1,
|
||||
:ip => "192.168.29.4"
|
||||
}
|
||||
]
|
||||
|
||||
# Provision each of the VMs.
|
||||
boxes.each do |opts|
|
||||
config.vm.define opts[:name] do |config|
|
||||
# Only Enable this if you are connecting to Proxy server
|
||||
# config.proxy.http = "http://usernam:password@x.y:80"⇒ Needed if you have a proxy
|
||||
# config.proxy.https = "http://usernam:password@x.y:80"
|
||||
# config.proxy.no_proxy = "localhost,127.0.0.1"
|
||||
config.vm.synced_folder ".", "/vagrant", id: "vagrant-root", disabled: true
|
||||
config.ssh.insert_key = false
|
||||
config.vm.box = opts[:box]
|
||||
config.vm.hostname = opts[:name]
|
||||
config.vm.provider :virtualbox do |v| ⇒ Defines the vagrant provider
|
||||
v.memory = opts[:ram]
|
||||
v.cpus = opts[:vcpu]
|
||||
end
|
||||
config.vm.network :private_network, ip: opts[:ip]
|
||||
config.vm.provision :file do |file|
|
||||
file.source = './keys/vagrant' ⇒ vagrant keys to allow access to the nodes
|
||||
file.destination = '/tmp/vagrant' ⇒ the location to copy the vagrant key
|
||||
end
|
||||
config.vm.provision :shell, path: "bootstrap-node.sh" ⇒ script that copy hosts entry
|
||||
config.vm.provision :ansible do |ansible| ⇒ declaration to run ansible playbook
|
||||
ansible.verbose = "v"
|
||||
ansible.playbook = "playbook.yml" ⇒ the playbook used to configure the hosts
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
这些是你需要注意的重要文件。
|
||||
|
||||
* `inventory-test.yaml`:连接到节点的清单文件
|
||||
* `playbook.yaml`:Vagrant 供应者调用的用于配置节点的剧本文件
|
||||
* `Vagrantfile':Vagrant 用来部署环境的文件
|
||||
* Vagrant 密钥文件:连接实验室环境中各节点的 Vagrant 密钥
|
||||
|
||||
你可以根据你的需要调整这些文件。Ansible 的灵活性使你有能力根据你的需要声明性地改变你的环境。
|
||||
|
||||
### 部署你的实验室环境
|
||||
|
||||
首先,克隆这个 [GitHub 仓库][11] 中的代码:
|
||||
|
||||
```
|
||||
$ git clone https://github.com/mikecali/ansible-labs-101.git
|
||||
Cloning into 'ansible-labs-101'...
|
||||
remote: Enumerating objects: 15, done.
|
||||
remote: Counting objects: 100% (15/15), done.
|
||||
remote: Compressing objects: 100% (13/13), done.
|
||||
remote: Total 15 (delta 2), reused 10 (delta 0), pack-reused 0
|
||||
Unpacking objects: 100% (15/15), 6.82 KiB | 634.00 KiB/s, done.
|
||||
```
|
||||
|
||||
接下来,将你的目录改为 `vagrant-session-2`,并查看其内容:
|
||||
|
||||
```
|
||||
$ ls
|
||||
Bootstrap-node.sh inventory keys playbook.yml README.md Vagrantfile
|
||||
```
|
||||
|
||||
现在你已经拥有了实验室环境所需的所有工件和配置文件。要部署环境,请运行:
|
||||
|
||||
```
|
||||
$ vagrant up
|
||||
```
|
||||
|
||||
只要有一个像样的网络连接,只需要 20 分钟左右就可以得到一个运行环境:
|
||||
|
||||
```
|
||||
$ vagrant up
|
||||
Bringing machine 'web1.demo.com' up with 'virtualbox' provider...
|
||||
Bringing machine 'web2.demo.com' up with 'virtualbox' provider...
|
||||
Bringing machine 'ansible-host' up with 'virtualbox' provider...
|
||||
==> web1.demo.com: Importing base box 'centos/8'...
|
||||
==> web1.demo.com: Matching MAC address for NAT networking...
|
||||
==> web1.demo.com: Checking if box 'centos/8' version '1905.1' is up to date...
|
||||
==> web1.demo.com: Setting the name of the VM: ansible-labs_web1democom_1606434176593_70913
|
||||
==> web1.demo.com: Clearing any previously set network interfaces...
|
||||
==> web1.demo.com: Preparing network interfaces based on configuration...
|
||||
web1.demo.com: Adapter 1: nat
|
||||
web1.demo.com: Adapter 2: hostonly
|
||||
==> web1.demo.com: Forwarding ports...
|
||||
web1.demo.com: 22 (guest) => 2222 (host) (adapter 1)
|
||||
==> web1.demo.com: Running 'pre-boot' VM customizations...
|
||||
==> web1.demo.com: Booting VM...
|
||||
==> web1.demo.com: Waiting for machine to boot. This may take a few minutes...
|
||||
web1.demo.com: SSH address: 127.0.0.1:2222
|
||||
web1.demo.com: SSH username: vagrant
|
||||
web1.demo.com: SSH auth method: private key
|
||||
[...]
|
||||
```
|
||||
|
||||
一旦该剧本执行完成,你会看到这样的输出:
|
||||
|
||||
```
|
||||
PLAY RECAP *********************************
|
||||
Ansible-host : ok=20 changed=11 unreachable=0 failed=0 skipped=0 rescued=0 ignored=3
|
||||
|
||||
Real 18m14.288s
|
||||
User 2m26.978s
|
||||
Sys 0m26.849s
|
||||
```
|
||||
|
||||
确认所有虚拟机都在运行:
|
||||
|
||||
```
|
||||
$ vagrant status
|
||||
Current machine states:
|
||||
|
||||
Web1.demo.com running (virtualbox)
|
||||
Web2.demo.com running (virtualbox)
|
||||
ansible-host running (virtualbox)
|
||||
[...]
|
||||
```
|
||||
|
||||
你可以通过登录其中一个虚拟机进一步调查。访问 `ansible-host`:
|
||||
|
||||
```
|
||||
> vagrant ssh ansible-host
|
||||
Activate the web console with: systemctl enable --now cockpit.socket
|
||||
|
||||
Last login: Thu Nov 26 12:21:23 2020 from 10.0.2.2
|
||||
[vagrant@ansible-host ~] uptime
|
||||
16:46:42 up 1:24, 1 user, load average: 0.00, 0.01, 0.04
|
||||
```
|
||||
|
||||
最后,你可以使用 Ansible 模块来 ping 你创建的其他节点:
|
||||
|
||||
```
|
||||
[vagrant@ansible-host]$ ansible -i inventory-test.yaml \
|
||||
webservers -m ping -u vagrant
|
||||
192.168.29.2 | SUCCESS => {
|
||||
"Ansible-facts": {
|
||||
"Discovered_interpreter_python": "/usr/libexec/platform-python"
|
||||
},
|
||||
"Changed": false;
|
||||
"Ping": "pong"
|
||||
}
|
||||
[...]
|
||||
```
|
||||
|
||||
### 清理
|
||||
|
||||
运行如下命令来清理环境:
|
||||
|
||||
```
|
||||
$ vagrant destroy [vagrant machine name]
|
||||
```
|
||||
|
||||
你的输出会像这样:
|
||||
|
||||
![Output from cleaning up environment][12]
|
||||
|
||||
### 有创意的学习
|
||||
|
||||
在自己的实验室里利用自己的时间学习 Ansible 这样的软件是一个好习惯,但由于受到无法控制的限制,可能会很困难。
|
||||
|
||||
有时候,你需要发挥创意,找到另一种方法。在开源社区中,你可以选择很多方案;我们选择这些工具的主要原因之一是,它们是许多人常用和熟悉的。
|
||||
|
||||
另外,请注意,这些剧本并没有按照我的要求进行优化。请随时改进它们,并在评论中分享你的工作。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/12/ansible-lab
|
||||
|
||||
作者:[Mike Calizo][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/mcalizo
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/science_experiment_beaker_lab.png?itok=plKWRhlU (Science lab with beakers)
|
||||
[2]: https://opensource.com/resources/what-ansible
|
||||
[3]: https://github.com/mikecali/ansible-labs-101
|
||||
[4]: https://www.ansible.com/
|
||||
[5]: https://www.vagrantup.com/
|
||||
[6]: https://www.virtualbox.org/
|
||||
[7]: https://getfedora.org/
|
||||
[8]: https://support.lenovo.com/pt/en/solutions/ht500006
|
||||
[9]: https://opensource.com/article/20/11/cockpit-server-management
|
||||
[10]: https://www.vagrantup.com/docs/installation
|
||||
[11]: https://github.com/mikecali/ansible-labs-101.git
|
||||
[12]: https://opensource.com/sites/default/files/uploads/cleanup.png (Output from cleaning up environment)
|
||||
[13]: https://creativecommons.org/licenses/by-sa/4.0/
|
@ -1,18 +1,20 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-12964-1.html)
|
||||
[#]: subject: (How to use this KDE Plasma text editor)
|
||||
[#]: via: (https://opensource.com/article/20/12/kwrite-kde-plasma)
|
||||
[#]: author: (Seth Kenlon https://opensource.com/users/seth)
|
||||
|
||||
如何使用这个 KDE Plasma 文本编辑器?
|
||||
======
|
||||
作为流行的 KDE Plasma 桌面的一部分,KWrite 在一个简单易用的界面中隐藏了大量有用的功能。
|
||||
![Coding on a computer][1]
|
||||
|
||||
KWrite 是一款适用于 KDE Plasma 桌面的文本编辑器。它的目的是成为一个通用的应用,任何人都可以在他们需要快速做笔记、写一篇学校论文、做一些编程,和/或任何其他你能想到的文本编辑器能做的事时用上它。它使用 [Kate 编辑器][2]的组件来创建一个简单的界面,但它利用这些相同的组件来提供大量有用的功能。
|
||||
> 作为流行的 KDE Plasma 桌面的一部分,KWrite 在一个简单易用的界面中隐藏了大量有用的功能。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202012/29/010557o53b649j66a1snjv.jpg)
|
||||
|
||||
KWrite 是一款适用于 KDE Plasma 桌面的文本编辑器。它的目的是成为一个通用的应用,任何人都可以在他们需要快速做笔记、写一篇学校论文、做一些编程,和/或任何其他你能想到的文本编辑器能做的事时用上它。它使用 [Kate 编辑器][2]的组件来创建一个简单的界面,但它利用这些相同的组件来提供了大量有用的功能。
|
||||
|
||||
### 安装
|
||||
|
||||
@ -22,7 +24,7 @@ KWrite 不可用于所有环境,它是 [KDE Plasma 桌面][3]的一个组件
|
||||
|
||||
### 使用 KWrite
|
||||
|
||||
当你启动 KWrite 时,你会看到期望的编辑器的样子:一大块用于输入的区域,顶部有一个菜单栏和工具栏,底部有一个状态栏。这就是你在开始之前需要了解的全部内容。KWrite 是一个直观的应用,工具栏按钮用于重要的活动,如打开和保存文件,简单的菜单系统用于更高级的编辑任务。
|
||||
当你启动 KWrite 时,你会看到期望的编辑器的样子:一大块用于输入的区域,顶部有一个菜单栏和工具栏,底部有一个状态栏。这就是你在开始之前需要了解的全部内容。KWrite 是一个直观的应用,工具栏按钮用于重要的动作,如打开和保存文件,简单的菜单系统用于更高级的编辑任务。
|
||||
|
||||
![Kwrite terminal containing dark gray html code on white background][4]
|
||||
|
||||
@ -30,29 +32,25 @@ KWrite 的许多功能都是潜在的,不需要你自己去激活它们就会
|
||||
|
||||
当然,你不必只选择 HTML、Python 和你的母语。KWrite 支持很多语言和格式(对于很多语言和格式,它甚至有自动完成选项)。
|
||||
|
||||
对于那些想要不止那些自动加载功能的用户,在编辑、视图和工具菜单中都有一些选项。例如,你可以激活动态拼写检查、运行脚本、调出命令行、注释或取消注释一行、调整缩进、显示行号等等。
|
||||
对于那些想要除了自动加载功能之外更多功能的用户,在编辑、视图和工具菜单中都有一些选项。例如,你可以激活动态的拼写检查、运行脚本、调出命令行、注释或取消注释一行、调整缩进、显示行号等等。
|
||||
|
||||
当从终端启动 KWrite 时,也有一些有趣的选项。例如,如果你知道要到文件中的哪一行,你可以用行号参数启动 KWrite:
|
||||
|
||||
|
||||
```
|
||||
`$ kwrite --line 101 example.txt`
|
||||
$ kwrite --line 101 example.txt
|
||||
```
|
||||
|
||||
你也可以使用 `--stdin` (或简写 `-i`)选项方便地将命令的输出通过管道到 KWrite。例如,这个命令下载 [example.com][5] 的首页,并在一个新的 KWrite 窗口中显示 HTML:
|
||||
|
||||
|
||||
```
|
||||
`$ curl http://example.com | kwrite --stdin`
|
||||
$ curl http://example.com | kwrite --stdin
|
||||
```
|
||||
|
||||
### 尝试 KWrite
|
||||
|
||||
我一直觉得 KDE 的优势之一就是它的复杂性很灵活。如果你想要一个简单的桌面,你基本上可以选择忽略任何你不想要的功能。KWrite 就是这种灵活性也适用于开发人员的一个例子。由于 Kate 具有许多功能,所以开发者有可能重用这些功能的一个子集来创建一个更干净、更专注的应用版本。
|
||||
我一直觉得 KDE 的优势之一就是它的复杂性很灵活。如果你想要一个简单的桌面,你基本上可以选择忽略任何你不想要的功能。KWrite 就是这种灵活性也适用于开发人员的一个例子。由于 Kate 具有许多功能,所以开发者有能够重用这些功能的一个子集来创建一个更干净、更专注的应用版本。
|
||||
|
||||
KWrite 是一个单文档编辑器。它没有标签,也没有任何项目的意识。它的目的是为那些想一次只处理一个文档的人准备的,他们希望基本的功能在默认情况下是活跃的,在需要的时候可以选择强大的编辑工具。安装优秀的 Plasma 桌面,今天就来试试吧!
|
||||
|
||||
KDE 最初是 Kool Desktop Environment 的缩写,但现在很多人都认为是 K Desktop。。。
|
||||
KWrite 是一个单文档编辑器。它没有标签,也没有任何“项目”的意识。它的目的是为那些想一次只处理一个文档的人准备的,他们希望基本的功能在默认情况下是激活的,在需要的时候可以选择强大的编辑工具。安装优秀的 Plasma 桌面,今天就来试试吧!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
@ -61,7 +59,7 @@ via: https://opensource.com/article/20/12/kwrite-kde-plasma
|
||||
作者:[Seth Kenlon][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/) 荣誉推出
|
||||
|
@ -1,8 +1,8 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-12971-1.html)
|
||||
[#]: subject: (4 cool new projects to try in COPR from December 2020)
|
||||
[#]: via: (https://fedoramagazine.org/4-cool-new-projects-to-try-in-copr-from-december/)
|
||||
[#]: author: (Jakub Kadlčík https://fedoramagazine.org/author/frostyx/)
|
||||
@ -16,13 +16,13 @@ COPR 是个人软件仓库[集合][2],它不在 Fedora 中。这是因为某
|
||||
|
||||
本文介绍了 COPR 中一些有趣的新项目。如果你第一次使用 COPR,请参阅 [COPR 用户文档][3]。
|
||||
|
||||
## [][4] Blanket
|
||||
### Blanket
|
||||
|
||||
[Blanket][5] 是一款播放背景声音的应用,它可能会提高你的注意力,提高你的工作效率。另外,它还可以帮助你在嘈杂的环境中放松和入睡。无论现在是什么时间或你在哪里,Blanket 都可以让你在鸟鸣时醒来,在友好的咖啡店聊天或遥远的城市交通的包围下工作,然后在外面下雨时像木头一样睡在壁炉旁边。还有其他流行的背景音选择,如粉色和白色噪音也可以选择。
|
||||
[Blanket][5] 是一款播放背景声音的应用,它可能会提高你的注意力,提高你的工作效率。另外,它还可以帮助你在嘈杂的环境中放松和入睡。无论何时何地,Blanket 都可以让你在鸟鸣中醒来,在咖啡店聊天声或远离城市交通喧嚣的友好氛围下工作,然后在外面淅淅沥沥的雨声中像木头一样沉睡在壁炉旁边。还有其他流行的背景音选择,如粉色和白色噪音。
|
||||
|
||||
![][6]
|
||||
|
||||
### [][7] 安装说明
|
||||
#### 安装说明
|
||||
|
||||
目前[仓库][8]为 Fedora 32 和 33 提供了 Blanket。要安装它,请使用以下命令:
|
||||
|
||||
@ -31,47 +31,46 @@ sudo dnf copr enable tuxino/blanket
|
||||
sudo dnf install blanket
|
||||
```
|
||||
|
||||
## [][9] k9s
|
||||
### k9s
|
||||
|
||||
[k9s][10] 是一个管理 Kubernetes 集群的命令行工具。它允许你列出正在运行的 pod 并与之交互,读取它们的日志,挖掘已使用的资源,并总体上使操作 Kubernetes 更轻松。凭借其通过插件和可定制的用户界面的可扩展性,_k9s_ 受到有经验用户的欢迎。
|
||||
[k9s][10] 是一个管理 Kubernetes 集群的命令行工具。它可以让你列出正在运行的 pod 并与之交互,读取它们的日志,挖掘已使用的资源,并总体上使操作 Kubernetes 更轻松。通过插件和可定制的用户界面的可扩展性,k9s 受到有经验用户的欢迎。
|
||||
|
||||
|
||||
![][11]
|
||||
|
||||
有关[更多预览截图][12],请参见[项目页面][10]。
|
||||
|
||||
### [][13] 安装说明
|
||||
#### 安装说明
|
||||
|
||||
目前[仓库][14]为 Fedora 32、33、Fedora Rawhide 以及 EPEL 7、8、Centos Stream 等提供 _k9s_。要安装它,请使用以下命令:
|
||||
目前[仓库][14]为 Fedora 32、33、Fedora Rawhide 以及 EPEL 7、8、Centos Stream 等提供 k9s。要安装它,请使用以下命令:
|
||||
|
||||
```
|
||||
sudo dnf copr enable luminoso/k9s
|
||||
sudo dnf install k9s
|
||||
```
|
||||
|
||||
## [][15] rhbzquery
|
||||
|
||||
[rhbzquery][16] 是一个简单的查询 Fedora Bugzilla 的工具。它提供了一个指定搜索查询的接口,但它并不在命令行中列出结果,而是由 _rhbzquery_ 生成 Bugzilla 的 URL,并在浏览器中打开。
|
||||
### rhbzquery
|
||||
|
||||
[rhbzquery][16] 是一个简单的查询 Fedora Bugzilla 的工具。它提供了一个指定搜索查询的界面,但它并不在命令行中列出结果,而是由 rhbzquery 生成 Bugzilla 的 URL,并在浏览器中打开。
|
||||
|
||||
![][17]
|
||||
|
||||
### [][18] 安装说明
|
||||
#### 安装说明
|
||||
|
||||
目前[仓库][19]为 Fedora 32、33 和 Fedora Rawhide 提供 *rhbzquery*。要安装它,请使用以下命令:
|
||||
目前[仓库][19]为 Fedora 32、33 和 Fedora Rawhide 提供 rhbzquery。要安装它,请使用以下命令:
|
||||
|
||||
```
|
||||
sudo dnf copr enable petersen/rhbzquery
|
||||
sudo dnf install rhbzquery
|
||||
```
|
||||
|
||||
## [][20] gping
|
||||
### gping
|
||||
|
||||
[gping][21] 是一个比标准的 _ping_ 命令更有视觉吸引力的选择,因为它以图表的形式显示结果。也可以同时 ping 多个主机,以方便比较它们的响应时间。
|
||||
[gping][21] 是一个比标准的 `ping` 命令更有视觉吸引力的选择,因为它以图表的形式显示结果。也可以同时 ping 多个主机,以方便比较它们的响应时间。
|
||||
|
||||
![][22]
|
||||
|
||||
### [][23] 安装说明
|
||||
#### 安装说明
|
||||
|
||||
目前[仓库][24]为 Fedora 32、33、Fedora Rawhide 以及 EPEL 7 和 8 提供了 gping。要安装它,请使用以下命令:
|
||||
|
||||
@ -87,7 +86,7 @@ via: https://fedoramagazine.org/4-cool-new-projects-to-try-in-copr-from-december
|
||||
作者:[Jakub Kadlčík][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/) 荣誉推出
|
||||
|
@ -0,0 +1,54 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-12967-1.html)
|
||||
[#]: subject: (4 reasons businesses adopted open source in 2020)
|
||||
[#]: via: (https://opensource.com/article/20/12/open-source-survey)
|
||||
[#]: author: (Chris Grams https://opensource.com/users/cgrams)
|
||||
|
||||
2020 年企业采用开源的 4 个原因
|
||||
======
|
||||
|
||||
> 根据 Tidelift 的第三次开源管理调查,根据公司规模,出现了差异。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202012/30/062849dn8amhiait1cvnne.jpg)
|
||||
|
||||
Tidelift 的[第三次开源管理调查][2]发现,企业在大流行期间正在转向开源,44% 的组织报告他们将增加使用开源进行应用开发。
|
||||
|
||||
我们以前见过类似现象。在以前的经济衰退中,组织转向开源[以节省成本][3],并因[其它一些转型收益][4]而留下来。我们想了解哪些长期收益对不同规模的组织最有帮助。以下是我们发现的摘要。
|
||||
|
||||
**开源正在推动成本和时间的节约,同时提高效率。** 68% 的组织提到的一个关键驱动力是节约资金和开发时间,因为使用开源减少了开发人员从头开始编写新代码的时间。近半数(48%)报告称,它提高了应用开发和维护效率。拥有超过 1000 名员工的组织更有可能将此作为鼓励使用更多开源的原因(61%,而少于 1000 人的组织为 41%)。
|
||||
|
||||
![Graph showing reasons for using open source][5]
|
||||
|
||||
*(Tidelift ©2020)*
|
||||
|
||||
**在组织使用更多的开源的原因中,消除供应商锁定是一个重要原因。** 我们发现 40% 的受访者将这视为主要原因。用开源软件取代昂贵的专有软件,可以确保组织更加灵活,避免对供应商的依赖。同样,规模较大的组织也倾向于这个原因。在拥有 1000 名以上员工的组织中,有 50% 的组织将此作为主要优势。
|
||||
|
||||
**增加开发人员的满意度是使用更多开源的另一个原因,有 31% 的组织提到了这一点。** 随着企业对人才的激烈竞争,他们了解确保开发人员在工作中和使用的工具中感到快乐的价值。调查发现,开发人员使用的前三种语言是 JavaScript(78%)、Python(52%)和 Java(41%)。
|
||||
|
||||
**此外,随着开源使用量的增加,83% 的组织继续对其贡献,近一半的组织制定了管理贡献的政策。** 这些政策包括:在工作时间对组织使用但不赞助或管理的项目的贡献、对他们赞助或管理的项目的贡献、在个人时间对与工作无关的(个人)项目的贡献、以及在工作时间对与工作无关的(个人)项目的贡献。
|
||||
|
||||
虽然向开源的长期迁移仍在继续,但很明显,COVID-19 的影响可能正在加速这一进程,组织继续从使用和贡献中获得更深层次的价值。
|
||||
|
||||
更多信息,请查看 [2020 年开源管理调查][2]的所有调查结果。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/12/open-source-survey
|
||||
|
||||
作者:[Chris Grams][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/cgrams
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/metrics_graph_stats_blue.png?itok=OKCc_60D (Metrics and a graph illustration)
|
||||
[2]: https://www.tidelift.com/subscription/2020-managed-open-source-survey
|
||||
[3]: https://blog.tidelift.com/the-third-wave-of-open-source-migration?utm_source=opensource&utm_medium=referral&utm_campaign=2020-survey
|
||||
[4]: https://blog.tidelift.com/theres-one-thing-stopping-developers-from-using-open-source-even-more?utm_source=opensource&utm_medium=referral&utm_campaign=2020-survey
|
||||
[5]: https://opensource.com/sites/default/files/uploads/tidelift_reasons-for-using-open-source.png (Graph showing reasons for using open source)
|
@ -1,8 +1,8 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-12968-1.html)
|
||||
[#]: subject: (Font Manager: A Simple Open-Source App for GTK+ Desktop)
|
||||
[#]: via: (https://itsfoss.com/font-manager/)
|
||||
[#]: author: (Ankush Das https://itsfoss.com/author/ankush/)
|
||||
@ -10,11 +10,13 @@
|
||||
Font Manager:一个简单的 GTK+ 桌面的开源应用
|
||||
======
|
||||
|
||||
_**简介:一个非常简单的字体管理器应用,让你专注于调整 Linux 系统上的字体。**_
|
||||
![](https://img.linux.net.cn/data/attachment/album/202012/30/065754mx4363qxabe8y9z0.jpg)
|
||||
|
||||
如果你是一个有经验的 Linux 用户,你可能会利用终端或 [tweak 工具][1]来管理你的 Linux 系统的字体。
|
||||
> 一个非常简单的字体管理器应用,让你专注于调整 Linux 系统上的字体。
|
||||
|
||||
老实说,不管 GNOME tweak 工具有多有用,仅仅管理字体可能会让人有点受不了。因此,一个单独的应用可以很好地帮助你管理字体。
|
||||
如果你是一个有经验的 Linux 用户,你可能会利用终端或 [调整工具][1]来管理你的 Linux 系统的字体。
|
||||
|
||||
老实说,不管 GNOME 调整工具有多有用,但是用来管理字体可能会不太够用。因此,一个单独的应用可以很好地帮助你管理字体。
|
||||
|
||||
### Font Manager:一个帮助管理字体的开源应用
|
||||
|
||||
@ -22,7 +24,7 @@ _**简介:一个非常简单的字体管理器应用,让你专注于调整 L
|
||||
|
||||
Font Manager(这就是应用的字面名称)是一个专门帮助你管理字体的应用。
|
||||
|
||||
你可以获得字体家族的详细信息,可用的变体,以及根据字体的高度、宽度、间距等进行过滤和调整的功能。考虑到它是一个简单的应用,因此你找不到很多功能,但是我将在下面简要介绍一些功能。
|
||||
你可以获得字体族的详细信息、可用的变体,以及根据字体的高度、宽度、间距等进行过滤和调整的功能。考虑到它是一个简单的应用,因此你找不到很多功能,但是我将在下面简要介绍一些功能。
|
||||
|
||||
### Font Manager 的功能
|
||||
|
||||
@ -30,19 +32,17 @@ Font Manager(这就是应用的字面名称)是一个专门帮助你管理
|
||||
|
||||
* 可以添加字体
|
||||
* 可以删除字体
|
||||
* 根据家族、供应商、间距、高度等因素轻松过滤字体
|
||||
* 根据字体族、供应商、间距、高度等因素轻松筛选字体
|
||||
* 调整字体的缩放系数
|
||||
* 调整字体的抗锯齿(软度/锐度)
|
||||
* 添加字体源,以便在安装前进行预览
|
||||
* 提供快速管理的键盘快捷键
|
||||
* 开箱即用的谷歌字体集成
|
||||
* 获取关于家族字体中可用字符的详细信息、许可证、字体大小、供应商、文件类型、间距、宽度和样式
|
||||
|
||||
|
||||
* 获取关于字体族中可用字符的详细信息、许可证、字体大小、供应商、文件类型、间距、宽度和样式
|
||||
|
||||
![][4]
|
||||
|
||||
总的来说,你可以轻松安装或删除字体。但是,当你管理字体时,你会得到相当多的好处,如上面的截图所示。
|
||||
总的来说,你可以轻松安装或删除字体。但是,当你管理字体时,你会得到很多帮助,如上面的截图所示。
|
||||
|
||||
### 在 Linux 上安装 Font Manager
|
||||
|
||||
@ -56,7 +56,7 @@ sudo apt update
|
||||
sudo apt install font-manager
|
||||
```
|
||||
|
||||
如果你不喜欢 [PPAs][5](我更喜欢这样安装),你也可以在任何 Linux 发行版上安装一个[可用的 Flatpak 包][6]。
|
||||
如果你不喜欢 [PPA][5](我更喜欢这样安装),你也可以在任何 Linux 发行版上安装一个[可用的 Flatpak 包][6]。
|
||||
|
||||
你只需要在你的 Linux 系统上启用 Flatpak,然后在你的软件中心搜索它(如果它支持 Flatpak 集成的话),或者直接输入下面的命令安装它:
|
||||
|
||||
@ -69,13 +69,13 @@ flatpak install flathub org.gnome.FontManager
|
||||
|
||||
更多的安装说明,你可以参考它的[官网][9]和 [GitHub 页面][10]。
|
||||
|
||||
[下载 Font Manager][9]
|
||||
- [下载 Font Manager][9]
|
||||
|
||||
### 总结
|
||||
|
||||
Font Manager 是一个简单的解决方案,适用于任何基于 GTK+ 的桌面环境。主要用于 GNOME,但你在其他桌面环境使用它。
|
||||
|
||||
你可以得到很多有用的信息,同时可以添加或删除字体,我想这显然是一个不折不扣的字体管理器。
|
||||
你可以得到很多有用的信息,同时可以添加或删除字体,我想这显然是一个真正的字体管理器。
|
||||
|
||||
你对 Font Manager 有什么看法?在下面的评论中告诉我你的想法吧!
|
||||
|
||||
@ -86,7 +86,7 @@ via: https://itsfoss.com/font-manager/
|
||||
作者:[Ankush Das][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/) 荣誉推出
|
||||
|
252
published/20201216 How to use Kubernetes resource quotas.md
Normal file
252
published/20201216 How to use Kubernetes resource quotas.md
Normal file
@ -0,0 +1,252 @@
|
||||
[#]: collector: "lujun9972"
|
||||
[#]: translator: "larryzju"
|
||||
[#]: reviewer: "wxy"
|
||||
[#]: publisher: "wxy"
|
||||
[#]: url: "https://linux.cn/article-13006-1.html"
|
||||
[#]: subject: "How to use Kubernetes resource quotas"
|
||||
[#]: via: "https://opensource.com/article/20/12/kubernetes-resource-quotas"
|
||||
[#]: author: "Mike Calizo https://opensource.com/users/mcalizo"
|
||||
|
||||
Kubernetes 资源配额使用指南
|
||||
======
|
||||
|
||||
> 资源配额控制应用的 CPU 或内存使用情况,防止资源被过量使用或被抢占。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202101/12/125309xr0kskdrqv33vn4q.jpg)
|
||||
|
||||
当 Kubernetes 集群运行过一段时间或者在被开发者大量使用后,[Kubernetes][2] 资源(例如 CPU 和内存)的控制的问题就会显现出来。而在大多情况下只有集群出问题后,我们才会意识到资源控制的重要性。
|
||||
|
||||
Kubernetes 部署过程如果没有能充分考虑到将来的扩展性,资源类问题将会非常常见,此类问题与集群的管理和部署团队的经验有关。
|
||||
|
||||
如果不加以合理控制,一个暴力的应用或者开发者可能影响到共享该集群的所有业务,大家因此会相互埋怨、指责并保护性地抢占资源。这对于集群管理和开发人员都是非常难以处理的场景。
|
||||
|
||||
在 Kubernetes 环境中控制应用的计算资源使用有多种方式。大部分情况下,我们可以使用“资源控制”和“限制范围”。注意存储管理不在我们讨论范围之内,存储管理可以通过<ruby>持久卷<rt>Persistent Volume</rt></ruby> 件,以实现针对不同的存储控制需求。
|
||||
|
||||
资源配额是一种控制 Kubernetes 计算资源的方法。本文告诉你如何使用该功能来管理开发人员行为并控制应用的资源使用。
|
||||
|
||||
### 什么是资源配额
|
||||
|
||||
简而言之,[资源配额][3] 提供了限制每个命名空间资源消耗的约束条件,它们只能在命名空间级别上应用,这意味着它们可以应用于计算资源,并限制命名空间内的对象数量。
|
||||
|
||||
Kubernetes资源配额通过 `ResourceQuota` 对象来为每个命名空间设置资源配额,对以下对象类型的 CPU 和内存进行限制:
|
||||
|
||||
* <ruby>吊舱<rt>Pod</rt></ruby>
|
||||
* <ruby>服务<rt>Service</rt></ruby>
|
||||
* <ruby>机密信息<rt>Secret</rt></ruby>
|
||||
* <ruby>持久卷断言<rt>Persistent Volume Claim</rt></ruby>(PVC)
|
||||
* <ruby>配置映射<rt>ConfigMap</rt></ruby>
|
||||
|
||||
Kubernetes 通过 `request` 和 `limit` 两个参数对 CPU 和内存进行限制(参考 [LimitRange][4] 文档)。前者表示容器最小被保证资源,后者表示容器最大可用资源。实际上最大可用资源还受限于其它容器的实际使用情况。
|
||||
|
||||
下一张图片解释了配额中 `request` 和 `limit` 的区别:
|
||||
|
||||
![Requests and limits in Kubernetes resource quotas][5]
|
||||
|
||||
下面我们就通过一个例子来说明如何设置资源配额来创建约束,将应用程序限制在某些资源上,它还展示了实现资源配额以获得对 Kubernetes 的控制的有用性。
|
||||
|
||||
### 准备环境
|
||||
|
||||
首先你需要一个 Kubernetes 环境。以下是我使用 Kubernetes 环境:
|
||||
|
||||
* [Minikube][7] v1.14.2
|
||||
* Fedora 33 操作系统
|
||||
* 互联网接入
|
||||
|
||||
如果你想在 Linux 机器上通过 Minikube 搭建 Kubernetes 测试环境,可以参考 Bryant Son 的《[Minikube 入门][7]》 一文。Window 或者 macOS 用户可以参考[这篇文章][8]。
|
||||
|
||||
### 设置资源配额
|
||||
|
||||
这里我们仅展示 CPU 配额设置步骤,配置内存配额或两者的组合与之类似。
|
||||
|
||||
在生产环境中,CPU 是最需要被控制的资源,尤其是在多应用的场景下特别需要注意防止某些应用消耗太多 CPU 而影响到其它应用。
|
||||
|
||||
首先我们创建一个命名空间,在其中设置 CPU 配额:
|
||||
|
||||
```bash
|
||||
$ kubectl create namespace quota-test
|
||||
namespace/quota-test created
|
||||
```
|
||||
|
||||
准备 `cpu-quota.yaml` 文件,内容如下:
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: ResourceQuota
|
||||
metadata:
|
||||
name: test-cpu-quota
|
||||
spec:
|
||||
hard:
|
||||
requests.cpu: "100m"
|
||||
limits.cpu: "200m"
|
||||
```
|
||||
|
||||
应用 CPU 配额到 Kubernetes 集群:
|
||||
|
||||
```bash
|
||||
$ kubectl apply -f cpu-qouta.yaml
|
||||
resourcequota/test-cpu-quota created
|
||||
```
|
||||
|
||||
使用 `kubectl describe` 检查配额配置情况:
|
||||
|
||||
```bash
|
||||
$ kubectl describe resourcequota/test-cpu-quota --namespace quota-test
|
||||
Name: test-cpu-quota
|
||||
Namespace: quota-test
|
||||
Resource Used Hard
|
||||
-------- ---- ----
|
||||
limits.cpu 0 200m
|
||||
requests.cpu 0 100m
|
||||
```
|
||||
|
||||
在 `Used resources` 列中显示了当前情况,该列值会随着<ruby>吊舱<rt>Pod</rt></ruby>的部署而变化。
|
||||
|
||||
下面是我们来验证限额管理的场景。我们将在同一命名空间下部署三个不同的吊舱,为它们配置以不同的资源限制如下:
|
||||
|
||||
* PodA:第一个被实例化,使用 50% 可用 CPU 资源
|
||||
* PodB:第二个被实例化,使用其余 50% 可用 CPU 资源
|
||||
* PodC:没有可用 CPU 资源,因此不会被部署
|
||||
|
||||
#### 部署吊舱
|
||||
|
||||
PodA:
|
||||
|
||||
```bash
|
||||
$ kubectl create -n quota-test -f - << EOF
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: poda
|
||||
spec:
|
||||
containers:
|
||||
- name: quota-test
|
||||
image: busybox
|
||||
imagePullPolicy: IfNotPresent
|
||||
command: ['sh', '-c', 'echo Pod is Running ; sleep 5000']
|
||||
resources:
|
||||
requests:
|
||||
cpu: "50m"
|
||||
limits:
|
||||
cpu: "100m"
|
||||
restartPolicy: Never
|
||||
EOF
|
||||
```
|
||||
|
||||
部署 PodA 后,再次查看配额描述信息中的 `Used CPU` 信息:
|
||||
|
||||
```bash
|
||||
$ kubectl describe resourcequota/test-cpu-quota --namespace quota-test
|
||||
Name: test-cpu-quota
|
||||
Namespace: quota-test
|
||||
Resource Used Hard
|
||||
-------- ---- ----
|
||||
limits.cpu 100m 200m
|
||||
requests.cpu 50m 100m
|
||||
```
|
||||
|
||||
PodB:
|
||||
|
||||
```bash
|
||||
$ kubectl create -n quota-test -f - << EOF
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: podb
|
||||
spec:
|
||||
containers:
|
||||
- name: quota-test
|
||||
image: busybox
|
||||
imagePullPolicy: IfNotPresent
|
||||
command: ['sh', '-c', 'echo Pod is Running ; sleep 5000']
|
||||
resources:
|
||||
requests:
|
||||
cpu: "50m"
|
||||
limits:
|
||||
cpu: "100m"
|
||||
restartPolicy: Never
|
||||
EOF
|
||||
```
|
||||
|
||||
再次查看 CPU 资源使用,此时 PodB 启动后 CPU 限制已经达到上限:
|
||||
|
||||
```bash
|
||||
$ kubectl describe resourcequota/test-cpu-quota --namespace quota-test
|
||||
Name: test-cpu-quota
|
||||
Namespace: quota-test
|
||||
Resource Used Hard
|
||||
-------- ---- ----
|
||||
limits.cpu 200m 200m
|
||||
requests.cpu 100m 100m
|
||||
```
|
||||
|
||||
PodC:
|
||||
|
||||
试着创建 PodC,此时 CPU 配额已经被 PodA 和 PodB 用尽:
|
||||
|
||||
```bash
|
||||
$ kubectl create -n quota-test -f - << EOF
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: podc
|
||||
spec:
|
||||
containers:
|
||||
- name: quota-test
|
||||
image: busybox
|
||||
imagePullPolicy: IfNotPresent
|
||||
command: ['sh', '-c', 'echo Pod is Running ; sleep 5000']
|
||||
resources:
|
||||
requests:
|
||||
cpu: "5m"
|
||||
limits:
|
||||
cpu: "10m"
|
||||
restartPolicy: Never
|
||||
EOF
|
||||
```
|
||||
|
||||
正我们期望,第三个 Pod 无法被启动,配额限制了吊舱的创建:
|
||||
|
||||
```
|
||||
Error from server (Forbidden): error when creating "STDIN": pods "podc" is forbidden: exceeded quota: test-cpu-quota, requested: limits.cpu=10m,requests.cpu=5m, used: limits.cpu=200m,requests.cpu=100m, limited: limits.cpu=200m,requests.cpu=100m
|
||||
```
|
||||
|
||||
如我们的例子所示,定义合理的资源配额限制开发者行为对 Kubernetes 管理十分重要。
|
||||
|
||||
### 清理
|
||||
|
||||
删除刚才创建的命名空间 `quota-test`:
|
||||
|
||||
|
||||
```bash
|
||||
$ kubectl delete -n quota-test
|
||||
```
|
||||
|
||||
### 规划资源配额
|
||||
|
||||
Kubernetes 中提供多种方式来控制资源的抢占和使用,合理的规划和配置配额、限制范围和其它原生参数对保持集群的稳定性十分必要。
|
||||
|
||||
你应该十分谨慎地控制计算资源的资源配额,特别是关键业务的生产应用环境。
|
||||
|
||||
在规划资源配额时,开发人员的参与很重要,需要他们预估并给出最合理的资源使用值。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/12/kubernetes-resource-quotas
|
||||
|
||||
作者:[Mike Calizo][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[larryzju](https://github.com/larryzju)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/mcalizo
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/OSDC_secret_ingredient_520x292.png?itok=QbKzJq-N "Jars with food inside on a shelf"
|
||||
[2]: https://kubernetes.io/
|
||||
[3]: https://kubernetes.io/docs/concepts/policy/resource-quotas
|
||||
[4]: https://kubernetes.io/docs/concepts/policy/limit-range/
|
||||
[5]: https://opensource.com/sites/default/files/uploads/resourcequota_requests-limits.png "Requests and limits in Kubernetes resource quotas"
|
||||
[6]: https://creativecommons.org/licenses/by-sa/4.0/
|
||||
[7]: https://opensource.com/article/18/10/getting-started-minikube
|
||||
[8]: https://www.liquidweb.com/kb/how-to-install-minikube/
|
@ -0,0 +1,85 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (wxy)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-13002-1.html)
|
||||
[#]: subject: (6 ways this fullscreen text editor improves focus)
|
||||
[#]: via: (https://opensource.com/article/20/12/focuswriter)
|
||||
[#]: author: (Seth Kenlon https://opensource.com/users/seth)
|
||||
|
||||
全屏文本编辑器 Focuswriter 提高关注力的六种方式
|
||||
======
|
||||
|
||||
> 这款全屏编辑器可以帮助你设定写作目标,并将干扰降到最低,从而实现你的目标。
|
||||
|
||||
![双手打字机][1]
|
||||
|
||||
计算机的好处是,它们真的很擅长一心多用。
|
||||
|
||||
计算机的坏处是,它们实在太擅长一心多用。
|
||||
|
||||
无论你认为自己作为一个人,在多任务处理方面是好是坏,有时你需要一点帮助来集中注意力,尤其是当你试图撰写清晰和简明的交流信息时。而这正是开发 Focuswriter 的原因。
|
||||
|
||||
### 安装
|
||||
|
||||
在 Linux 上,你可以从 [Flathub][2] 以 Flatpak 包安装 Focuswriter。
|
||||
|
||||
在 Windows 或 Linux 上(如果你不使用 Flatpak),你可以[从它的网站安装 Focuswriter][3]。你也可以从源代码安装,它也可以从 Focuswriter 网站上获得。
|
||||
|
||||
### 使用 Focuswriter
|
||||
|
||||
不可否认,Focuswriter 实际上处于文本编辑器和文字处理器的重叠的地带。它的默认格式是 <ruby>开放文档文本<rt>Open Document Text</rt></ruby>(.odt)格式,所以它允许你设置文本样式和对齐文本、标记页眉,以及开启和关闭智能引号。但它的文字处理器功能也就到此为止,因为 Focuswriter 确实主要专注于_写作_,而不是对你所写的东西进行样式设计。
|
||||
|
||||
Focuswriter 以几种不同的方式鼓励专注力:
|
||||
|
||||
#### 吸引力
|
||||
|
||||
Focuswriter 看起来并不像你平常的电脑应用程序,更不像你平常的文本编辑器。当它启动时,它会在你的文档后面加载一个主题。主题一般是良性的 —— 默认是写字台,但也有星空、远方的风景等等。当然,你并不是要全神贯注于此主题,但它确实可以帮助你避免被徘徊于你的编辑器后面的其他应用窗口或电脑桌面分散注意力。因为它很容易定制,所以你几乎不大可能找不到你喜欢的主题。
|
||||
|
||||
![木质写字台背景主题上的 Focuswriter 白色盒子与灰色字样][4]
|
||||
|
||||
#### 音效
|
||||
|
||||
Focuswriter 使用起来其实很有趣。除了视觉主题外,它还有一个_可选的_打字机音频主题。启用后,每按一次键都会发出机械打字机按键的声音。当你按下**回车键**时,回车的声音令人满意,这是对你完成一段文字(或一行文字,如果你为了改善版本控制而每行写一句话)的奖励。
|
||||
|
||||
这个音频主题完全是可选的,默认情况下是不开启的。你可能会怀疑它的效果,但你不应该低估发出这些生产力声音而有具有现代文本编辑能力所带来的满足感。
|
||||
|
||||
#### 全屏显示
|
||||
|
||||
Focuswriter 不仅在默认情况下启动全屏,而且还从视图中隐藏了其菜单和其他部件。要访问主菜单栏,你要将光标放在屏幕顶部,直到它出现。右边隐藏了一个滚动条,左边隐藏了一个文档切换器小部件,底部则隐藏着一个状态栏。
|
||||
|
||||
#### 极简主义
|
||||
|
||||
Focuswriter 的编辑功能并不多。它没有高级搜索选项,也没有代码格式化或语法高亮的专门选项。它的设计是让你在文档中写入文本,而不是其他的什么。即使是上下文右键菜单也只提供基本的编辑功能(复制、剪切、粘贴等)或拼写检查选项。
|
||||
|
||||
#### 聚焦一行
|
||||
|
||||
Focuswriter 的另一个可选功能是它能够“灰化”除了你的当前文本行之外的所有文本行。这可以帮助你的眼睛懒洋洋地定位你当前的文字行,如果你不是一个盲打打字员,或者如果你正在抄写一些你手写在纸张上的东西,眼睛必须经常远离屏幕,这可能特别有用。
|
||||
|
||||
#### 目标追踪
|
||||
|
||||
你可以在 Focuswriter 的首选项中为自己设置一个每日字数目标或定时目标。当你工作时,你的进度会被跟踪,并显示在屏幕底部的状态栏中。除非你将光标悬停在它上面,否则它是隐藏在你的视野中的,所以你不会被迫沉迷于它,但它足够方便,可以帮助你保持进度。
|
||||
|
||||
### 即使你认为它很傻,也请尝试一下 Focuswriter
|
||||
|
||||
以前也听说过全屏文本编辑器,但我一直不觉得全屏文本编辑器对我来说有什么重要意义。毕竟,几乎所有的应用程序都可以全屏显示,而我个人也没有任何关注力问题。
|
||||
|
||||
不过在尝试过 Focuswriter 之后,我明白了一个好的全屏“关注力优先”文本编辑器的魅力所在。也许没有必要,但话又说回来,开源是如此的兴盛,我们有大量的冗余应用,这些应用功能略有差异,但实现上差异很大。Focuswriter 让写作变得有趣,它让工作变得愉快。下载它,设定一个目标,然后开始写作吧!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/12/focuswriter
|
||||
|
||||
作者:[Seth Kenlon][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/seth
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/typewriter-hands.jpg?itok=oPugBzgv (Typewriter with hands)
|
||||
[2]: https://flathub.org/apps/details/org.gottcode.FocusWriter
|
||||
[3]: https://gottcode.org/focuswriter/
|
||||
[4]: https://opensource.com/sites/default/files/uploads/focuswriter-31_days_focuswriter-opensource.png (Focuswriter white box with gray wording on wooden writing desk background theme)
|
186
published/20201222 Learn Rust by writing a simple game.md
Normal file
186
published/20201222 Learn Rust by writing a simple game.md
Normal file
@ -0,0 +1,186 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (wxy)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-12979-1.html)
|
||||
[#]: subject: (Learn Rust by writing a simple game)
|
||||
[#]: via: (https://opensource.com/article/20/12/learn-rust)
|
||||
[#]: author: (Moshe Zadka https://opensource.com/users/moshez)
|
||||
|
||||
通过编写一个简单的游戏来学习 Rust
|
||||
======
|
||||
|
||||
> 你可以尝试以多种语言编程一个简单的游戏来开始编程之路。
|
||||
|
||||
![海底的螃蟹 Ferris,Rust 编程语言的非官方标志][1]
|
||||
|
||||
当你想学习一门新的编程语言时,不妨关注一下编程语言的共同点。
|
||||
|
||||
* 变量
|
||||
* 表达式
|
||||
* 语句
|
||||
|
||||
这些概念是大多数编程语言的基础。一旦你理解了它们,你就可以开始弄清楚其余的东西。
|
||||
|
||||
因为编程语言通常具有相似性,一旦你懂了一种语言,你就可以通过理解其差异来学习另一种语言的基础知识。
|
||||
|
||||
学习新语言的一个好方法是使用一个你可以用来练习的标准程序。这可以让你专注于语言,而不是程序的逻辑。我在这一系列文章中使用了一个“猜数字”的程序,在这个程序中,电脑会在 1 到 100 之间选一个数字让你猜。程序一直循环,直到你猜对数字为止。
|
||||
|
||||
这个程序锻炼了编程语言的几个概念:
|
||||
|
||||
* 变量
|
||||
* 输入
|
||||
* 输出
|
||||
* 条件评估
|
||||
* 循环
|
||||
|
||||
这是学习一门新编程语言的很好的实践实验。
|
||||
|
||||
### 安装 Rust
|
||||
|
||||
你可以[使用 Rustup 安装一个 Rust 工具链][2],或者你可以[在线尝试 Rust][3] 而不在本地安装它。
|
||||
|
||||
如果你在本地安装,你应该定期用 `rustup update` 来更新它,以保持你的工具链的新鲜,并使用 `cargo update` 来保持你的库的最新版本。
|
||||
|
||||
### Rust 语言版本的猜数字
|
||||
|
||||
[Rust][4] 是一门赋予任何人构建可靠和高效的软件能力的语言。你可以通过编写一个 Rust 版本的“猜数字”游戏来探索 Rust。
|
||||
|
||||
第一步是编写一个 `Cargo.toml` 文件。你可以使用 `cargo new` 命令生成一个骨架 `Cargo.toml`。这几乎是开始一个 Rust 项目的最佳方式。
|
||||
|
||||
```
|
||||
$ cargo new guess
|
||||
$ cd guess
|
||||
$ ls -1
|
||||
Cargo.toml
|
||||
src/
|
||||
```
|
||||
|
||||
`Cargo.toml` 文件为你的包命名,并给它一些元数据,最重要的是,指明了它依赖于 `rand` [crate][5]。
|
||||
|
||||
```
|
||||
[package]
|
||||
name = "guess"
|
||||
version = "2020.11.0"
|
||||
authors = ["Moshe Zadka <moshez@opensource.com>"]
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
rand = "*"
|
||||
```
|
||||
|
||||
Rust 中的许多东西不是由语言或标准库提供的。取而代之的是,你可以从某个外部 crate 得到它们,这些 crate 可以做许多事情。
|
||||
|
||||
程序逻辑在 `src/main.rs` 中:
|
||||
|
||||
```
|
||||
use rand::Rng;
|
||||
use std::io::BufRead;
|
||||
|
||||
fn main() {
|
||||
let mut rng = rand::thread_rng();
|
||||
let random = rng.gen_range(1..101);
|
||||
println!("Guess a number between 1 and 100");
|
||||
for line in std::io::stdin().lock().lines() {
|
||||
let parsed = line.ok().as_deref().map(str::parse::<i64>);
|
||||
if let Some(Ok(guess)) = parsed {
|
||||
match guess {
|
||||
_ if guess < random => println!("Too low"),
|
||||
_ if guess > random => println!("Too high"),
|
||||
_ => {
|
||||
println!("That's right");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
代码的前两行声明你要做什么。在本例中,`rand::Rng` 生成一个猜测值,而 [trait][7] `std::io::BufRead` 使得可以从标准输入中读取。
|
||||
|
||||
Rust 代码的入口在 `main()` 函数中,所以下一步就是定义 `main()`。
|
||||
|
||||
要给一个变量赋值,先放 `let`,再放变量的名字,后面放 `=` 号。这样就创建了一个[不可变][8]变量。
|
||||
|
||||
Rust 中大多数变量都是不可变的,但是 `rng` 对象必须是可变的(`mut`)。例如,语句 `let random = 0` 给`random` 变量分配一个零值。
|
||||
|
||||
函数的第一行创建了一个线程安全的 `Rng` 对象,并将其分配给变量 `rng`。Rust 是建立在线程和内存安全的基础上的,所以你必须在开始写代码时就考虑到这些事情。
|
||||
|
||||
程序的下一行读取函数 `gen_range()` 的结果,并将其分配给名为 `random` 的变量。该函数取一个最小值(包含)和一个上界(不包含)。为了也包含上界,你可以用一个等号来标记较大的数字(例如,`1...=100`),或者你也可以像我在代码中做的那样,将上界设置为比你的预期最大值大 1。在这种情况下,该范围是 `1` 到 `100`,使得游戏刚好有足够的挑战性。
|
||||
|
||||
中央循环在 `std::io::stdin()` 中迭代行。由于有各种可能导致行不能读取的例外情况,Rust 要求你用一个 `Result` 来包裹一行。有时候可能无法将一行解析为一个整数。
|
||||
|
||||
这段代码使用条件模式匹配来忽略所有会导致错误的行:
|
||||
|
||||
```
|
||||
let parsed = line.ok().as_deref().map(str::parse::<i64>);
|
||||
if let Some(Ok(guess)) = parsed {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
第一行创建了一个 `Result<Option<i64>, ...>` 对象,因为它可能在读取或解析步骤中失败。由于下一行只在 `Some(Ok(guess))` 上匹配,每当一行的结果是一个不匹配的值时,它就会跳过 `if` 语句。这是一种强大的忽略错误的方法。
|
||||
|
||||
Rust 支持条件表达式和流程控制,比如循环。在“猜数字”游戏中,只要猜中的值不等于 `random`,Rust 就会继续循环。
|
||||
|
||||
`if` 语句的主体包含一个 Rust 的 `match` 语句的三向分支。虽然 `match` 最常用于模式匹配,但它也可以检查任意条件。在这种情况下是打印一个适当的信息,如果猜测是正确的,则中断(`break`)循环。
|
||||
|
||||
### 示例输出
|
||||
|
||||
现在你已经写好了你的 Rust 程序,你可以运行它来玩“猜数字”游戏。每次运行程序时,Rust 都会选择一个不同的随机数,所以继续猜,直到找到正确的数字。
|
||||
|
||||
```
|
||||
$ cargo run
|
||||
Compiling guess v2020.11.0 (/Users/mzadka/src/guess)
|
||||
Finished dev [unoptimized + debuginfo] target(s) in 0.70s
|
||||
Running `target/debug/guess`
|
||||
Guess a number between 1 and 100
|
||||
50
|
||||
Too high
|
||||
25
|
||||
Too high
|
||||
12
|
||||
Too low
|
||||
18
|
||||
Too high
|
||||
15
|
||||
Too high
|
||||
13
|
||||
Too low
|
||||
14
|
||||
That's right
|
||||
```
|
||||
|
||||
典型的做法是用 `cargo run` 来测试程序。最终,你可能会使用 `cargo build` 分成两个独立的步骤[构建一个可执行文件并运行它][9]。
|
||||
|
||||
### 学习 Rust
|
||||
|
||||
这个“猜数字”游戏是学习一门新的编程语言的一个很好的入门程序,因为它以一种相当直接的方式锻炼了几个常见的编程概念。通过在不同的编程语言中实现这个简单的游戏,你可以展示语言的一些核心概念,并比较它们的细节。
|
||||
|
||||
你有喜欢的编程语言吗?你会如何用它来写“猜数字”游戏呢?请关注本系列文章,看看你可能感兴趣的其他编程语言的例子吧!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/12/learn-rust
|
||||
|
||||
作者:[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/rust_programming_crab_sea.png?itok=2eWLz8A5 (Ferris the crab under the sea, unofficial logo for Rust programming language)
|
||||
[2]: https://www.rust-lang.org/learn/get-started
|
||||
[3]: https://play.rust-lang.org/
|
||||
[4]: https://www.rust-lang.org/
|
||||
[5]: https://doc.rust-lang.org/book/ch07-01-packages-and-crates.html
|
||||
[6]: mailto:moshez@opensource.com
|
||||
[7]: https://doc.rust-lang.org/rust-by-example/trait.html
|
||||
[8]: https://en.wikipedia.org/wiki/Immutable_object
|
||||
[9]: https://opensource.com/article/20/3/rust-cargo
|
275
published/20201222 Learn to use the Sed text editor.md
Normal file
275
published/20201222 Learn to use the Sed text editor.md
Normal file
@ -0,0 +1,275 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (wxy)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-12992-1.html)
|
||||
[#]: subject: (Learn to use the Sed text editor)
|
||||
[#]: via: (https://opensource.com/article/20/12/sed)
|
||||
[#]: author: (Seth Kenlon https://opensource.com/users/seth)
|
||||
|
||||
学习使用 Sed 文本编辑器
|
||||
======
|
||||
|
||||
> Sed 缺少通常的文本框,而是按照用户的命令直接写入到文件上。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202101/07/002353st8vgivu78yzp77v.jpg)
|
||||
|
||||
`sed` 命令是为 AT&T 最初的 Unix 操作系统第 7 版创建的,此后,可能每一个 Unix 和 Linux 操作系统都包含了它。`sed` 应用程序是一个 _流编辑器_,与文本编辑器不同的是,它不会打开一个视觉缓冲区,将文件的数据加载到其中进行处理。相反,它根据在终端输入的命令或脚本中的一系列命令,逐行对文件进行操作。
|
||||
|
||||
### 安装
|
||||
|
||||
如果你使用的是 Linux、BSD 或 macOS,那么你已经安装了 GNU 或 BSD 版的 `sed`。这是两个不同的原始 `sed` 命令的重新实现,虽然它们很相似,但也有一些小的区别。GNU `sed` 通常被认为是功能最丰富的 `sed`,而且它在这些平台上都可以广泛使用。
|
||||
|
||||
如果你找不到 GNU `sed`(在非 Linux 系统上通常被称为 `gsed`),那么你可以[从 GNU 网站上下载它的源代码][2]。安装 GNU `sed` 的好处是,可以使用它的额外功能,但它也可以被限制为只符合 `sed` 的 [POSIX][3] 规范,如果你需要移植性的话。
|
||||
|
||||
在 Windows 上,你可以用 [Chocolatey][5] 来[安装][4] GNU `sed`。
|
||||
|
||||
### Sed 如何工作
|
||||
|
||||
`sed` 应用程序一次只处理一行。因为它没有视觉显示,所以它在内存中创建了一个模式空间:一个包含输入流的当前行的空间(去掉任何尾部的换行符)。一旦填充了模式空间,你对 `sed` 的指令就会被执行。有时你的指令是有条件的,有时是无条件的,所以这些指令的结果取决于你如何使用 `sed`。
|
||||
|
||||
当命令结束时,`sed` 会将模式空间的内容打印到输出流中。默认的输出流是**标准输出**,但可以将其重定向到一个文件,甚至使用 `--in-place=.bak` 选项重定向到同一个文件中。
|
||||
|
||||
然后再从下一个输入行开始循环。
|
||||
|
||||
`sed`命令的语法是:
|
||||
|
||||
```
|
||||
$ sed --options [optional SCRIPT] [INPUT FILE or STREAM]
|
||||
```
|
||||
|
||||
#### 找到你要编辑的内容
|
||||
|
||||
在可视化编辑器中,你通常不需要考虑太多,就能在文本文件中找到你想要修改的内容。你的眼睛(或屏幕阅读器)会扫描文本,找到你想改变的单词或你想插入或删除文本的地方,然后你就可以开始输入了。而 `sed` 没有交互模式,所以你需要告诉它必须满足什么条件才能运行特定的命令。
|
||||
|
||||
在这些例子中,假设一个名为 `example.txt` 的文件包含了这样的文字:
|
||||
|
||||
```
|
||||
hello
|
||||
world
|
||||
This is line three.
|
||||
Here is the final line.
|
||||
```
|
||||
|
||||
#### 行号
|
||||
|
||||
指定行号告诉 `sed` 只对文件中的那一行进行操作。
|
||||
|
||||
例如,下面这条命令选择文件的第 1 行并打印出来。因为 `sed` 在处理后的默认操作也是打印一行到**标准输出**,这样做的效果就是重复第一行:
|
||||
|
||||
```
|
||||
$ sed '1p' example.txt
|
||||
hello
|
||||
hello
|
||||
world
|
||||
This is line three.
|
||||
Here is the final line.
|
||||
```
|
||||
|
||||
你也可以步进式指定行号。例如,`1~2` 表示每两行选择一行(“从第一行开始每两行选择一行”)。指令 `1~3` 表示从第一行开始,每三行选择一行:
|
||||
|
||||
```
|
||||
$ sed '1p' example.txt
|
||||
hello
|
||||
hello
|
||||
world
|
||||
This is line three.
|
||||
Here is the final line.
|
||||
Here is the final line.
|
||||
```
|
||||
|
||||
#### 行定位
|
||||
|
||||
你可以通过使用 `$` 作为选择器,只对文件的最后一行进行操作:
|
||||
|
||||
```
|
||||
$ sed '$p' example.txt
|
||||
hello
|
||||
world
|
||||
This is line three.
|
||||
Here is the final line.
|
||||
Here is the final line.
|
||||
```
|
||||
|
||||
在 GNU `sed` 中,你可以选择多行(例如,`sed '1,$p'` 打印第一行和最后一行)。
|
||||
|
||||
#### 反转
|
||||
|
||||
任何数字或位置的选择,你都可以用感叹号(`!`)字符反转。下面这将选择除第一行以外的所有行:
|
||||
|
||||
```
|
||||
$ sed '1!p' example.txt
|
||||
hello
|
||||
world
|
||||
world
|
||||
This is line three.
|
||||
This is line three.
|
||||
Here is the final line.
|
||||
Here is the final line.
|
||||
```
|
||||
|
||||
#### 模式匹配
|
||||
|
||||
你可以把模式匹配想象成文字处理器或浏览器中的**查找**操作。你提供一个词(一个 _模式_),然后选择了结果。模式匹配的语法是 `/pattern/`:
|
||||
|
||||
```
|
||||
$ sed '/hello/p' example.txt
|
||||
hello
|
||||
hello
|
||||
world
|
||||
This is line three.
|
||||
Here is the final line.
|
||||
$ sed '/line/p' example.txt
|
||||
hello
|
||||
world
|
||||
This is line three.
|
||||
This is line three.
|
||||
Here is the final line.
|
||||
Here is the final line.
|
||||
```
|
||||
|
||||
### 用 Sed 编辑
|
||||
|
||||
一旦你找到了你要编辑的内容,你就可以执行你想要的任何操作。你可以用 `sed` 中的命令来执行编辑。`sed` 中的命令不是 `sed` 命令本身。如果这样说有帮助的话,可以把它们看作是“动作”或“动词”或“指令”。
|
||||
|
||||
`sed` 中的命令是单个字母,例如前面例子中使用的**打印**命令的 `p`。它们一开始可能很难记忆,但和所有事情一样,你会随着练习而了解它们。
|
||||
|
||||
#### p 代表打印
|
||||
|
||||
`p` 指令打印当前模式空间中的任何内容。
|
||||
|
||||
#### d 用于删除
|
||||
|
||||
`d` 指令删除模式空间:
|
||||
|
||||
```
|
||||
$ sed '$d' example.txt
|
||||
hello
|
||||
world
|
||||
This is line three.
|
||||
$ sed '1d' example.txt
|
||||
world
|
||||
This is line three.
|
||||
Here is the final line.
|
||||
```
|
||||
|
||||
#### s 用于搜索和替换
|
||||
|
||||
`s` 命令搜索一个模式并将其替换为其他东西。这可能是 `sed` 最流行和最随意的用法,而且它通常是用户学习的第一个(有时也是唯一的)`sed` 命令。几乎可以肯定它是文本编辑中最有用的命令:
|
||||
|
||||
```
|
||||
$ sed 's/world/opensource.com/' example.txt
|
||||
hello
|
||||
opensource.com
|
||||
This is line three.
|
||||
Here is the final line.
|
||||
```
|
||||
|
||||
在你的替换文本中,也可以使用一些特殊的功能。例如,`\L` 将替换文本转换为小写,`\l` 则只转换下一个字符。还有其他一些功能,列在 `sed` 文档中(你可以用 `info sed` 命令查看)。
|
||||
|
||||
替换子句中的特殊字符 `&` 指的是匹配到的模式:
|
||||
|
||||
```
|
||||
$ sed 's/is/\U&/' example.txt
|
||||
hello
|
||||
world
|
||||
ThIS is line three.
|
||||
Here IS the final line.
|
||||
```
|
||||
|
||||
你也可以通过特殊的标志来影响 `s` 如何处理它找到的内容。`g`(应该是指 _全局_)标志告诉 `s` 对行上找到的所有匹配项进行替换,而不仅仅是第一个匹配项:
|
||||
|
||||
```
|
||||
$ sed 's/is/\U&/g' example.txt
|
||||
hello
|
||||
world
|
||||
ThIS IS line three.
|
||||
Here IS the final line.
|
||||
```
|
||||
|
||||
其他重要的标志还包括用一个数字来表示要影响第几个出现的匹配模式:
|
||||
|
||||
```
|
||||
$ sed 's/is/\U&/2' example.txt
|
||||
hello
|
||||
world
|
||||
This IS line three.
|
||||
Here is the final line.
|
||||
```
|
||||
|
||||
`w` 标志,后面跟着一个文件名,_只有_在有变化的情况下,才会将匹配的行写入文件:
|
||||
|
||||
```
|
||||
$ sed 's/is/\U&/w sed.log' example.txt
|
||||
hello
|
||||
world
|
||||
ThIS is line three.
|
||||
Here IS the final line.
|
||||
$ cat sed.log
|
||||
ThIS is line three.
|
||||
Here IS the final line.
|
||||
```
|
||||
|
||||
标志可以组合:
|
||||
|
||||
```
|
||||
$ sed 's/is/\U&/2w sed.log' example.txt
|
||||
hello
|
||||
world
|
||||
This IS line three.
|
||||
Here is the final line.
|
||||
$ cat sed.log
|
||||
This IS line three.
|
||||
```
|
||||
|
||||
### 脚本
|
||||
|
||||
有很多很棒的网站都有 `sed` “单行脚本”,它们给你提供了面向任务的 `sed` 命令来解决常见的问题。然而,自己学习 `sed` 可以让你写出自己的单行脚本,而且这些单行脚本可以根据你的具体需求来定制。
|
||||
|
||||
`sed` 的脚本可以在终端中写成一行,也可以保存到文件中,然后用 `sed` 本身执行。我倾向于把小脚本写成一个命令,因为我发现自己在现实生活中很少重复使用 `sed` 命令。当我写一个 `sed` 脚本时,通常都是针对一个文件的。例如,在写完这篇文章的初稿后,我用 `sed` 来规范 “sed” 的大小写,而这是我可能永远也不会再做的任务。
|
||||
|
||||
你可以向 `sed` 发出一系列不同的命令,用分号(`;`)分开。
|
||||
|
||||
```
|
||||
$ sed '3t ; s/line/\U&/' example.txt
|
||||
hello
|
||||
world
|
||||
This is LINE three.
|
||||
This is the final line.
|
||||
```
|
||||
|
||||
### 带括号的范围改变
|
||||
|
||||
你也可以用大括号(`{}`)限制哪些结果受到影响。当你将 `sed` 命令用大括号括起来时,它们只适用于特定的选择。例如,“line” 字出现在样本文本的两行中。你可以通过声明所需的匹配条件(`$` 表示最后一行),并将你希望执行的 `s` 命令放在紧随其后的括号中,强制 `sed` 只影响最后一行:
|
||||
|
||||
```
|
||||
$ sed '$ {s/line/\U&/}' example.txt
|
||||
hello
|
||||
world
|
||||
This is line three.
|
||||
This is the final LINE.
|
||||
```
|
||||
|
||||
### 学习 Sed
|
||||
|
||||
你可以用 `sed` 做的事情比本文所解释的多得多。我甚至还没有涉及到分支(`b`)、测试(`t`)、保留空格(`H`)和许多其他功能。就像 [ed][6] 一样,`sed` 可能不是你要用来创建文档的文本编辑器,甚至不是你需要做的每一个脚本任务中使用的文本编辑器,但它是你作为 POSIX 用户的一个强大的选择。学习 `sed` 命令的结构以及如何编写简短的脚本可以快速修改大量的文本。阅读 GNU `sed` 的`info` 页面,或者 BSD `sed` 的手册页,看看 `sed` 能为你做什么。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/12/sed
|
||||
|
||||
作者:[Seth Kenlon][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/seth
|
||||
[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]: http://www.gnu.org/software/sed/
|
||||
[3]: https://opensource.com/article/19/7/what-posix-richard-stallman-explains
|
||||
[4]: https://chocolatey.org/packages/sed
|
||||
[5]: https://opensource.com/article/20/3/chocolatey
|
||||
[6]: https://opensource.com/article/20/12/gnu-ed
|
122
published/20201224 5 reasons to use the Atom text editor.md
Normal file
122
published/20201224 5 reasons to use the Atom text editor.md
Normal file
@ -0,0 +1,122 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-13009-1.html)
|
||||
[#]: subject: (5 reasons to use the Atom text editor)
|
||||
[#]: via: (https://opensource.com/article/20/12/atom)
|
||||
[#]: author: (Seth Kenlon https://opensource.com/users/seth)
|
||||
|
||||
使用 Atom 文本编辑器的 5 个理由
|
||||
======
|
||||
|
||||
> Atom 是一个全面的环境,可以完成从基本到复杂的任务,适合从初学者到老用户。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202101/13/122223fnsn53dpzllwlclp.jpg)
|
||||
|
||||
现在漂亮的开源文本编辑器很常见,有 Adobe 的 [Brackets][2]、微软的 [VSCode][3] 和 GitHub 的 [Atom][4]。这些似乎都提供了类似的体验:现代化的界面、易于安装的插件,以及背后的一个大厂商支持。而且它们其实都很不错。那么 Atom 与其他超现代的文本编辑器有什么不同呢?与经典的老式编辑器如 [Vim][5] 或 [Emacs][6] 有何区别呢?
|
||||
|
||||
![Atom terminal with white text on dark grey background][7]
|
||||
|
||||
我用过很多文本编辑器,并且经过反思,我不得不承认,所有的文本编辑器基本上都差不多。在判断一个编辑器的功效时,只要它能做一件事:编辑文字,就能满足 80% 的要求。另外的 20% 则是额外的便利、额外的小玩意和花哨的功能。它们是很好的东西,但几乎不是必不可少的。
|
||||
|
||||
不过我经常回到 Atom,因为作为一个开源的用户,只要我愿意,我就可以奢侈地有很多应用使用。以下是我喜欢 Atom 的原因。
|
||||
|
||||
### 新手友好
|
||||
|
||||
我最喜欢 Atom 的一点是,它让人感觉很“正常”。我可以把 Atom 安装在任何人的电脑上,他们很快就可以开始输入了。没有新的键盘快捷键需要学习,没有严重偏离用户界面的惯例。如果我花几分钟时间向他们展示一些应用的强大功能,那么他们很快就会有能力安装新的插件,发现他们喜欢的有用功能。
|
||||
|
||||
它的独特之处在于让人感到与众不同,但又足够“安全”,足以让人相信(也确实如此)他们可以使用它。这是一条很难走的路线,但 Atom 做到了,我很欣赏它。
|
||||
|
||||
### 强大的扩展
|
||||
|
||||
当你启动应用就已经满足了大多数需求时,开源文本编辑器的一个主要“卖点”就是它的扩展。我习惯使用的编辑器是 [GNU Emacs][8],它的扩展功能多到令人瞠目结舌,可以提供从电子邮件客户端到视频游戏的所有功能。要做到这一点很难,老实说,我还没有看到其它能做到的编辑器。不过这说明了扩展是多么重要,而 Atom 有一套不错的插件。
|
||||
|
||||
有一些扩展可以为语言和格式添加语法高亮、添加动态格式检查、以及集成调试器、运行时环境、视频和音乐播放器控件等等。实际上,你可以让 Atom 成为你桌面的控制中心,你很少需要离开它。
|
||||
|
||||
### 语言和语法支持
|
||||
|
||||
我是 [Docbook][9] 的忠实粉丝。顺便说一下,也是它的简化前端 Asciidoc 的粉丝。当我评估一个编辑器时,Docbook 模式和 Asciidoc 支持是我的两个主要指标。虽然对 XML 的支持比较常见,但与特定模式的集成可能是一个高难度的任务,而且 Asciidoc 相对小众。Atom 的社区为我最喜欢的格式提供了很好的支持。
|
||||
|
||||
当然,我已经提到了 Atom 一般来说有很好的扩展,但无论你在输入什么语言,语法高亮都是一个重要的功能。再次感谢充满活力的社区,在 Atom 的软件包仓库中,丰富的语法高亮选项的是它的优点之一。
|
||||
|
||||
### 简单定制主题
|
||||
|
||||
Atom 让你制作自己的风格就像设计网站的风格一样简单,所以如果你会使用 CSS,你可以制作你自己的 Atom 主题。要创建你自己的主题,找到<ruby>软件包<rt>Package</rt></ruby>菜单。如果你没有看到<ruby>软件包<rt>Package</rt></ruby>菜单,先按 `Alt` 键,露出顶部菜单栏。在<ruby>软件包<rt>Package</rt></ruby>菜单中,将鼠标悬停在<ruby>软件包生成器<rt>Package Generator</rt></ruby> 上,然后选择<ruby>Generate Atom Syntax Theme<rt>生成 Atom 语法主题</rt></ruby>。这将打开一个新的项目,默认名为 “my-theme-syntax”。你可以把它命名为任何你想要的名字,但根据 Atom 惯例,它应该以 `-syntax` 结尾。
|
||||
|
||||
在你的新主题项目中,找到这些文件:`base.less`、`colors.less` 和 `syntax-variables.less`。这些文件定义了当语法激活时,特殊的关键字,甚至是背景和前景的颜色是如何显示的。因为它们都是从一个通用模板中继承的值,所以很容易修改。比如说:
|
||||
|
||||
```
|
||||
// Syntax styles
|
||||
|
||||
.syntax--comment {
|
||||
color: @light-gray;
|
||||
}
|
||||
|
||||
.syntax--keyword {
|
||||
color: @purple;
|
||||
|
||||
&.syntax--control {
|
||||
color: @purple;
|
||||
}
|
||||
|
||||
&.syntax--operator {
|
||||
color: @syntax-text-color;
|
||||
}
|
||||
|
||||
&.syntax--other.syntax--special-method {
|
||||
color: @blue;
|
||||
}
|
||||
|
||||
&.syntax--other.syntax--unit {
|
||||
color: @orange;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
以两个破折号结尾的值,如 `.syntax--keyword`,是语法高亮引擎识别的对象。当然,如果你想进一步开发你的自定义设置,你甚至可以创建你自己的语法定义(尽管这比 CSS 主题更费劲)。在 [flight-manual.atom.io][10] 上可以阅读所有关于修改 Atom 的方法。
|
||||
|
||||
### 灵活的工作流
|
||||
|
||||
Atom 有很多功能,默认情况下仅激活其中一部分。这意味着你可以决定你喜欢的工作方式,是否激活新的扩展并使用它们从根本上改变 Atom,还是只打开 Atom 的偏好并进行小的调整。你可以用 Atom 来写一本小说,也可以用它来写 Python 代码或技术文档或其他任何东西。
|
||||
|
||||
即使是它的 Git 集成也没有坚持让你使用可能会想到的显而易见的仓库(Github 赞助了 Atom)。它没有任何限制,而且它对每个人都同样有用,不管受众是谁。
|
||||
|
||||
### 安装
|
||||
|
||||
在 Linux、Windows 和 macOS 上,你可以 [从它的网站安装 Atom][11]。
|
||||
|
||||
另外,在 Linux 上,你可以从 [Flathub][12] 中,以 Flatpak 安装 Atom。
|
||||
|
||||
如果你想自己构建 Atom,你也可以 [从 Github 上的源码编译它][13]。
|
||||
|
||||
### 尝试 Atom
|
||||
|
||||
Atom 可以成为你的下一个文本编辑器、记事本和 IDE。它易于使用、易于配置、易于扩展,并提供了良好的用户体验。今天就下载 Atom,试试吧。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/12/atom
|
||||
|
||||
作者:[Seth Kenlon][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/seth
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/science_experiment_beaker_lab.png?itok=plKWRhlU (Science lab with beakers)
|
||||
[2]: https://opensource.com/article/20/12/brackets
|
||||
[3]: https://opensource.com/article/20/12/%C2%A0https://opensource.com/article/20/6/open-source-alternatives-vs-code
|
||||
[4]: https://opensource.com/article/17/5/atom-text-editor-packages-writers
|
||||
[5]: https://opensource.com/article/20/12/vi-text-editor
|
||||
[6]: https://opensource.com/article/20/12/emacs
|
||||
[7]: https://opensource.com/sites/default/files/uploads/atom-31_days-atom-opensource.png (Atom terminal with white text on dark grey background)
|
||||
[8]: https://opensource.com/article/20/2/who-cares-about-emacs
|
||||
[9]: https://opensource.com/article/17/9/docbook
|
||||
[10]: https://flight-manual.atom.io/
|
||||
[11]: https://atom.io
|
||||
[12]: https://flathub.org/apps/details/io.atom.Atom
|
||||
[13]: https://github.com/atom
|
128
published/20201225 How to use heredoc as a text editor.md
Normal file
128
published/20201225 How to use heredoc as a text editor.md
Normal file
@ -0,0 +1,128 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-12978-1.html)
|
||||
[#]: subject: (How to use heredoc as a text editor)
|
||||
[#]: via: (https://opensource.com/article/20/12/heredoc)
|
||||
[#]: author: (Seth Kenlon https://opensource.com/users/seth)
|
||||
|
||||
如何使用 heredoc 作为一个文本编辑器
|
||||
======
|
||||
|
||||
> 这个不起眼的终端功能在紧要关头提供一个文本编辑器。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202101/03/094710uucu3150at905t15.jpg)
|
||||
|
||||
在 Linux 和 Unix 的 shell 中有一个不为人知的功能,它能让你用 [cat][2] 命令打开一个 do-while 循环。它被称为 heredoc,无论你使用什么 shell,它都能让你或多或少地拥有一个文本编辑器。它的语法是:
|
||||
|
||||
```
|
||||
$ cat << EOF >> example.txt
|
||||
```
|
||||
|
||||
中间的字符串(`EOF`),本质上是一个停止循环的条件。也就是说,如果你在一行中单独输入它,循环就会结束。在循环过程中,无论你在终端中输入什么,都会被管道传送到目标文件中(在本例中)。
|
||||
|
||||
### 安装
|
||||
|
||||
只要你有一个终端,你就能够启动 heredoc。我在 [Bash][3]、[tsh][4] 和 Korn shell 中使用过这个语法技巧。
|
||||
|
||||
### 使用 heredoc
|
||||
|
||||
要打开一个 heredoc “会话”,你可以使用带重定向的 `cat` 命令。首先用终止字符串(常见约定是 `EOF`,代表 “End Of File”,但它实际上可以是任何字符串)指向 `cat` 命令。在终止字符串之后,将输出重定向到一个目标文件。然后,你就可以直接在终端中输入了,可以使用最常见的 shell 键盘快捷键来处理你的工作。当你在一行上输入你指定的终止字符串时,你的会话就结束了。你可以通过唯一的提示符(通常是 `>`)知道你是在一个 heredoc 循环中。
|
||||
|
||||
```
|
||||
$ cat << EOF >> example.txt
|
||||
> Everything you type here will be placed into example.txt when I type EOF on a line by itself. Until then, you can type...
|
||||
>
|
||||
> whatever...
|
||||
>
|
||||
> you want to type.
|
||||
>
|
||||
> EOF
|
||||
$
|
||||
```
|
||||
|
||||
在终端等待 `EOF` 时,你输入的所有内容都会被放入目标文件中,提示符被忽略,`EOF` 本身也不是文件的一部分。
|
||||
|
||||
```
|
||||
Everything you type here will be placed into example.txt when I type EOF on a line by itself. Until then, you can type...
|
||||
|
||||
whatever...
|
||||
|
||||
you want to type.
|
||||
```
|
||||
|
||||
在现实中,你可能不会用 heredoc 语法来代替一个正常的文本编辑器。它是一个很好的快速处理方式,可以输入多行,但超过 10 行左右就开始限制它的作用了。例如,如果不触发你 shell 的 [history][5] 功能,你就不能编辑以前的行。根据你的 shell 和配置,你可能需要先按向上键,然后按向下键来找回你的文本,然后用 `Ctrl+B` 来后退。
|
||||
|
||||
你的 shell 的大部分功能都能正常工作,但可能没有撤销功能,也没有什么错误恢复功能。
|
||||
|
||||
此外,即使是最简安装的系统,可能也至少安装了 [Vi][6] 或 [ed][7]。
|
||||
|
||||
然而 heredoc 还是很有用的!它比 `echo` 更灵活,当你在编写 shell 脚本时,它是不可缺少的。例如,想象一下你正在编写一个安装脚本,以便你可以自动安装一组自定义应用。其中一个应用没有生成 `.dekstop` 文件,所以它不会出现在你的应用菜单中。为了解决这个问题,你决定在安装时生成一个 `.desktop` 文件。
|
||||
|
||||
与其编写一个 `.desktop` 文件,然后作为安装脚本的外部依赖,不如在安装脚本中使用 heredoc:
|
||||
|
||||
```
|
||||
#!/bin/sh
|
||||
|
||||
VERSION=${VERSION:-x.y.z}
|
||||
PKGNAM=${VERSION:-example}
|
||||
PKG="${PKGNAM}"-"${VERSION}"-`arch`.tgz
|
||||
|
||||
# download package
|
||||
wget "${PKG}"
|
||||
tar txvf "${PKG}"
|
||||
|
||||
# use here doc to create missing .desktop file
|
||||
cat << EOF >> $HOME/.local/share/applications/example.desktop
|
||||
[Desktop Entry]
|
||||
Version=1.0
|
||||
Type=Application
|
||||
Name="${PKGNAM}"
|
||||
Comment="${PKGNAM}"
|
||||
Exec="${PKGNAM}" %F
|
||||
EOF
|
||||
|
||||
# insert the rest of an install script...
|
||||
```
|
||||
|
||||
你自动地将文本输入到了一个文件中,而不需要文本编辑器(当然,除了你用来写脚本的那个)。下面是生成的 `.desktop` 文件的样子:
|
||||
|
||||
```
|
||||
[Desktop Entry]
|
||||
Version=1.0
|
||||
Type=Application
|
||||
Name=example
|
||||
Comment=example
|
||||
Exec=example %F
|
||||
```
|
||||
|
||||
正如你所看到的,你可以在 heredoc 中使用变量,而且它们得到了正确的解析。`EOF` 字符串并没有出现在文件中,它只是标志着 heredoc 的结束。
|
||||
|
||||
### 比 echo 更好
|
||||
|
||||
heredoc 技术通常被认为比 `echo` 或 [printf][8] 更容易,因为一旦你“进入”了文档,你就可以自由地做任何你想做的事情。从这个意义上说,它是自由的,但与合适的文本编辑器相比,它是有限的。
|
||||
|
||||
使用 heredoc 来做快速笔记和 shell 脚本,再也不用为如何动态生成配置文件而烦恼了。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/12/heredoc
|
||||
|
||||
作者:[Seth Kenlon][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/seth
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/lenovo-thinkpad-laptop-window-focus.png?itok=g0xPm2kD (young woman working on a laptop)
|
||||
[2]: https://opensource.com/article/19/2/getting-started-cat-command
|
||||
[3]: https://opensource.com/article/20/4/bash-sysadmins-ebook
|
||||
[4]: https://opensource.com/article/20/8/tcsh
|
||||
[5]: https://opensource.com/article/20/6/bash-history-commands
|
||||
[6]: https://opensource.com/article/19/3/getting-started-vim
|
||||
[7]: https://opensource.com/article/20/12/gnu-ed
|
||||
[8]: https://opensource.com/article/20/8/printf
|
@ -0,0 +1,103 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (wxy)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-12982-1.html)
|
||||
[#]: subject: (Try GNU nano, a lightweight alternative to Vim)
|
||||
[#]: via: (https://opensource.com/article/20/12/gnu-nano)
|
||||
[#]: author: (Seth Kenlon https://opensource.com/users/seth)
|
||||
|
||||
试试 GNU nano,一个轻量级的 Vim 替代品
|
||||
======
|
||||
|
||||
> 轻巧而直接,nano 提供了一个简单、直观的编辑器,没有额外的麻烦。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202101/04/124300oklykg26z6wyhjey.jpg)
|
||||
|
||||
许多 Linux 发行版都捆绑了 [Vim][2] 作为默认的文本编辑器。这吸引了很多长期使用 Linux 的用户,反正那些不喜欢它的用户也可以在安装后及时更换。不过 Vim 是一个很有趣的编辑器,因为它是少数几个打开时的模式不允许输入文字的编辑器之一。这对任何用户来说都是一个令人费解的选择,对一个新用户来说也是很困惑的。
|
||||
|
||||
多亏了 GNU nano,才有了 Vim 之外的另一种轻量级终端文本编辑器,而且使用起来非常方便 —— 它的窗口底部列出了最重要的命令。
|
||||
|
||||
![Black nano terminal with white text][3]
|
||||
|
||||
### 安装
|
||||
|
||||
在 Linux 和 macOS 上,你可能已经安装了 GNU nano。你可以用 `which` 命令来验证:
|
||||
|
||||
```
|
||||
$ which nano
|
||||
/bin/nano
|
||||
```
|
||||
|
||||
如果你没有安装它,你可以从你的软件库中安装,或者你可以自己[下载它的源代码并编译][4]。
|
||||
|
||||
在 Windows 上,你可以使用 [Chocolatey][6] 来 [安装 GNU nano][5]。
|
||||
|
||||
### 启动 nano
|
||||
|
||||
从终端启动 nano,要么单独打开它:
|
||||
|
||||
```
|
||||
$ nano
|
||||
```
|
||||
|
||||
或者你也可以在你的命令后面加上一个文件的路径来打开一个特定的文件。如果你命名的文件还不存在,它就会被创建:
|
||||
|
||||
```
|
||||
$ nano example.txt
|
||||
```
|
||||
|
||||
### 使用 nano
|
||||
|
||||
nano,是个只要稍看一下,就会发现它是一个非常自明的东西。当你启动它的时候,nano 会打开一个空的缓冲区或者你要打开的文件。在屏幕下方,有一个功能列表和相应的键盘快捷键。更多的功能可以按 `Ctrl+G` 获取帮助。
|
||||
|
||||
以下是最重要的应用程序命令:
|
||||
|
||||
* `Ctrl+S` 保存你的工作
|
||||
* `Ctrl+W` 另存为
|
||||
* `Ctrl+R` 加载文件(读取)
|
||||
* `Ctrl+X` 退出
|
||||
* `Ctrl+G` 获得帮助
|
||||
|
||||
以下是最常用的编辑命令:
|
||||
|
||||
* `Alt+A` 选择(标记)一个区域
|
||||
* `Ctrl+K` 剪切标记的文字
|
||||
* `Ctrl+U` 粘贴(不剪切)
|
||||
* `Alt+F` 撤销
|
||||
* `Alt+E` 重做
|
||||
|
||||
### 可定制
|
||||
|
||||
nano 不像 Emacs 或 Vim 那样可扩展,但你可以在一个名为 `~/.nanorc` 的文件中进行一些重要的定制。在这个文件中,你可以设置全局的偏好,包括文字折行设置、颜色方案、行号等。你也可以创建你自己的键绑定,所以如果你想用 `Ctrl+V` 来代替 nano 默认的 `Ctrl+U` 来粘贴,你可以改变分配给 `paste` 函数的绑定。
|
||||
|
||||
```
|
||||
bind ^V paste all
|
||||
```
|
||||
|
||||
你可以在 [GNU nano 文档][7]中获得所有可用函数的列表。
|
||||
|
||||
### 简单而有效
|
||||
|
||||
GNU nano 是一款简单明了的文本编辑器。它易于使用,并提供了你所期望的所有文本编辑器的功能。试试吧,享受直观编辑的简单性。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/12/gnu-nano
|
||||
|
||||
作者:[Seth Kenlon][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/seth
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/osdc-docdish-typewriter-pink.png?itok=OXJBtyYf (A pink typewriter)
|
||||
[2]: https://opensource.com/article/20/12/vi-text-editor
|
||||
[3]: https://opensource.com/sites/default/files/uploads/nano-31_days-nano-opensource.png (Black nano terminal with white text)
|
||||
[4]: http://nano-editor.org
|
||||
[5]: https://opensource.com/article/20/12/%C2%A0https://chocolatey.org/packages/nano
|
||||
[6]: https://opensource.com/article/20/3/chocolatey
|
||||
[7]: https://www.nano-editor.org/dist/latest/nanorc.5.html
|
111
published/20201228 Learn Python by coding a simple game.md
Normal file
111
published/20201228 Learn Python by coding a simple game.md
Normal file
@ -0,0 +1,111 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-12973-1.html)
|
||||
[#]: subject: (Learn Python by coding a simple game)
|
||||
[#]: via: (https://opensource.com/article/20/12/learn-python)
|
||||
[#]: author: (Moshe Zadka https://opensource.com/users/moshez)
|
||||
|
||||
编写一个简单的游戏来学习 Python
|
||||
======
|
||||
|
||||
> 通过编写一个“猜数字”游戏来探索 Python(和其他编程语言)。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202101/01/105156uwwgx3tw2otntoow.jpg)
|
||||
|
||||
在这个系列中,我们要用不同的编程语言编写相同的应用,以比较各种语言是如何工作的,并说明使用标准测试程序是学习新编程好方法。
|
||||
|
||||
当你学习一门新的编程语言时,关注它们的共同点是件好事。变量、表达式和语句是大多数编程语言的基础。一旦你理解了这些概念,你就可以开始弄清楚其余的东西。
|
||||
|
||||
因为编程语言有许多相似之处,一旦你知道一种语言,你通常可以通过观察它与你所知道的语言的不同之处来学习另一种语言的基础知识。使用你用其他语言编写的标准测试程序,可以让你专注于语言,而不是程序的逻辑。
|
||||
|
||||
为了证明这点,我们正在测试如何用多种语言编写一个“猜数字”程序。计算机选择一个 1 到 100 之间的数字,然后让你猜。程序循环,直到你猜出正确答案。
|
||||
|
||||
“猜数字”程序练习了编程语言的几个概念:
|
||||
|
||||
* 变量
|
||||
* 输入
|
||||
* 输出
|
||||
* 条件判断
|
||||
* 循环
|
||||
|
||||
这是一个很好的学习新编程语言的实践实验。
|
||||
|
||||
### 用 Python 猜数字
|
||||
|
||||
用 [Python 软件基金会][2]的话来说。“Python 是一种解释性的、交互式的、面向对象的程序设计语言,它包含了模块、异常、动态类型、非常高层的动态数据类型和类。”它是一种很好的通用编程语言,从简单的脚本到复杂的 GUI 应用都很适用。
|
||||
|
||||
你可以通过编写一个版本的“猜数字”游戏来探索 Python。这是我的实现:
|
||||
|
||||
```
|
||||
import random as randomlib
|
||||
random = randomlib.randint(1, 100)
|
||||
print("Guess a number between 1 and 100")
|
||||
while True:
|
||||
guess = int(input())
|
||||
if guess < random:
|
||||
print("Too low")
|
||||
elif guess > random:
|
||||
print("Too high")
|
||||
else:
|
||||
print("That's right!")
|
||||
break
|
||||
```
|
||||
|
||||
要给一个变量赋值,请列出变量的名称,然后是 `=` 号。例如,语句 `random = 0` 给 `random` 变量分配了一个零值。
|
||||
|
||||
脚本的第一行就导入了 `random` 模块。由于本系列中的所有程序都使用 `random` 作为变量的名称,你可以使用 `import random as randomlib` 以别名导入它,以避免命名冲突。
|
||||
|
||||
很少有函数被内置到 Python 中,大多数函数必须从标准库中显式导入。`random` 标准库模块有生成各种随机值的功能。
|
||||
|
||||
脚本的第二行读取函数 `randint()` 的结果,并将其赋值给名为 `random` 的变量。函数需要两个参数:一个最小值和一个最大值。在本例中,范围是 `1` 到 `100`,以使游戏具有足够的挑战性。
|
||||
|
||||
你可以使用 `input()` 函数提示用户输入一个值。如果你写 `guess = int(input())`,Python 会等待用户输入一些文本,将其转换为一个整数,然后将值存储在 `guess` 变量中。
|
||||
|
||||
Python 支持条件表达式和循环等流程控制。在“猜数字”游戏中,只要 `guess` 中的值不等于 `random`,Python 就会继续循环。
|
||||
|
||||
如果猜测值小于随机数,Python 会打印 `Too low`,如果猜测值大于这个数字,Python 会打印 `Too high`。
|
||||
|
||||
### 示例输出
|
||||
|
||||
现在你已经写好了 Python 程序,运行它来玩“猜数字”游戏。每次运行程序,Python 都会随机选取一个不同的数字。为了完成这个游戏,你需要猜测,直到找到正确的数字:
|
||||
|
||||
```
|
||||
$ python guess.py
|
||||
Guess a number between 1 and 100
|
||||
50
|
||||
Too high
|
||||
25
|
||||
Too high
|
||||
12
|
||||
Too high
|
||||
7
|
||||
Too high
|
||||
3
|
||||
Too low
|
||||
5
|
||||
Too low
|
||||
6
|
||||
That's right!
|
||||
```
|
||||
|
||||
在学习一门新的编程语言时,这个“猜数字”游戏是一个很好的入门程序,因为它以一种相当直接的方式练习了几个常见的编程概念。通过在不同的编程语言中实现这个简单的游戏,你可以展示不同编程语言的一些核心概念,并比较每种语言的细节。
|
||||
|
||||
你有喜欢的编程语言吗?你会如何编写“猜数字”游戏?请关注本系列文章,看看你可能感兴趣的其他编程语言的例子吧!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/12/learn-python
|
||||
|
||||
作者:[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/python_programming_question.png?itok=cOeJW-8r (Python programming language logo with question marks)
|
||||
[2]: https://docs.python.org/3/faq/general.html#general-information
|
@ -0,0 +1,74 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-12993-1.html)
|
||||
[#]: subject: (Learn to use the JOE text editor on Linux)
|
||||
[#]: via: (https://opensource.com/article/20/12/joe)
|
||||
[#]: author: (Seth Kenlon https://opensource.com/users/seth)
|
||||
|
||||
学习在 Linux 上使用 JOE 文本编辑器
|
||||
======
|
||||
|
||||
> Joe's Own Editor (JOE)是一款简单易学和使用的通用文本编辑器。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202101/07/233204ps2fl3fffgmxzxqg.jpg)
|
||||
|
||||
我很喜欢那些能让你轻松学会如何使用的文本编辑器。GNU nano 是我最喜欢的例子:你启动 nano,你会在整个会话的窗口底部看到一个最常用的命令列表。Joe's Own Editor(简称 `joe`)是另一个很好的例子。
|
||||
|
||||
`joe` 编辑器使用了一个基于终端的界面,提供了简单的文本编辑功能和一个易于访问的帮助屏幕。它用 C 语言编写,体积小,只对 libc 有硬性依赖(ncurses 是可选的),并且采用 GPL 许可证。
|
||||
|
||||
### 安装
|
||||
|
||||
在 Linux 上,你也许能在你的发行版软件仓库中找到 JOE。虽然它有点小众,并不是所有的发行版都打包了它。如果是这样的话,你可以从 [SourceForge][2] 下载源码,然后自己编译。这是个简单的过程:
|
||||
|
||||
```
|
||||
$ ./configure
|
||||
$ make
|
||||
$ sudo make install
|
||||
```
|
||||
|
||||
### 使用 JOE
|
||||
|
||||
据其作者介绍,JOE 的灵感来自于一个叫 WordStar 的应用和 [GNU Emacs][3]。它的大部分基本编辑键都与 WordStar 的快捷键相同,编辑器本身也在努力向 WordStar 靠拢。JOE 也有 GNU Emacs 的一些键绑定和功能。这种两种灵感来源的混合有时会让人迷惑,但话又说回来,在任何情况下,让自己离开 Emacs(或你通常选择的文本编辑器)都会让人迷惑。重要的是,JOE 提供了帮助,而且很容易访问。
|
||||
|
||||
在 JOE 界面右上角,有一个持续的提示,你可以按 `Ctrl+K`,紧接着按 `H` 来查看帮助界面。这是一个切换键,所以一旦你激活它,帮助屏幕就会一直显示在你的编辑器窗口顶部,直到用同样的组合键(JOE 中的键盘符号为 `^KH`)解除。
|
||||
|
||||
### 键盘快捷键
|
||||
|
||||
尽管 JOE 的作者在模拟 WordStar 用户体验方面非常自豪,但我不得不承认,这对我来说是失落的。我从来没有听说过 WordStar,直到我在 JOE 的文档中读到了它,在我看来,它的键盘快捷键方案完全是任意的。有的用 `Ctrl+K` 作为转义序列的前缀,有的用 `Esc` 作为前缀,还有的完全不需要转义序列。我无法确定其中的逻辑。编辑操作和应用选项一样,都有可能需要或不需要转义序列,而且字母关联对我来说是没有什么意义(例如,`Ctrl+K D` 代表**另存为**)。
|
||||
|
||||
幸运的是,JOE 可以让你在键盘快捷键上作弊。安装后,JOE 会悄悄为 `joe` 可执行文件创建一些符号链接。包括:
|
||||
|
||||
* `jmacs` JOE 使用 Emacs 键绑定
|
||||
* `jpico` JOE 使用 Pico (或 GNU nano) 键绑定
|
||||
* `rjoe` JOE 的编辑只限于启动时传递给 JOE 的文件
|
||||
* `jstar` JOE 使用 WordStar 键绑定
|
||||
|
||||
![Black terminal with white text showing WordStar key bindings][4]
|
||||
|
||||
持久保留的帮助菜单仍然存在,所以如果你不清楚有哪些功能可以使用,可以通过屏幕右上方的帮助提示来参考。当然,在 Pico/nano 模式下,主要命令总是可见的。
|
||||
|
||||
### 尝试 JOE
|
||||
|
||||
JOE 并不是一个你永远不会离开的文本编辑器,它不会成为你的 IDE、电子邮件客户端、网络浏览器和文件管理器。事实上,它甚至可能不是你所有任务的主要文本编辑器。它专注于做好一件事,那就是成为一般的文本编辑。
|
||||
|
||||
JOE 拥有你所需要的所有基本功能,比如能够快速浏览你的文本、能够选择文本、复制和粘贴等等。试试 JOE 吧,使用你喜欢的符号链接。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/12/joe
|
||||
|
||||
作者:[Seth Kenlon][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/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://joe-editor.sourceforge.io/
|
||||
[3]: https://opensource.com/article/20/12/emacs
|
||||
[4]: https://opensource.com/sites/default/files/uploads/joe-jstar-31_days-joe-opensource.png (Black terminal with white text showing WordStar key bindings)
|
@ -0,0 +1,167 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (wxy)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-12985-1.html)
|
||||
[#]: subject: (Practice programming in C++ by writing a simple game)
|
||||
[#]: via: (https://opensource.com/article/20/12/learn-c-game)
|
||||
[#]: author: (Seth Kenlon https://opensource.com/users/seth)
|
||||
|
||||
编写一个简单的游戏来练习用 C++ 编程
|
||||
======
|
||||
|
||||
> C++ 语言很复杂,但它可以教会你很多关于数据类型、内存管理和代码链接的知识。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202101/05/110821dwzztxchazhto8ko.jpg)
|
||||
|
||||
学习一门编程语言有几种方法。如果你是编码新手,你通常会学习一些基本的计算机编码概念,并尝试应用它们。如果你已经知道如何用另一种语言进行编码,你可以重新学习编码概念在新语言中是如何表达的。
|
||||
|
||||
不管是哪种情况,学习这些新原理的便捷方法是创建一个简单的猜谜游戏。这会迫使你了解一门语言如何接收输入和发送输出,如何比较数据,如何控制程序的流程,以及如何利用条件来影响结果。它还确保你知道一门语言是如何组织其代码的;例如,Lua 或 [Bash][2] 可以很容易地作为脚本运行,而 [Java][3] 则需要你创建一个类。
|
||||
|
||||
在本文中,我将演示如何用 [C++][4] 在终端上实现猜谜游戏。
|
||||
|
||||
### 安装依赖关系
|
||||
|
||||
要跟上本文的步伐,你需要 C++ 和一个编译器。
|
||||
|
||||
在 Linux 上,你可以通过从你的发行版软件仓库中安装 Qt Creator IDE 来获得你所需要的一切。
|
||||
|
||||
在 Fedora、CentOS 或 RHEL 上:
|
||||
|
||||
```
|
||||
$ sudo dnf install qt-creator
|
||||
```
|
||||
|
||||
在 Debian、Ubuntu、Chromebook 或类似的系统上:
|
||||
|
||||
```
|
||||
$ sudo apt install qtcreator
|
||||
```
|
||||
|
||||
本文并没有使用 Qt Creator IDE,但它是一个安装你所需要的一切的简单方法,对于复杂的 C++ 项目(包括那些带有 GUI 的项目),它是一个必不可少的工具。在 macOS 或 Windows 上,按照 Qt 网站上的[安装说明][5]进行安装。
|
||||
|
||||
### 设置包含和命名空间
|
||||
|
||||
C++ 的核心语言是精简的。即使是一个简单的应用程序也需要使用额外的库。这个应用程序使用 [iostream][6] 来获得对 `cout` 和 `cin` 关键字的访问。
|
||||
|
||||
另外,确保程序使用 `std` 命名空间:
|
||||
|
||||
```
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
```
|
||||
|
||||
这并不是绝对必要,但如果不将命名空间设置为 `std`,所有来自 `iostream` 库的关键字都需要一个命名空间前缀。例如,我不能写作 `cout`,而是要写作 `std::cout`。
|
||||
|
||||
C++ 中的语句以分号结束。
|
||||
|
||||
### 创建一个函数
|
||||
|
||||
每个 C++ 应用程序至少需要一个函数。一个 C++ 应用程序的主函数必须称为 `main`,它必须返回一个整数(`int`),这符合 [POSIX][7] 的期望,即一个进程在成功时返回 0,而在失败时返回其他值。你可以通过为它提供返回类型和名称来创建一个新函数。
|
||||
|
||||
```
|
||||
int main() {
|
||||
// code goes here
|
||||
}
|
||||
```
|
||||
|
||||
### 实现程序逻辑
|
||||
|
||||
游戏代码必须首先产生一个随机数供玩家猜测。在 C++ 中,你可以通过建立一个用于生成伪随机数的*种子*来实现。一个简单的种子就是当前的时间。一旦有了种子,你就可以得到一个在 1 和 100 之间的数字。通过调用 `rand` 函数,并设置上限值 100 来产生一个从 0 到 99 的随机数,所以无论选择了什么数字都要加 1,并将结果分配给一个名为 `number` 的变量。你还必须声明一个变量来保存玩家的猜测值。为了清楚起见,我称这个变量为 `guess`。
|
||||
|
||||
这个示例代码还包括一个调试语句,告诉你随机数到底是什么。这对于猜测游戏来说不是很好,但它使测试速度快了很多。以后,你可以删除这一行,或者直接在行前面用 `//` 注释出来:
|
||||
|
||||
```
|
||||
srand (time(NULL));
|
||||
int number = rand() % 100+1;
|
||||
int guess = 0;
|
||||
|
||||
cout << number << endl; //debug
|
||||
```
|
||||
|
||||
### 增加 do-while 和 if 语句
|
||||
|
||||
C++ 中的 `do-while` 语句以关键字 `do` 开头,并将你希望 C++ 做的所有事情用括号括起来。用 `while` 关键字结束语句,后面是必须满足的条件(括号内):
|
||||
|
||||
```
|
||||
do {
|
||||
// code here
|
||||
} while ( number != guess );
|
||||
```
|
||||
|
||||
游戏代码出现在 `if`、`else if` 和 `else` 语句之间,为玩家提供提示。
|
||||
|
||||
首先,用 `cout` 语句提示玩家猜测。`cout` 函数将输出打印到 `stdout` 上。因为 `cout` 语句没有连着 `endl`(endline)函数,所以没有换行。紧接着这个 `cout` 语句,通过使用 `cin` 函数告诉 C++ 等待输入。正如你所猜测的那样,`cin` 等待来自 `stdin` 的输入。
|
||||
|
||||
接下来,程序进入 `if` 控制语句。如果玩家的猜测大于 `number` 变量中包含的伪随机数,那么程序就会打印出一个提示,后面是一个换行符。这就中断了 `if` 语句,但 C++ 仍然被困在 `do-while` 循环中,因为它的条件(`number` 变量等于 `guess`)还没有满足。
|
||||
|
||||
如果玩家的猜测小于 `number` 变量中包含的伪随机数,那么程序就会打印出一个提示,后面是一个换行符。这再次中断了 `if` 语句,但程序仍然被困在 `do-while` 循环中。
|
||||
|
||||
当 `guess` 等于 `number` 时,最终满足关键条件,触发 `else` 语句,`do-while` 循环结束,程序结束:
|
||||
|
||||
```
|
||||
do {
|
||||
cout << "Guess a number between 1 and 100: ";
|
||||
cin >> guess;
|
||||
|
||||
if ( guess > number) { cout << "Too high.\n" << endl; }
|
||||
else if ( guess < number ) { cout << "Too low.\n" << endl; }
|
||||
else {
|
||||
cout << "That's right!\n" << endl;
|
||||
exit(0);
|
||||
} // fi
|
||||
} while ( number != guess );
|
||||
return 0;
|
||||
} // main
|
||||
```
|
||||
|
||||
### 构建代码和玩游戏
|
||||
|
||||
你可以用 GCC 构建你的应用程序:
|
||||
|
||||
```
|
||||
$ g++ -o guess.bin guess.cpp
|
||||
```
|
||||
|
||||
运行二进制文件试试:
|
||||
|
||||
```
|
||||
$ ./guess.bin
|
||||
74
|
||||
Guess a number between 1 and 100: 76
|
||||
Too high.
|
||||
|
||||
Guess a number between 1 and 100: 1
|
||||
Too low.
|
||||
|
||||
Guess a number between 1 and 100: 74
|
||||
That's right!
|
||||
```
|
||||
|
||||
成功了!
|
||||
|
||||
### 试试 C++ 吧
|
||||
|
||||
C++ 语言很复杂。为终端编写 C++ 应用程序可以让你学到很多关于数据类型、内存管理和代码链接的知识。试着用 C++ 编写一个有用的实用程序,看看你能发现什么!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/12/learn-c-game
|
||||
|
||||
作者:[Seth Kenlon][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/seth
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/BIZ_question_B.png?itok=f88cyt00 (A bunch of question marks)
|
||||
[2]: https://opensource.com/article/20/12/learn-bash
|
||||
[3]: https://opensource.com/article/20/12/learn-java-writing-guess-number-game
|
||||
[4]: https://www.cplusplus.com/
|
||||
[5]: https://www.qt.io/product/development-tools
|
||||
[6]: http://www.cplusplus.com/reference/iostream/
|
||||
[7]: https://opensource.com/article/19/7/what-posix-richard-stallman-explains
|
@ -0,0 +1,166 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (wxy)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-12976-1.html)
|
||||
[#]: subject: (Bring an old MacBook back to life with Linux)
|
||||
[#]: via: (https://opensource.com/article/20/12/linux-macbook)
|
||||
[#]: author: (Eric D. Schabell https://opensource.com/users/eschabell)
|
||||
|
||||
用 Linux 让旧 MacBook 重获新生
|
||||
======
|
||||
|
||||
> 花上一小时,用 Fedora 让一台过时的 Mac 重新有用。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202101/02/102156tjj8g7r272j74huj.jpg)
|
||||
|
||||
最近,我偶然找到了一台 2011 年底的老款 13 英寸 MacBook Pro,有 125GB SSD 和 8GB 内存。我曾带着这台机器去世界各地旅行,当年,我开了很多场会议、研讨会或演示,分享 JBoss 技术带来的各种 AppDev 优势。
|
||||
|
||||
在验证了它的电池能用,充了电,重新安装了一个新的 OS X 之后,我发现 Safari 浏览器的版本受限于旧的安全规范,这意味着它现在无法连接到很多 HTTPS 网站。这就使得这个解决方案失效了。
|
||||
|
||||
这个老伙计该怎么处理呢?
|
||||
|
||||
自从我作为开发人员专门在 Linux 工作站上工作以来已经有几年了。我只使用 Fedora,所以我决定尝试在这台 MacBook Pro 上安装它的最新版本。
|
||||
|
||||
我只花了一个多小时就用下面的步骤让 [Fedora 33][2] 在这台笔记本上工作了。
|
||||
|
||||
### 下载 Fedora 33 并创建一个临场 USB
|
||||
|
||||
第一步是找到正确的安装 Fedora 的方法。这台机器有一个 CD 插槽,所以可以刻录一个 ISO 并从它启动,但我选择直接使用可启动的 USB 方式。
|
||||
|
||||
我登上了另一台 MacBook,访问了 [Fedora Workstation 网站][3],它有 Fedora Media Writer 的链接。点击你的机器类型的图标(在我的例子中是苹果标志),你会得到一个安装包。
|
||||
|
||||
![Fedora Media Writer 下载界面][4]
|
||||
|
||||
开始安装,可以看到一个引导你完成安装过程的图形用户界面(GUI)。选择 Fedora Workstation 33 选项。
|
||||
|
||||
![在 Fedora Media Writer 中下载 Fedora Workstation][6]
|
||||
|
||||
接下来,选择右上角的“Create Live USB”选项。
|
||||
|
||||
![创建 Live USB 的按钮][7]
|
||||
|
||||
镜像将开始下载,你将看到一个下拉菜单来选择安装位置。
|
||||
|
||||
![下载 Fedora Workstation][8]
|
||||
|
||||
插入一个有足够空间的 U 盘,下载完成后,就可以选择它并在上面安装镜像。完成后,关闭 GUI,取出 U 盘。
|
||||
|
||||
### 安装 Linux
|
||||
|
||||
将你创建的 U 盘插入 MacBook Pro 左侧的端口,并按住 `Cmd` 键左侧的 `Option`(或 `Alt`)键的同时重新启动。这将打开一个启动机器的选项菜单:使用 EFI 选项,因为那是 USB 镜像。
|
||||
|
||||
笔记本电脑将从 USB 设备启动,你可以按照[正常的 Fedora 安装][9]过程进行。如果你能将 MacBook Pro 插入网线连接,会有帮助,因为它的 Broadcom WiFi 设备无法开箱即用。
|
||||
|
||||
![MacBook Pro][10]
|
||||
|
||||
你现在也可以将 Fedora 安装到你的硬盘上,并将它永久地放在你的机器上。
|
||||
|
||||
![在 MacBook Pro 上安装 Fedora][11]
|
||||
|
||||
一旦安装程序完成,重新启动机器,Fedora 33 现在应该是启动选项。
|
||||
|
||||
![MacBook Pro 启动到 Fedora][12]
|
||||
|
||||
唯一缺少的就是 WiFi 驱动,所以要保持网线连接,安装你正在运行的内核的开发包,并为该内核构建 `broadcom-wl` 驱动。
|
||||
|
||||
验证你需要用于 WiFi 的卡。
|
||||
|
||||
```
|
||||
$ lspci -vnn -d 14e4:
|
||||
```
|
||||
|
||||
在输出中会有几项,包括如下内容:
|
||||
|
||||
```
|
||||
Network controller [0280]: Broadcom Inc. and subsidiaries....
|
||||
|
||||
Subsystem: Apple Inc. AirPort Extreme...
|
||||
```
|
||||
|
||||
安装一个仓库来拉取 Broadcom 相关的部分:
|
||||
|
||||
```
|
||||
$ su -c 'dnf install -y http://download1.rpmfusion.org/nonfree/fedora/rpmfusion-nonfree-release-$(rpm -E %fedora).noarch.rpm'
|
||||
```
|
||||
|
||||
接下来的部分很有趣:如果你查看正在运行的内核时,你会看到 `v5.9.8-200.fc33`,但是你要使用开发内核包来构建你的 Broadcom 无线驱动。所以,你需要安装 `v5.8.15-301.fc33`(在写这篇文章的时候可用)。使用 `uname -r` 检查它们,并使用 `sudo dnf list kernel` 列出已安装的内核包:
|
||||
|
||||
```
|
||||
$ sudo dnf list kernel
|
||||
kernel.x86_64 5.8.15-301.fc33
|
||||
kernel.x86_64 5.9.8-200.fc33
|
||||
```
|
||||
|
||||
安装开发包:
|
||||
|
||||
```
|
||||
$ sudo dnf install -y akmods kernel-devel-5.8.15-301.fc33
|
||||
```
|
||||
|
||||
![安装开发包][13]
|
||||
|
||||
安装 Broadcom 无线软件包:
|
||||
|
||||
```
|
||||
$ sudo dnf install -y broadcom-wl
|
||||
```
|
||||
|
||||
构建内核模块:
|
||||
|
||||
```
|
||||
$ sudo akmods
|
||||
```
|
||||
|
||||
![构建内核模块][14]
|
||||
|
||||
重新启动你的机器,你应该可以看到无线驱动(`wl`)。
|
||||
|
||||
```
|
||||
$ lsmod | grep wl
|
||||
```
|
||||
|
||||
在 Fedora 中设置你的无线连接:
|
||||
|
||||
![设置无线连接][15]
|
||||
|
||||
这篇文章对我来说有些出乎意料,但我希望它能帮助别人在周末享受一些老硬件的乐趣!
|
||||
|
||||
> 现在要走不寻常路了……在 2011 年的 Macbook Pro 上安装 [#Fedora][16]。祝我好运! [pic.twitter.com/zlsESnq2Px][17]。
|
||||
>
|
||||
> - Eric D. Schabell (@ericschabell) [2020 年 11 月 22 日][18]
|
||||
|
||||
*此文原载于 [Schabell.org][19],经许可转载。*
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/12/linux-macbook
|
||||
|
||||
作者:[Eric D. Schabell][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/eschabell
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/computer_desk_home_laptop_browser.png?itok=Y3UVpY0l (Digital images of a computer desktop)
|
||||
[2]: https://getfedora.org/en/
|
||||
[3]: https://getfedora.org/en/workstation/download/
|
||||
[4]: https://opensource.com/sites/default/files/uploads/fedoramediawriter.png (Fedora Media Writer download screen)
|
||||
[5]: https://creativecommons.org/licenses/by-sa/4.0/
|
||||
[6]: https://opensource.com/sites/default/files/uploads/fedoraworkstation33-installation.png (Fedora Workstation download in Fedora Media Writer)
|
||||
[7]: https://opensource.com/sites/default/files/uploads/create-live-usb.png (Create Live USB button)
|
||||
[8]: https://opensource.com/sites/default/files/uploads/download_fedora-workstation.png (Downloading Fedora Workstation)
|
||||
[9]: https://docs.fedoraproject.org/en-US/fedora/f33/install-guide/install/Booting_the_Installation/
|
||||
[10]: https://opensource.com/sites/default/files/uploads/macbook.jpeg (MacBook Pro)
|
||||
[11]: https://opensource.com/sites/default/files/uploads/macbook_install-fedora.jpeg (Installing Fedora on MacBook Pro)
|
||||
[12]: https://opensource.com/sites/default/files/uploads/macbook_fedora-boot.jpeg (MacBook Pro booting into Fedora)
|
||||
[13]: https://opensource.com/sites/default/files/uploads/install-development-packages.jpeg (Installing development packages)
|
||||
[14]: https://opensource.com/sites/default/files/uploads/build-kernel-module.jpeg (Building the kernel module)
|
||||
[15]: https://opensource.com/sites/default/files/uploads/wireless-setup.jpeg (Set up wireless connection)
|
||||
[16]: https://twitter.com/hashtag/Fedora?src=hash&ref_src=twsrc%5Etfw
|
||||
[17]: https://t.co/zlsESnq2Px
|
||||
[18]: https://twitter.com/ericschabell/status/1330434517883121665?ref_src=twsrc%5Etfw
|
||||
[19]: https://www.schabell.org/2020/11/installing-fedora33-on-macbook-pro-13inch-late-2011.html
|
@ -0,0 +1,150 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-12990-1.html)
|
||||
[#]: subject: (Show progress in your Python apps with tqdm)
|
||||
[#]: via: (https://opensource.com/article/20/12/tqdm-python)
|
||||
[#]: author: (Moshe Zadka https://opensource.com/users/moshez)
|
||||
|
||||
使用 tqdm 在 Python 应用中显示进度
|
||||
======
|
||||
|
||||
> 如果你的程序需要一段时间才能显示结果,可通过显示它的进度来避免让用户感到沮丧。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202101/06/230842thi8skahe68dqa3m.jpg)
|
||||
|
||||
阿拉米语,希伯来语和阿拉伯语中的闪米特语根 _q-d-m_ 通常与前进或进度有关。阿拉伯语 _taqaddum_ (تقدّم)的意思是“进度”。进度是很重要的。正如每部感觉良好的电影都会告诉你,旅程和目的地同样重要。
|
||||
|
||||
大多数程序都有一个明确的目标,一个期望的最终状态。有时,计算这个最终状态可能需要很长的时间。虽然计算机没有感情不在乎,但人却在乎。人类并不乐意坐在原地等待,而看不到任何明显的进展迹象。疑问不断蔓延。程序崩溃了吗?磁盘性能是否抖动?操作系统是否把所有的计算资源都分配给了其他任务?
|
||||
|
||||
就像正义一样,进度必须被看到,而不仅仅是完成。Python 库 [tqdm][2] 有助于使进度变得明确。
|
||||
|
||||
`tqdm` 模块可在控制台下工作,但它也专门支持了我最喜欢的环境之一 Jupyter。要在 Jupyter 中使用 `tqdm`,你需要导入 `notebook` 子模块并安装 [ipywidgets][3]。`notebook` 子模块与 `tqdm` 接口兼容。
|
||||
|
||||
这意味着你可以做一些导入时操作来导入正确的模块,同时保持 `tqdm` 的用法不变。诀窍是检查 `__main__` 模块是否具有全局变量 `get_ipython`。虽然这只是一个启发式的方法,但却是一个相当准确的方法:
|
||||
|
||||
```
|
||||
import sys
|
||||
if hasattr(sys.modules["__main__"], "get_ipython"):
|
||||
from tqdm import notebook as tqdm
|
||||
else:
|
||||
import tqdm
|
||||
```
|
||||
|
||||
最简单的情况是,某件事情需要运行一定的迭代次数(事先已知),而每一次迭代的时间都差不多。例如,有一个计算任何数字的平方根的算法,通过从 1 作为猜测值开始,然后计算出一个改进后的猜测值:
|
||||
|
||||
```
|
||||
def improve_guess(rt, n):
|
||||
return (rt + n/rt) / 2
|
||||
```
|
||||
|
||||
一点点的改进可以让你更加接近该平方根。例如,你可以计算 2 的平方根:
|
||||
|
||||
```
|
||||
guess = 1
|
||||
target = 2
|
||||
for i in tqdm.trange(10):
|
||||
guess = improve_guess(guess, target)
|
||||
```
|
||||
|
||||
![tqdm output][4]
|
||||
|
||||
精确了到小数点后 10 位!
|
||||
|
||||
```
|
||||
round(2 - guess*guess, 10)
|
||||
```
|
||||
|
||||
```
|
||||
0.0
|
||||
```
|
||||
|
||||
一个稍微复杂一点的例子是,当元素的数量是已知的,而处理每个元素需要类似的时间。例如,你可以计算一些数字的乘积。为此,你需要一些随机数:
|
||||
|
||||
```
|
||||
import random
|
||||
numbers = [random.uniform(0, 2.8) for i in range(100)]
|
||||
numbers[:5]
|
||||
```
|
||||
|
||||
```
|
||||
[2.6575636572230916,
|
||||
0.1286674965830302,
|
||||
1.0634250104041332,
|
||||
1.1760969844376505,
|
||||
0.45192978568125486]
|
||||
```
|
||||
|
||||
现在有了这些数字,可以将它们相乘了。使用 `tqdm` 最简单的方法是包装一个 Python 迭代函数。数值是一样的,但是 `tqdm` 会显示一个进度条:
|
||||
|
||||
```
|
||||
result = 1
|
||||
for num in tqdm.tqdm(numbers):
|
||||
result *= num
|
||||
result
|
||||
```
|
||||
|
||||
```
|
||||
2.4081854901728303
|
||||
```
|
||||
|
||||
![tqdm output][6]
|
||||
|
||||
然而,并不是所有的事情都可以预测。最不容易预测的事情之一就是网络速度。当你下载一个大文件时,衡量进度的唯一方法就是检查已经下载了多少:
|
||||
|
||||
```
|
||||
url = "https://www.python.org/ftp/python/3.9.0/Python-3.9.0.tgz"
|
||||
import httpx
|
||||
with httpx.stream("GET", url) as response:
|
||||
total = int(response.headers["Content-Length"])
|
||||
with tqdm.tqdm(total=total) as progress:
|
||||
for chunk in response.iter_bytes():
|
||||
progress.update(len(chunk))
|
||||
```
|
||||
|
||||
![tqdm output][7]
|
||||
|
||||
有时,“嵌套”进度条是有意义的。例如,如果你要下载一个目录,你就需要一个进度条来跟踪文件,并为每个文件设置一个进度条。
|
||||
|
||||
下面是一个例子(但没有实际下载一个目录):
|
||||
|
||||
```
|
||||
files = [f"vid-{i}.mp4" for i in range(4)]
|
||||
for fname in tqdm.tqdm(files, desc="files"):
|
||||
total = random.randrange(10**9, 2 * 10**9)
|
||||
with tqdm.tqdm(total=total, desc=fname) as progress:
|
||||
current = 0
|
||||
while current < total:
|
||||
chunk_size = min(random.randrange(10**3, 10**5), total - current)
|
||||
current += chunk_size
|
||||
if random.uniform(0, 1) < 0.01:
|
||||
time.sleep(0.1)
|
||||
progress.update(chunk_size)
|
||||
```
|
||||
|
||||
![tqdm output][8]
|
||||
|
||||
所以,如果你的程序需要一段时间才能显示最终结果,为避免让你的用户感到沮丧。请显示它的进度!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/12/tqdm-python
|
||||
|
||||
作者:[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/fail_progress_cycle_momentum_arrow.png?itok=q-ZFa_Eh (arrows cycle symbol for failing faster)
|
||||
[2]: https://pypi.org/project/tqdm/
|
||||
[3]: https://opensource.com/article/20/11/daily-journal-jupyter
|
||||
[4]: https://opensource.com/sites/default/files/uploads/output_8_0.png (tqdm output)
|
||||
[5]: https://creativecommons.org/licenses/by-sa/4.0/
|
||||
[6]: https://opensource.com/sites/default/files/uploads/output_15_0.png (tqdm output)
|
||||
[7]: https://opensource.com/sites/default/files/uploads/output_18_0.png (tqdm output)
|
||||
[8]: https://opensource.com/sites/default/files/uploads/output_21_0.png (tqdm output)
|
148
published/20201230 Choose between Btrfs and LVM-ext4.md
Normal file
148
published/20201230 Choose between Btrfs and LVM-ext4.md
Normal file
@ -0,0 +1,148 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (Chao-zhi)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-13043-1.html)
|
||||
[#]: subject: (Choose between Btrfs and LVM-ext4)
|
||||
[#]: via: (https://fedoramagazine.org/choose-between-btrfs-and-lvm-ext4/)
|
||||
[#]: author: (Troy Curtis Jr https://fedoramagazine.org/author/troycurtisjr/)
|
||||
|
||||
Btrfs 和 LVM-ext4 该如何选择?
|
||||
======
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202101/23/133137m2wfkiq8ykyvwyhv.jpg)
|
||||
|
||||
[Fedora 33][4] 在其各类桌面版本中引入了新的默认文件系统 [Btrfs][5]。多年以来,Fedora 一直在 <ruby>[逻辑卷管理][7]<rt>Logical Volume Manager</rt></ruby>(LVM) 卷之上使用 [ext4][6],引入 Brtfs 对 Fedora 来说是一个很大的转变。更改默认文件系统需要 [令人信服的原因][8]。虽然 Btrfs 是令人兴奋的下一代文件系统,但 LVM 上的 ext4 是成熟而稳定的。本指南旨在探索各自的高级特性,使得更容易在 Btrfs 和 LVM-ext4 之间进行选择。
|
||||
|
||||
### 先说结论
|
||||
|
||||
最简单的建议是坚持使用默认值。全新安装的 Fedora 33 环境默认为 Btrfs,升级之前的 Fedora 版本将继续使用最初安装的设置,通常是 LVM-ext4。对于现有的 Fedora 用户来说,获取 Btrfs 的最简单方式是全新安装。然而,全新安装比简单升级更具破坏性。除非有特殊需要,否则这种干扰可能是不必要的。Fedora 开发团队仔细考虑了这两个默认值,因此对任何一个选择都要有信心。
|
||||
|
||||
### 那么其他文件系统呢?
|
||||
|
||||
现在有很多 [Linux 系统的文件系统][9]。在加上卷管理器、加密方法和存储机制的组合后,这一数字呈爆炸式增长。那么,为什么要关注 btrfs 和 LVM-ext4 呢?对于 Fedora 的用户来说,这两种设置可能是最常见的。在 Fedora 11 中,LVM 之上的 ext4 成为了默认磁盘布局,在此之前则使用的是 ext3。
|
||||
|
||||
既然 Btrfs 是 Fedora 33 的默认设置,那么绝大多数现有用户会考虑是应该原地踏步还是向前跳跃。面对全新安装的 Fedora 33 环境,有经验的 Linux 用户可能会想知道是使用这个新的文件系统,还是退回到他们熟悉的文件系统。因此,在众多可能的存储选项中,许多 Fedora 用户会想知道如何在 Btrfs 和 LVM-ext4 之间进行选择。
|
||||
|
||||
### 两者的共性
|
||||
|
||||
尽管两个文件系统之间存在核心差异,但 Btrfs 和 LVM-ext4 实际上有很多共同之处。两者都是成熟且经过充分测试的存储技术。从 Fedora Core 的早期开始,就一直在使用 LVM,而 ext4 在 [2009 年成为 Fedora 11 的默认设置][10]。Btrfs 在 2009 年并入 Linux 主线内核,并且 [Facebook 广泛使用了该文件系统][11]。SUSE Linux Enterprise 12 [在 2014 年使其成为默认文件系统][12]。因此,它在生产环境中也有着长久的运行时间。
|
||||
|
||||
这两个系统都能很好地防止因意外停电而导致的文件系统损坏,尽管它们的实现方式不同。它们支持的配置包括使用单盘设置和跨越多个设备,并且这两种配置都能够创建近乎即时的快照。有各种工具可以帮助管理这两种系统,包括命令行和图形界面。这两种解决方案在家用台式机和高端服务器上都同样有效。
|
||||
|
||||
### LVM-ext4 的优势
|
||||
|
||||
![LVM 上 ext4 的结构][13]
|
||||
|
||||
[ext4 文件系统][14] 专注于高性能和可伸缩性,没有太多额外的花哨之处。它能有效地防止长时间后的碎片化,并当碎片化出现后提供了 [很好的工具][15]。ext4 之所以坚如磐石,是因为它构建在前代的 ext3 文件系统之上,带来了多年的系统内测试和错误修复。
|
||||
|
||||
LVM-ext4 环境中的大多数高级功能都来自 LVM 本身。LVM 位于文件系统的“下方”,这意味着它支持任何文件系统。<ruby>逻辑卷<rt>Logical volume</rt></ruby>(LV)是通用的块设备,因此 [虚拟机可以直接使用它们][16]。这种灵活性使得每个逻辑卷都可以使用合适的文件系统,用合适的选项应对各种情况。这种分层方法还遵循了“小工具协同工作”的 Unix 哲学。
|
||||
|
||||
从硬件抽象出来的<ruby>[卷组][17]<rt>volume group</rt></ruby>(VG)允许 LVM 创建灵活的逻辑卷。每个逻辑卷都提取自同一个存储池,但具有自己的设置。调整卷的大小比调整物理分区的大小容易得多,因为没有数据有序放置的限制。LVM <ruby>[物理卷][18]<rt>physical volume</rt></ruby>(PV)可以是任意数量的分区,甚至可以在系统运行时在设备之间移动。
|
||||
|
||||
LVM 支持只读和读写的 [快照][19],这使得从活动系统创建一致的备份变得很容易。每个快照都有一个定义的大小,更改源卷或快照卷将占用其中的空间。又或者,逻辑卷也可以是<ruby>[稀疏配置池][20]<rt>thinly provisioned pool</rt></ruby>的一部分。这允许快照自动使用池中的数据,而不是使用在创建卷时定义的固定大小的块。
|
||||
|
||||
#### 有多个磁盘驱动器的 LVM
|
||||
|
||||
当有多个设备时,LVM 才真正大放异彩。它原生支持大多数 [RAID 级别][21],每个逻辑卷可以具有不同的 RAID 级别。LVM 将自动为 RAID 配置选择适当的物理设备,或者用户可以直接指定它。基本的 RAID 支持包括用于性能的数据条带化([RAID0][22])和用于冗余的镜像([RAID1][23])。逻辑卷也可以使用 [RAID5][24]、[RAID6][25] 和 [RAID10][26] 等高级设置。LVM RAID 支持已经成熟,因为 LVM 在底层使用的 [设备映射器(dm)][27] 和 [多设备(md)][28] 内核支持, 与 [mdadm][29] 使用的一样。
|
||||
|
||||
对于具有快速和慢速驱动器的系统,逻辑卷也可以是 [缓存卷][30]。经典示例是 SSD 和传统磁盘驱动器的组合。缓存卷使用较快的驱动器来存储更频繁访问的数据(或用作写缓存),而慢速的驱动器则用于处理大量数据。
|
||||
|
||||
LVM 中大量稳定的功能以及 ext4 的可靠性在既往的使用中早已被证明了。当然,功能越多就越复杂。在配置 LVM 时,要找到合适的功能选项是很有挑战性的。对于单驱动器的台式机系统,LVM 的功能(例如 RAID 和缓存卷)不适用。但是,逻辑卷比物理分区更灵活,快照也很有用。对于正常的桌面使用,LVM 的复杂性会成为典型的用户可能遇到的问题恢复的障碍。
|
||||
|
||||
### Btrfs 的优势
|
||||
|
||||
![Btrfs 结构][31]
|
||||
|
||||
从前几代文件系统中学到的经验指导了构建到 [Btrfs][5] 的功能设计。与 ext4 不同,它可以直接跨越多个设备,因此它具有通常仅在卷管理器中才能找到的功能。它还具有 Linux 文件系统空间中独有的功能([ZFS][32] 具有相似的功能集,但[不要指望它在 Linux 内核中出现][33])。
|
||||
|
||||
#### Btrfs 的主要功能
|
||||
|
||||
也许最重要的功能是对所有数据进行<ruby>校验和<rt>checksumming</rt></ruby>。校验和与<ruby>[写时复制][37]<rt>copy-on-write</rt></ruby>(COW)一起,提供了在意外断电后确保文件系统完整性的 [关键方法][34]。更独特的是,校验和可以检测数据本身中的错误。悄然的数据损坏(有时也称为 [bitrot][35])比大多数人意识到的更常见。如果没有主动验证,损坏最终可能会传播到所有可用的备份中。这使得用户没有有效的副本。通过透明地校验所有数据,Btrfs 能够立即检测到任何此类损坏。启用正确的 [dup 或 raid 选项][36],文件系统也可以透明地修复损坏。
|
||||
|
||||
写时复制也是 Btrfs 的基本功能,因为它在提供文件系统完整性和即时子卷快照方面至关重要。从公共子卷创建快照后,快照会自动共享底层数据。另外,事后的<ruby>[重复数据删除][38]<rt>deduplication</rt></ruby> 使用相同的技术来消除相同的数据块。单个文件可以通过使用 `cp` 的 [reflink 选项][39] 来使用 COW 功能。reflink 副本对于复制大型文件(例如虚拟机镜像)特别有用,这些文件往往随着时间的推移具有大部分相同的数据。
|
||||
|
||||
Btrfs 支持跨越多个设备,而无需卷管理器。多设备支持可提供数据镜像功能以实现冗余和条带化以提高性能。此外,还实验性地支持更高级的 RAID 级别,例如 [RAID 5][24] 和 [RAID 6][25]。与标准 RAID 设置不同,Btrfs 的 RAID1 实际上允许奇数个设备。例如,它可以使用 3 个设备,即使它们的大小不同。
|
||||
|
||||
所有 RAID 和 dup 选项都是在文件系统级别指定的。因此,各个子卷不能使用不同的选项。请注意,使用多设备的 RAID1 选项意味着即使一个设备发生故障,卷中的所有数据都是可用的,并且校验功能可以保持数据本身的完整性。这超出了当前典型的 RAID 设置所能提供的范围。
|
||||
|
||||
#### 附加功能
|
||||
|
||||
Btrfs 还支持快速简便的远程备份。子卷快照可以 [发送到远程系统][40] 进行存储。通过利用文件系统中固有的 COW 元数据,这些传输通过仅发送先前发送的快照中的增量更改而非常有效。诸如 [snapper][41] 之类的用户应用程序使管理这些快照变得容易。
|
||||
|
||||
另外,Btrfs 卷可以具有 [透明压缩][42] 功能,并且 [chattr +c][43] 可以标记进行压缩的单个文件或目录。压缩不仅可以减少数据消耗的空间,还可以通过减少写入操作量来帮助延长 SSD 的寿命。压缩当然会带来额外的 CPU 开销,但是有很多选项就可以权衡取舍。
|
||||
|
||||
Btrfs 集成了文件系统和卷管理器功能,这意味着总体维护比 LVM-ext4 更简单。当然,这种集成的灵活性较低,但是对于大多数台式机甚至服务器而言,设置已足够。
|
||||
|
||||
### LVM 上使用 Btrfs
|
||||
|
||||
Btrfs 可以 [就地转换 ext3/ext4 文件系统][44]。就地转换意味着无需将数据复制出来然后再复制回去。数据块本身甚至都不需要修改。因此,对于现有的 LVM-ext4 系统,一种选择是将 LVM 保留在原处,然后简单地将 ext4 转换为 Btrfs。虽然可行且受支持,但有一些原因使它不是最佳选择。
|
||||
|
||||
Btrfs 的吸引力之一是与卷管理器集成的文件系统所带来的更轻松的管理。要是在 LVM 之上运行,对于系统维护,仍然要对额外的卷管理器进行一些设置。同样,LVM 设置通常具有多个固定大小的逻辑卷,并具有独立文件系统。虽然 Btrfs 支持给定的计算机上的多个卷,但是许多不错的功能都需要单一卷具有多个子卷。如果每个 LVM 卷都有一个独立的 Btrfs 卷,则用户仍然需要手动管理固定大小的 LVM 卷。虽然能够收缩挂载的 Btrfs 文件系统的能力确实使处理固定大小的卷的工作变得更轻松。通过在线收缩功能,就无需启动 [实时镜像][45] 了。
|
||||
|
||||
在使用 Btrfs 的多设备支持时,必须仔细考虑逻辑卷的物理位置。对于 Btrfs 而言,每个逻辑卷都是一个单独的物理设备,如果实际情况并非如此,则某些数据可用性功能可能会做出错误的决定。例如,如果单个驱动器发生故障,对数据使用 RAID1 通常可以提供保护。如果实际逻辑卷在同一物理设备上,则没有冗余。
|
||||
|
||||
如果强烈需要某些特定的 LVM 功能,例如原始块设备或高速缓存的逻辑卷,则在 LVM 之上运行 Btrfs 是有意义的。在这种配置下,Btrfs 仍然提供其大多数优点,例如校验和和易于发送的增量快照。尽管使用 LVM 会产生一些操作开销,但 Btrfs 的这种开销并不比任何其他文件系统大。
|
||||
|
||||
### 总结
|
||||
|
||||
当尝试在 Btrfs 和 LVM-ext4 之间进行选择时,没有一个正确的答案。每个用户都有独特的要求,并且同一用户可能拥有具有不同需求的不同系统。看一下每个配置的功能集,并确定是否有令人心动的功能。如果没有,坚持默认值没有错。选择这两种设置都有很好的理由。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://fedoramagazine.org/choose-between-btrfs-and-lvm-ext4/
|
||||
|
||||
作者:[Troy Curtis Jr][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[Chao-zhi](https://github.com/Chao-zhi)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://fedoramagazine.org/author/troycurtisjr/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://fedoramagazine.org/wp-content/uploads/2020/12/btrfs-lvm-ext4-816x345.jpg
|
||||
[2]: https://unsplash.com/@raulpetri?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText
|
||||
[3]: https://unsplash.com/?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText
|
||||
[4]: https://fedoramagazine.org/announcing-fedora-33/
|
||||
[5]: https://btrfs.wiki.kernel.org/index.php/Main_Page
|
||||
[6]: https://ext4.wiki.kernel.org/index.php/Main_Page
|
||||
[7]: https://man7.org/linux/man-pages/man8/lvm.8.html
|
||||
[8]: https://fedoraproject.org/wiki/Changes/BtrfsByDefault
|
||||
[9]: https://man7.org/linux/man-pages/man5/filesystems.5.html
|
||||
[10]: https://docs.fedoraproject.org/en-US/Fedora/11/html/Release_Notes/index.html#sect-Release_Notes-Fedora_11_Overview
|
||||
[11]: https://facebookmicrosites.github.io/btrfs/docs/btrfs-facebook.html
|
||||
[12]: https://www.suse.com/releasenotes/x86_64/SUSE-SLES/12/#fate-317221
|
||||
[13]: https://fedoramagazine.org/wp-content/uploads/2020/12/ext4-on-LVM.jpg
|
||||
[14]: https://opensource.com/article/18/4/ext4-filesystem
|
||||
[15]: https://man7.org/linux/man-pages/man8/e4defrag.8.html
|
||||
[16]: https://libvirt.org/storage.html#StorageBackendLogical
|
||||
[17]: https://www.redhat.com/sysadmin/create-volume-group
|
||||
[18]: https://www.redhat.com/sysadmin/create-physical-volume
|
||||
[19]: https://tldp.org/HOWTO/LVM-HOWTO/snapshotintro.html
|
||||
[20]: https://man7.org/linux/man-pages/man7/lvmthin.7.html
|
||||
[21]: https://rhea.dev/articles/2018-08/LVM-RAID-on-Fedora
|
||||
[22]: https://en.wikipedia.org/wiki/Standard_RAID_levels#RAID_0
|
||||
[23]: https://en.wikipedia.org/wiki/Standard_RAID_levels#RAID_1
|
||||
[24]: https://en.wikipedia.org/wiki/Standard_RAID_levels#RAID_5
|
||||
[25]: https://en.wikipedia.org/wiki/Standard_RAID_levels#RAID_6
|
||||
[26]: https://en.wikipedia.org/wiki/Non-standard_RAID_levels#Linux_MD_RAID_10
|
||||
[27]: https://man7.org/linux/man-pages/man8/dmsetup.8.html
|
||||
[28]: https://man7.org/linux/man-pages/man4/md.4.html
|
||||
[29]: https://fedoramagazine.org/managing-raid-arrays-with-mdadm/
|
||||
[30]: https://man7.org/linux/man-pages/man7/lvmcache.7.html
|
||||
[31]: https://fedoramagazine.org/wp-content/uploads/2020/12/Btrfs-Volume.jpg
|
||||
[32]: https://en.wikipedia.org/wiki/ZFS
|
||||
[33]: https://itsfoss.com/linus-torvalds-zfs/
|
||||
[34]: https://btrfs.wiki.kernel.org/index.php/FAQ#Can_I_have_nodatacow_.28or_chattr_.2BC.29_but_still_have_checksumming.3F
|
||||
[35]: https://arstechnica.com/information-technology/2014/01/bitrot-and-atomic-cows-inside-next-gen-filesystems/
|
||||
[36]: https://man7.org/linux/man-pages/man8/mkfs.btrfs.8.html#DUP_PROFILES_ON_A_SINGLE_DEVICE
|
||||
[37]: https://en.wikipedia.org/wiki/Copy-on-write
|
||||
[38]: https://btrfs.wiki.kernel.org/index.php/Deduplication
|
||||
[39]: https://btrfs.wiki.kernel.org/index.php/UseCases#How_do_I_copy_a_large_file_and_utilize_COW_to_keep_it_from_actually_being_copied.3F
|
||||
[40]: https://fedoramagazine.org/btrfs-snapshots-backup-incremental/
|
||||
[41]: http://snapper.io/
|
||||
[42]: https://btrfs.wiki.kernel.org/index.php/Compression
|
||||
[43]: https://www.man7.org/linux/man-pages/man1/chattr.1.html
|
||||
[44]: https://btrfs.wiki.kernel.org/index.php/Conversion_from_Ext3
|
||||
[45]: https://fedoramagazine.org/reclaim-hard-drive-space-with-lvm/
|
@ -0,0 +1,126 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-13000-1.html)
|
||||
[#]: subject: (Learn Lua by writing a "guess the number" game)
|
||||
[#]: via: (https://opensource.com/article/20/12/lua-guess-number-game)
|
||||
[#]: author: (Seth Kenlon https://opensource.com/users/seth)
|
||||
|
||||
通过编写“猜数字”游戏学习 Lua
|
||||
======
|
||||
|
||||
> 通过编写一个简单的游戏来认识 Lua,它是一种动态类型的、轻量级的、高效的、可嵌入的脚本语言。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202101/10/125405hgrqrigagbucpbqg.jpg)
|
||||
|
||||
如果你是 Bash、Python 或 Ruby 等脚本语言的爱好者,你可能会发现 Lua 很有趣。Lua 是一种动态类型的、轻量级的、高效的、可嵌入的脚本语言,它有与 C 语言的 API 接口。它通过基于寄存器的虚拟机解释字节码来运行,它可以用于过程式编程、函数式编程和数据驱动编程等编程方式。它甚至可以通过巧妙地使用数组(即“<ruby>表<rt>table</rt></ruby>”)来模拟类,以用于面向对象的编程。
|
||||
|
||||
感受一门语言的好方法是通过编写一个你已经熟悉的简单应用。最近,一些作者已经演示了如何使用他们最喜欢的语言来创建一个“猜数字”游戏。[Lua][2] 是我最喜欢的语言之一,所以这是我的 Lua 版猜数字游戏。
|
||||
|
||||
### 安装 Lua
|
||||
|
||||
如果你是在 Linux 上,你可以从你的发行版仓库中安装 Lua。在 macOS 上,你可以从 [MacPorts][3] 或 [Homebrew][4] 安装 Lua。在 Windows 上,你可以从 [Chocolatey][5] 安装 Lua。
|
||||
|
||||
安装 Lua 后,打开你最喜欢的文本编辑器,可以准备编写了。
|
||||
|
||||
### Lua 代码
|
||||
|
||||
首先,你必须设置一个伪随机数生成器,这样你的玩家就有一些不可预知的东西来尝试猜测。这是一个两个步骤的过程:首先,你根据当前的时间生成一个随机种子,然后在 1 到 100 的范围内选择一个数字:
|
||||
|
||||
```
|
||||
math.randomseed(os.time())
|
||||
number = math.random(1,100)
|
||||
```
|
||||
|
||||
接下来,创建一个 Lua 所谓的<ruby>表<rt>table</rt></ruby>来表示你的玩家。表就像一个 [Bash 中的数组][7]或 Java 中的 `ArrayList`。你可以创建一个表,然后分配与该表相关的子变量。在这段代码中,`player` 是表,而 `player.guess` 是表中的一个条目:
|
||||
|
||||
```
|
||||
player = {}
|
||||
player.guess = 0
|
||||
```
|
||||
|
||||
处于调试的需求,可以输出这个秘密数字。这对游戏并不合适,但对测试很有帮助。Lua 中的注释是在前面放双破折号:
|
||||
|
||||
```
|
||||
print(number) --debug
|
||||
```
|
||||
|
||||
接下来,设置一个 `while` 循环,当分配给 `player.guess` 的值不等于代码开始时建立的随机的 `number` 时,循环将永远运行。目前,`player.guess` 被设置为 0,所以它不等于 `number`。Lua 的不等式数学运算符是 `~=`,诚然这很独特,但过一段时间你就会习惯。
|
||||
|
||||
在这个无限循环的过程中,首先游戏会打印一个提示,让玩家明白游戏的内容。
|
||||
|
||||
接下来,Lua 会暂停,等待玩家输入猜测的数。Lua 使用 `io.read` 函数从文件和标准输入 (stdin) 中读取数据。你可以将 `io.read` 的结果分配到一个变量中,这个变量是在 `player` 表中动态创建的。处理玩家输入的问题是,即使它是一个数字,它也是作为一个字符串读取的。你可以使用 `tonumber()` 函数将这个输入转换为整数类型,将结果赋值回初始为 `0` 的 `player.guess` 变量:
|
||||
|
||||
```
|
||||
while ( player.guess ~= number ) do
|
||||
print("Guess a number between 1 and 100")
|
||||
player.answer = io.read()
|
||||
player.guess = tonumber(player.answer)
|
||||
```
|
||||
|
||||
现在 `player.guess` 包含了一个新的值,它将与 `if` 语句中的随机数进行比较。Lua 使用关键字 `if`、`elseif` 和 `else`,并用关键字 `end` 来结束该语句:
|
||||
|
||||
```
|
||||
if ( player.guess > number ) then
|
||||
print("Too high")
|
||||
elseif ( player.guess < number) then
|
||||
print("Too low")
|
||||
else
|
||||
print("That's right!")
|
||||
os.exit()
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
最后,函数 `os.exit()` 在成功后关闭应用,关键字 `end` 使用了两次:一次是结束 `if` 语句,另一次是结束 `while` 循环。
|
||||
|
||||
### 运行应用
|
||||
|
||||
在终端上运行游戏:
|
||||
|
||||
```
|
||||
$ lua ./guess.lua
|
||||
96
|
||||
Guess a number between 1 and 100
|
||||
1
|
||||
Too low
|
||||
Guess a number between 1 and 100
|
||||
99
|
||||
Too high
|
||||
Guess a number between 1 and 100
|
||||
96
|
||||
That's right!
|
||||
```
|
||||
|
||||
就是这样!
|
||||
|
||||
### 直观且一致
|
||||
|
||||
从这段代码中可以看出,Lua 是非常一致且相当直观的。它的表机制是一种令人耳目一新的数据关联方式,它的语法也是简约而高效的。Lua 代码中几乎没有浪费的行,事实上,这个例子中至少有两行可以进一步优化,但我想把数据转换作为它的步骤来演示(也许你可以找到我所指的两行,并对它们进行重构)。
|
||||
|
||||
Lua 非常易于使用,它的[文档阅读起来很愉快][9],主要是因为它的内容实在是不多。你会在短时间内学会核心语言,然后你就可以自由地探索 [LuaRocks][10],发现别人贡献的各种很棒的库。“Lua” 在葡萄牙语中的意思是“月亮”,所以今晚可以尝试一下。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/12/lua-guess-number-game
|
||||
|
||||
作者:[Seth Kenlon][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/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://www.lua.org/
|
||||
[3]: https://opensource.com/article/20/11/macports
|
||||
[4]: https://opensource.com/article/20/6/homebrew-mac
|
||||
[5]: https://opensource.com/article/20/3/chocolatey
|
||||
[6]: http://www.opengroup.org/onlinepubs/009695399/functions/time.html
|
||||
[7]: https://opensource.com/article/20/6/associative-arrays-bash
|
||||
[8]: http://www.opengroup.org/onlinepubs/009695399/functions/exit.html
|
||||
[9]: https://www.lua.org/docs.html
|
||||
[10]: https://opensource.com/article/19/11/getting-started-luarocks
|
@ -0,0 +1,74 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-12997-1.html)
|
||||
[#]: subject: (Use the Markdown Editor app in Nextcloud)
|
||||
[#]: via: (https://opensource.com/article/20/12/nextcloud-markdown)
|
||||
[#]: author: (Seth Kenlon https://opensource.com/users/seth)
|
||||
|
||||
使用 Nextcloud 中的 Markdown 编辑器应用
|
||||
======
|
||||
|
||||
> Nextcloud 拥有流行的 Markdown 文件的最流畅的编辑器之一,它有很多方便和直观的功能。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202101/09/164849mofte5zy5ryuewax.jpg)
|
||||
|
||||
纯文本的好处是,没有额外的针对计算机的信息会杂乱无章地出现在原本供人类阅读的文字中。计算机的好处是它们是可编程的,因此只要我们人类同意在写作时遵循非常特定的惯例,我们就可以对计算机进行编程,将人类可读的文本解释为秘密指令。例如,我们在一个词的周围打上两个星号,不仅可以给人类一个视觉上的提示,说明这个词很重要,我们还可给计算机编程让它用**粗体**显示这个词。
|
||||
|
||||
这正是 [Markdown][2] 背后的理论和实践,这种流行的纯文本格式向作者们承诺,只要_他们_使用特定的纯文本约定,那么他们的文本就会以特定的风格呈现。
|
||||
|
||||
传统中,这意味着作者用纯文本写作,直到文本被传给转换器应用(最初是 `markdown.pl`),才会看到漂亮的样式,但 Nextcloud 的 Markdown 编辑器应用改变了这一点。
|
||||
|
||||
通过 Nextcloud 的 Markdown 编辑器,你可以一边输入纯文本,一边看到它渲染后的样式。这对于那些要努力记住 Markdown 有时令人困惑的符号的作者们无异于是救星(方括号是在小括号中的超链接之前还是之后?)。而且更好的是,它运行在 Nextcloud 中,所以你可以在任何地方使用它。
|
||||
|
||||
### 安装
|
||||
|
||||
要使用 Nextcloud 的 Markdown 编辑器,你必须安装 Nextcloud。好消息是,Nextcloud 非常_容易_安装。我已经在树莓派、共享服务器、甚至作为一个本地应用安装了它(这是愚蠢的,不要这样做)。如果你不相信自己的能力,你甚至可以依靠 [Turnkey Linux][3] 来帮你完成这些难关,否则就直接从 [Nextcloud.com][4] 购买托管服务。在你安装 Nextcloud 后,添加应用就很简单了。点击 Nextcloud 界面右上角的用户图标,选择 **Apps**。找到 **Office and Text** 类别,点击安装并启用 **Markdown Editor**。
|
||||
|
||||
![Nextcloud app store showing Markdown Editor installer][5]
|
||||
|
||||
### 启动
|
||||
|
||||
激活后,Markdown 编辑器会与 Nextcloud 文件中任何以 .md 结尾的文件相关联,当你打开一个 Markdown 文件时,你就会启动 Markdown 编辑器。
|
||||
|
||||
### 使用 Markdown 编辑器
|
||||
|
||||
Markdown 编辑器包含了一个大的文本区域供你输入,以及一个沿着顶部的工具栏。
|
||||
|
||||
![Example markdown file][6]
|
||||
|
||||
工具栏包含了文字处理器的基本功能:用粗体、斜体和删除线设计文本样式、创建标题和段落、列表等等。
|
||||
|
||||
如果你了解 Markdown,这些功能中的许多可以在你输入时自动调用。如果你不熟悉 Markdown,那么工具栏或常用的键盘快捷键(`Ctrl+B` 表示粗体,`Ctrl+I` 表示斜体等等)可以帮助你设计文本的样式。
|
||||
|
||||
Markdown 编辑器的工作方式的最好的一点是,它真正做到了使人人满意:如果你想以 Markdown 格式输入,那么它就会接受它并立即将其转化为视觉样式;如果你不想操心 Markdown 语法,那么当你使用键盘快捷键或工具栏按钮时,它就会为你生成样式。无论哪种方式,你永远不会看到 Markdown 语法格式,但你也永远不会失去它。这是一个完美的折中方案。
|
||||
|
||||
它也是一个非常聪明的编辑器。当你选择一个单词时,它会为你创建一个超链接,它能快速流畅地自动转换 Markdown,而且它知道一些不同“风格”的 Markdown 语法(主要是 Commonmark,但也有传统的 Markdown、Github Markdown,等等)。
|
||||
|
||||
![black text on white background, word highlighted in blue to create an automatic link][7]
|
||||
|
||||
### 尝试 Nextcloud
|
||||
|
||||
我用过几个 Markdown 预览应用,Nextcloud 的 Markdown 编辑器是最流畅的一个。它尊重用户,并为显示 Markdown 做了最基本的工作,所以它的转换速度很快,也很准确。因为它是 Nextcloud 中的一个应用,你还可以获得这样的好处:你的作品可以即时保存在自己的私有的开源云上,并进行版本控制。没有比这更好的文本编辑器了。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/12/nextcloud-markdown
|
||||
|
||||
作者:[Seth Kenlon][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/seth
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/computer_desk_home_laptop_browser.png?itok=Y3UVpY0l (Digital images of a computer desktop)
|
||||
[2]: https://opensource.com/article/19/9/introduction-markdown
|
||||
[3]: https://www.turnkeylinux.org/nextcloud
|
||||
[4]: http://nextcloud.com
|
||||
[5]: https://opensource.com/sites/default/files/uploads/nextcloud-app-install-31_days-markdown-opensource.jpg (Nextcloud app store showing Markdown Editor installer)
|
||||
[6]: https://opensource.com/sites/default/files/uploads/nextcloud-markdown-31-days-opensource.jpg (Example markdown file )
|
||||
[7]: https://opensource.com/sites/default/files/uploads/nextcloud-link-31_days_markdown-opensource.jpg (black text on white background, word highlighted in blue to create an automatic link)
|
87
published/20201231 10 things to love about Git.md
Normal file
87
published/20201231 10 things to love about Git.md
Normal file
@ -0,0 +1,87 @@
|
||||
[#]: collector: "lujun9972"
|
||||
[#]: translator: "lxbwolf"
|
||||
[#]: reviewer: "wxy"
|
||||
[#]: publisher: "wxy"
|
||||
[#]: url: "https://linux.cn/article-12981-1.html"
|
||||
[#]: subject: "10 things to love about Git"
|
||||
[#]: via: "https://opensource.com/article/20/12/git"
|
||||
[#]: author: "Joshua Allen Holm https://opensource.com/users/holmja"
|
||||
|
||||
让你爱上 Git 的 10 篇文章
|
||||
======
|
||||
|
||||
> 你对 Git 了解得越多,使用 Git 就会越容易。一起来回顾下年度最佳 Git 文章。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202101/04/120824ue7jvn9nj4n2s4vh.jpg)
|
||||
|
||||
Git 是开源开发者工具箱中最基本的工具。这个强大的版本控制系统有很多复杂的功能。使用 Git 不需要了解它所有的功能,但是对 Git 了解得越多,使用 Git 就会越容易。
|
||||
|
||||
下面每篇文章都提供了一些奇技淫巧来提升和增强你的 Git 技能。
|
||||
|
||||
### 怎么解决 git 合并时的冲突
|
||||
|
||||
Brian Breniser 的这篇教程从 `git merge` 的定义以及解释什么是冲突开始。然后他详细解释了在合并时如果有冲突[如何解决冲突][2]。Breniser 还提了一些能学习更多关于解决冲突和其他 Git 功能的建议。
|
||||
|
||||
### 4 个不可或缺的 Git 脚本
|
||||
|
||||
Vince Power 分享了他[最重要的 Git 脚本][3]。这些脚本可以从 Git Extras 包中获得,该包提供了 60 多个 Git 增强脚本。Power 最爱的脚本有:在无需打开文本编辑器的情况下编辑 `.git-ignore` 的 `git-ignore` ;用于提供 Git 仓库的摘要的 `git-info`;用来处理 GitLab 的合并请求(MR)和 GitHub 的拉取请求(PR)的 `git-pr`;把 Git 的提交(`commit`)、标签(`tag`)和推送(`push`)合为一体的 `git-release`。
|
||||
|
||||
### 完美生活:git rebase -i
|
||||
|
||||
在 Dave Neary 的这篇文章中可以学习[使用 git rebase -i 来修改你的 Git 提交历史][4]。Neary 从解释 Git 是如何把提交历史记录到仓库中的以及 `git commit` 和 `git rebase` 的区别。之后,他又解释了如何使用 `git rebase -i` 让 Git 仓库的提交历史变得简洁。这个命令能让你把“修复书写错误”的提交合进其它提交里,把几个相似的小提交合并成一个大的提交。
|
||||
|
||||
### Git Cola 让使用 Git 变得简单
|
||||
|
||||
Seth Kenlon 演示了[如何使用 Git Cola][5]。Git 是个命令行工具,这对于有些人来说是有学习门槛的。Git Cola 提供了一个图形界面,因此不习惯用命令行的用户也可以使用 Git。在此文中,Kenlon 展示了如何安装 Git Cola,并使用 Git Cola 的图形用户界面完成了很多 Git 提交任务。
|
||||
|
||||
### 6 个在团队中使用 Git 的最佳实践
|
||||
|
||||
从设计上讲,Git 是个协同工具,但是关于如何协同的很多细节是由团队自行决定的。Ravi Chandran 提了一些建议,团队应该采用这些建议[更高效地使用 Git][6]。Chandran 在文中列出的 6 个最佳实践是:“使约定正式化”,“正确地合并修改”,“经常变基你的功能分支”,“在合并之前把压扁你的提交”,“使用标签”,“让软件的可执行程序打印标签”。
|
||||
|
||||
### 改变我使用 Git 工作方式的七个技巧
|
||||
|
||||
Rajeev Bera 分享了 [7 个 Git 技巧][7],这些技巧能提升 Git 的用户体验。文章探讨了 Git 的自动更正、提交计数、仓库优化、备份未追踪的文件、了解 `.git` 目录、在另一个分支查看文件以及在 Git 下搜索。
|
||||
|
||||
### 使用 tmux 和 Git 定制化我的 Linux 终端
|
||||
|
||||
Moshe Zadka 展示了他是如何[使用 tmux 和 Git][8]定制化他的 Linux 终端的。Zadka 的文章是个人工作流的优秀探索。他使用 GNOME 终端,用 tmux 和一些能让他快速查看 Git 仓库状态的功能来增强终端。他只需要用一个字母就可以提交文件或把提交推送到远程仓库。
|
||||
|
||||
### 使用 Lazygit 让复杂的 Git 任务简单化
|
||||
|
||||
Jesse Duffield 解释了如何使用[Lazygit,一个能让使用 Git 变得简单的终端界面][9]。Lazygit 的开发者 Duffield 详细阐述了如何使用这个界面来暂存文件、以交互方式变基、进行筛选、搜索提交以及创建一个 PR。
|
||||
|
||||
### 使用子模块和子树来管理 Git 项目
|
||||
|
||||
子模块和子树是两种在 Git 仓库中引入嵌套的子项目的方式。在[使用子模块和子树来管理 Git 项目][10]中,Manaswini Das 解释了两个选项的工作原理和区别。
|
||||
|
||||
### 不喜欢 diff?那么试试 Meld
|
||||
|
||||
Ben Nuttall 展示了如何[使用 Meld 代替 diff][11]来进行对比和合并修改。Meld 是图形化的 `diff`,输出更容易理解。Nuttall 演示了使用 `diff` 和 Meld 进行对比的区别。他还解释了 Meld 是如何识别 Git 项目的,这意味着在 Git 中一个文件被提交之后,可以用 Meld 来搜索修改。
|
||||
|
||||
你想学习关于 Git 的什么内容?请在评论去分享你的想法。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/12/git
|
||||
|
||||
作者:[Joshua Allen Holm][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/holmja
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/lenovo-thinkpad-laptop-concentration-focus-windows-office.png?itok=-8E2ihcF "Woman using laptop concentrating"
|
||||
[2]: https://opensource.com/article/20/4/git-merge-conflict
|
||||
[3]: https://linux.cn/article-12180-1.html
|
||||
[4]: https://linux.cn/article-12231-1.html
|
||||
[5]: https://opensource.com/article/20/3/git-cola
|
||||
[6]: https://linux.cn/article-12621-1.html
|
||||
[7]: https://linux.cn/article-12894-1.html
|
||||
[8]: https://linux.cn/article-12450-1.html
|
||||
[9]: https://opensource.com/article/20/3/lazygit
|
||||
[10]: https://linux.cn/article-12244-1.html
|
||||
[11]: https://linux.cn/article-12067-1.html
|
||||
[12]: https://opensource.com/how-submit-article
|
306
published/20201231 Build your own text editor in Java.md
Normal file
306
published/20201231 Build your own text editor in Java.md
Normal file
@ -0,0 +1,306 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (robsean)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-13038-1.html)
|
||||
[#]: subject: (Build your own text editor in Java)
|
||||
[#]: via: (https://opensource.com/article/20/12/write-your-own-text-editor)
|
||||
[#]: author: (Seth Kenlon https://opensource.com/users/seth)
|
||||
|
||||
使用 Java 构建你自己的文本编辑器
|
||||
======
|
||||
|
||||
> 有时候,除你自己外,没有人能制作你所梦想的工具。以下是如何开始构建你自己的文本编辑器。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202101/21/134710uzumn6ej36u7t79j.jpg)
|
||||
|
||||
有很多文本编辑器。有运行在终端中、运行在 GUI 中、运行在浏览器和浏览器引擎中的。有很多是还不错,有一些则是极好的。但是有时候,毫无疑问,最令人满意的就是你自己构建的编辑器。
|
||||
|
||||
毫无疑问:构建一个真正优秀的文本编辑器比表面上看上去要困难得多。但话说回来,建立一个基本的文本编辑器也不像你担心的那样难。事实上,大多数编程工具包已经为你准备好了文本编辑器的大部分组件。围绕文本编辑的组件,例如菜单条,文件选择对话框等等,是很容易落到实处。因此,虽然是中级的编程课程,但构建一个基本的文本编辑器是出乎意料的有趣和简明。你可能会发现自己渴望使用一个自己构造的工具,而且你使用得越多,你可能会有更多的灵感来增加它的功能,从而更多地学习你正在使用的编程语言。
|
||||
|
||||
为了使这个练习切合实际,最好选择一种具有令人满意的 GUI 工具箱的语言。有很多种选择,包括 Qt 、FLTK 或 GTK ,但是一定要先评审一下它的文档,以确保它有你所期待的功能。对于这篇文章来说,我使用 Java 以及其内置的 Swing 小部件集。如果你想使用一种不同的语言或者一种不同的工具集,这篇文章在如何帮你处理这种问题的方面也仍然是有用的。
|
||||
|
||||
不管你选择哪一种,在任何主要的工具箱中编写一个文本编辑器都是惊人的相似。如果你是 Java 新手,需要更多关于开始的信息,请先阅读我的 [猜谜游戏文章][2] 。
|
||||
|
||||
### 工程设置
|
||||
|
||||
通常,我使用并推荐像 [Netbeans][3] 或 Eclipse 这样的 IDE,但我发现,当学习一种新的语言时,手工做一些工作是很有帮助的,这样你就能更好地理解使用 IDE 时被隐藏起来的东西。在这篇文章中,我假设你正在使用文本编辑器和终端进行编程。
|
||||
|
||||
在开始前,为你自己的工程创建一个工程目录。在工程文件夹中,创建一个名称为 `src` 的目录来容纳你的源文件。
|
||||
|
||||
```
|
||||
$ mkdir -p myTextEditor/src
|
||||
$ cd myTextEditor
|
||||
```
|
||||
|
||||
在你的 `src` 目录中创建一个名称为 `TextEdit.java` 的空白的文件:
|
||||
|
||||
```
|
||||
$ touch src/TextEditor.java
|
||||
```
|
||||
|
||||
在你最喜欢的文本编辑器中打开这个空白的文件(我的意思是除你自己编写之外的最喜欢的一款文本编辑器),然后准备好编码吧!
|
||||
|
||||
### 包和导入
|
||||
|
||||
为确保你的 Java 应用程序有一个唯一的标识符,你必须声明一个 `package` 名称。典型的格式是使用一个反向的域名,如果你真的有一个域名的话,这就特别容易了。如果你没有域名的话,你可以使用 `local` 作为最顶层。像 Java 和很多语言一样,行以分号结尾。
|
||||
|
||||
在命名你的 Java 的 `package` 后,你必须告诉 Java 编译器(`javac`)使用哪些库来构建你的代码。事实上,这通常是你边编写代码边添加的内容,因为你很少事先知道你自己所需要的库。然而,这里有一些库是显而易见的。例如,你知道这个文本编辑器是基于 Swing GUI 工具箱的,因此,导入 `javax.swing.JFrame` 和`javax.swing.UIManager` 和其它相关的特定库。
|
||||
|
||||
```
|
||||
package com.example.textedit;
|
||||
|
||||
import javax.swing.JFileChooser;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JMenu;
|
||||
import javax.swing.JMenuBar;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JTextArea;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.UnsupportedLookAndFeelException;
|
||||
import javax.swing.filechooser.FileSystemView;
|
||||
import java.awt.Component;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.util.Scanner;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
```
|
||||
|
||||
对于这个练习的目标,你可以提前预知你所需要的所有的库。在真实的生活中,不管你喜欢哪一种语言,你都将在研究如何解决一些问题的时候发现库,然后,你将它导入到你的代码中,并使用它。不需要担心 —— 如果你忘记包含一个库,你的编译器或解释器将警告你!
|
||||
|
||||
### 主窗口
|
||||
|
||||
这是一个单窗口应用程序,因此这个应用程序的主类是一个 `JFrame` ,其附带有一个捕捉菜单事件的 `ActionListener` 。在 Java 中,当你使用一个现有的小部件元素时,你可以使用你的代码“扩展”它。这个主窗口需要三个字段:窗口本身(一个 `JFrame` 的实例)、一个用于文件选择器返回值的标识符和文本编辑器本身(`JTextArea`)。
|
||||
|
||||
```
|
||||
public final class TextEdit extends JFrame implements ActionListener {
|
||||
private static JTextArea area;
|
||||
private static JFrame frame;
|
||||
private static int returnValue = 0;
|
||||
```
|
||||
|
||||
令人惊奇的是,这数行代码完成了实现一个基本文本编辑器的 80% 的工作,因为 `JtextArea` 是 Java 的文本输入字段。剩下的 80 行代码大部分用于处理辅助功能,比如保存和打开文件。
|
||||
|
||||
### 构建一个菜单
|
||||
|
||||
`JMenuBar` 小部件被设计到 JFrame 的顶部,它为你提供你想要的很多菜单项。Java 不是一种
|
||||
拖放式的编程语言,因此,对于你所添加的每一个菜单,你都还必须编写一个函数。为保持这个工程的可控性,我提供了四个函数:创建一个新的文件,打开一个现有的文件,保存文本到一个文件,和关闭应用程序。
|
||||
|
||||
在大多数流行的工具箱中,创建一个菜单的过程基本相同。首先,你创建菜单条本身,然后创建一个顶级菜单(例如 “File” ),再然后创建子菜单项(例如,“New”、“Save” 等)。
|
||||
|
||||
```
|
||||
public TextEdit() { run(); }
|
||||
|
||||
public void run() {
|
||||
frame = new JFrame("Text Edit");
|
||||
|
||||
// Set the look-and-feel (LNF) of the application
|
||||
// Try to default to whatever the host system prefers
|
||||
try {
|
||||
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
|
||||
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
|
||||
Logger.getLogger(TextEdit.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
|
||||
// Set attributes of the app window
|
||||
area = new JTextArea();
|
||||
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
frame.add(area);
|
||||
frame.setSize(640, 480);
|
||||
frame.setVisible(true);
|
||||
|
||||
// Build the menu
|
||||
JMenuBar menu_main = new JMenuBar();
|
||||
|
||||
JMenu menu_file = new JMenu("File");
|
||||
|
||||
JMenuItem menuitem_new = new JMenuItem("New");
|
||||
JMenuItem menuitem_open = new JMenuItem("Open");
|
||||
JMenuItem menuitem_save = new JMenuItem("Save");
|
||||
JMenuItem menuitem_quit = new JMenuItem("Quit");
|
||||
|
||||
menuitem_new.addActionListener(this);
|
||||
menuitem_open.addActionListener(this);
|
||||
menuitem_save.addActionListener(this);
|
||||
menuitem_quit.addActionListener(this);
|
||||
|
||||
menu_main.add(menu_file);
|
||||
|
||||
menu_file.add(menuitem_new);
|
||||
menu_file.add(menuitem_open);
|
||||
menu_file.add(menuitem_save);
|
||||
menu_file.add(menuitem_quit);
|
||||
|
||||
frame.setJMenuBar(menu_main);
|
||||
}
|
||||
```
|
||||
|
||||
现在,所有剩余的工作是实施菜单项所描述的功能。
|
||||
|
||||
### 编程菜单动作
|
||||
|
||||
你的应用程序响应菜单选择,是因为你的 `JFrame` 有一个附属于它的 `ActionListener` 。在 Java 中,当你实施一个事件处理程序时,你必须“重写”其内建的函数。这只是听起来可怕。你不是在重写 Java;你只是在实现已经被定义但尚未实施事件处理程序的函数。
|
||||
|
||||
在这种情况下,你必须重写 `actionPerformed`方法。因为在 “File” 菜单中的所有条目都与处理文件有关,所以在我的代码中很早就定义了一个 `JFileChooser` 。代码其它部分被划分到一个 `if` 语句的子语句中,这起来像接收到什么事件就相应地执行什么动作。每个子语句都与其它的子语句完全不同,因为每个项目都标示着一些完全唯一的东西。最相似的是 “Open” 和 “Save”,因为它们都使用 `JFileChooser` 选择文件系统中的一个位置来获取或放置数据。
|
||||
|
||||
“New” 菜单会在没有警告的情况下清理 JTextArea ,“Quit” 菜单会在没有警告的情况下关闭应用程序。这两个 “功能” 都是不安全的,因此你应该想对这段代码进行一点改善,这是一个很好的开始。在内容还没有被保存前,一个友好的警告是任何一个好的文本编辑器都必不可少的一个功能,但是在这里为了简单,这是未来的一个功能。
|
||||
|
||||
```
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
String ingest = null;
|
||||
JFileChooser jfc = new JFileChooser(FileSystemView.getFileSystemView().getHomeDirectory());
|
||||
jfc.setDialogTitle("Choose destination.");
|
||||
jfc.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
|
||||
|
||||
String ae = e.getActionCommand();
|
||||
if (ae.equals("Open")) {
|
||||
returnValue = jfc.showOpenDialog(null);
|
||||
if (returnValue == JFileChooser.APPROVE_OPTION) {
|
||||
File f = new File(jfc.getSelectedFile().getAbsolutePath());
|
||||
try{
|
||||
FileReader read = new FileReader(f);
|
||||
Scanner scan = new Scanner(read);
|
||||
while(scan.hasNextLine()){
|
||||
String line = scan.nextLine() + "\n";
|
||||
ingest = ingest + line;
|
||||
}
|
||||
area.setText(ingest);
|
||||
}
|
||||
catch ( FileNotFoundException ex) { ex.printStackTrace(); }
|
||||
}
|
||||
// 保存
|
||||
} else if (ae.equals("Save")) {
|
||||
returnValue = jfc.showSaveDialog(null);
|
||||
try {
|
||||
File f = new File(jfc.getSelectedFile().getAbsolutePath());
|
||||
FileWriter out = new FileWriter(f);
|
||||
out.write(area.getText());
|
||||
out.close();
|
||||
} catch (FileNotFoundException ex) {
|
||||
Component f = null;
|
||||
JOptionPane.showMessageDialog(f,"File not found.");
|
||||
} catch (IOException ex) {
|
||||
Component f = null;
|
||||
JOptionPane.showMessageDialog(f,"Error.");
|
||||
}
|
||||
} else if (ae.equals("New")) {
|
||||
area.setText("");
|
||||
} else if (ae.equals("Quit")) { System.exit(0); }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
从技术上来说,这就是这个文本编辑器的全部。当然,并没有真正做什么,除此之外,在这里仍然有测试和打包步骤,因此仍然有很多时间来发现缺少的必需品。假设你没有注意到提示:在这段代码中 _肯定_ 缺少一些东西。你现在知道缺少的是什么吗?(在 [猜谜游戏文章][4] 中被大量的提到。)
|
||||
|
||||
### 测试
|
||||
|
||||
你现在可以测试你的应用程序。从终端中启动你所编写的文本编辑器:
|
||||
|
||||
```
|
||||
$ java ./src/TextEdit.java
|
||||
error: can’t find main(String[]) method in class: com.example.textedit.TextEdit
|
||||
```
|
||||
|
||||
它看起来像在代码中没有获得 `main` 方法。这里有一些方法来修复这个问题:你可以在 `TextEdit.java` 中创建一个 `main` 方法,并让它运行一个 `TextEdit` 类实例,或者你可以创建一个单独的包含 `main` 方法的文件。两种方法都可以工作,但从大型工程的预期来看,使用后者更为明智,因此,使用单独的文件与其一起工作使之成为一个完整的应用程序的方法是值得使用的。
|
||||
|
||||
在 `src` 中创建一个 `Main.java` 文件,并在最喜欢的编辑器中打开:
|
||||
|
||||
```
|
||||
package com.example.textedit;
|
||||
|
||||
public class Main {
|
||||
public static void main(String[] args) {
|
||||
TextEdit runner = new TextEdit();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
你可以再次尝试,但是现在有两个相互依赖的文件要运行,因此你必须编译代码。Java 使用 `javac` 编译器,并且你可以使用 `-d` 选项来设置目标目录:
|
||||
|
||||
```
|
||||
$ javac src/*java -d .
|
||||
```
|
||||
|
||||
这会在你的软件包名称 `com/example/textedit` 后创建一个准确地模型化的新的目录结构。这个新的类路径包含文件 `Main.class` 和 `TextEdit.class` ,这两个文件构成了你的应用程序。你可以使用 `java` 并通过引用你的 Main 类的位置和 _名称_(非文件名称)来运行它们:
|
||||
|
||||
```
|
||||
$ java info/slackermedia/textedit/Main`
|
||||
```
|
||||
|
||||
你的文本编辑器打开了,你可以在其中输入文字,打开文件,甚至保存你的工作。
|
||||
|
||||
![带有单个下拉菜单的白色文本编辑器框,有 File、New、Open、Save 和 Quit 菜单][5]
|
||||
|
||||
### 以 Java 软件包的形式分享你的工作
|
||||
|
||||
虽然一些程序员似乎看起来认可以各种各样的源文件的形式分发软件包,并鼓励其他人来学习如何运行它,但是,Java 让打包应用程序变得真地很容易,以至其他人可以很容易的运行它。你已经有了必备的大部分结构体,但是你仍然需要一些元数据到一个 `Manifest.txt` 文件中:
|
||||
|
||||
```
|
||||
$ echo "Manifest-Version: 1.0" > Manifest.txt
|
||||
```
|
||||
|
||||
用于打包的 `jar` 命令,与 [tar][6] 命令非常相似,因此很多选项对你来说可能会很熟悉。要创建一个 JAR 文件:
|
||||
|
||||
```
|
||||
$ jar cvfme TextEdit.jar
|
||||
Manifest.txt
|
||||
com.example.textedit.Main
|
||||
com/example/textedit/*.class
|
||||
```
|
||||
|
||||
根据命令的语法,你可以推测出它会创建一个新的名称为 `TextEdit.jar` 的 JAR 文件,它所需要的清单数据位于 `Manifest.txt` 中。它的主类被定义为软件包名称的一个扩展,并且类自身是 `com/example/textedit/Main.class` 。
|
||||
|
||||
你可以查看 JAR 文件的内容:
|
||||
|
||||
```
|
||||
$ jar tvf TextEdit.jar
|
||||
0 Wed Nov 25 META-INF/
|
||||
105 Wed Nov 25 META-INF/MANIFEST.MF
|
||||
338 Wed Nov 25 com/example/textedit/textedit/Main.class
|
||||
4373 Wed Nov 25 com/example/textedit/textedit/TextEdit.class
|
||||
```
|
||||
|
||||
如果你想看看你的元数据是如何被集成到 `MANIFEST.MF` 文件中的,你甚至可以使用 `xvf` 选项来提取它。
|
||||
|
||||
使用 `java` 命令来运行你的 JAR 文件:
|
||||
|
||||
```
|
||||
$ java -jar TextEdit.jar
|
||||
```
|
||||
|
||||
你甚至可以 [创建一个桌面文件][7] ,这样,在单击应用程序菜单中的图标时,应用程序就会启动。
|
||||
|
||||
### 改进它
|
||||
|
||||
在当前状态下,这是一个非常基本的文本编辑器,最适合做快速笔记或简短自述文档。一些改进(比如添加垂直滚动条)只要稍加研究就能快速简单地完成,而另一些改进(比如实现一个广泛的偏好系统)则需要真正的工作。
|
||||
|
||||
但如果你一直在想学一种新的语言,这可能是一个完美的自我学习实用工程。创建一个文本编辑器,如你所见,它在代码方面并不难对付,它在一定范围是可控的。如果你经常使用文本编辑器,那么编写你自己的文本编辑器可能会使你满意和乐趣。因此打开你最喜欢的文本编辑器(你写的那个),开始添加功能吧!
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/20/12/write-your-own-text-editor
|
||||
|
||||
作者:[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/wfh_work_home_laptop_work.png?itok=VFwToeMy (Working from home at a laptop)
|
||||
[2]: https://opensource.com/article/20/12/learn-java
|
||||
[3]: https://opensource.com/article/20/12/netbeans
|
||||
[4]: http://www.google.com/search?hl=en&q=allinurl%3Adocs.oracle.com+javase+docs+api+component
|
||||
[5]: https://opensource.com/sites/default/files/uploads/this-time-its-personal-31_days_yourself-opensource.png (White text editor box with single drop down menu with options File, New, Open, Save, and Quit)
|
||||
[6]: https://opensource.com/article/17/7/how-unzip-targz-file
|
||||
[7]: https://opensource.com/article/18/1/how-install-apps-linux
|
78
published/20210101 Resize images using Python.md
Normal file
78
published/20210101 Resize images using Python.md
Normal file
@ -0,0 +1,78 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-13003-1.html)
|
||||
[#]: subject: (Resize images using Python)
|
||||
[#]: via: (https://opensource.com/life/15/2/resize-images-python)
|
||||
[#]: author: (Dayo Ntwari https://opensource.com/users/dayontwari)
|
||||
|
||||
使用 Python 调整图像大小
|
||||
======
|
||||
|
||||
> 快速解释如何在 Python 中调整图像大小,同时保持相同的长宽比。
|
||||
|
||||
![Python in a tree][1]
|
||||
|
||||
我喜欢 [Python][2],而且我已经学了一段时间了。前段时间,我写了一个 Python 脚本,在这个脚本中,我需要调整一堆图片的大小,同时保持长宽比(比例)不变。于是我四处寻找,发现了 [Pillow][3],这是一个 Python 图像库,也是一个叫做 PIL 的旧库的“友好复刻”。
|
||||
|
||||
要安装 Pillow,请使用 Python 的 `pip` 模块:
|
||||
|
||||
```
|
||||
$ python3 -m pip install Pillow
|
||||
```
|
||||
|
||||
### 按宽度缩放
|
||||
|
||||
这是一个使用 Pillow 模块来调整图片大小的基本脚本:
|
||||
|
||||
```
|
||||
from PIL import Image
|
||||
|
||||
basewidth = 300
|
||||
img = Image.open('fullsized_image.jpg')
|
||||
wpercent = (basewidth / float(img.size[0]))
|
||||
hsize = int((float(img.size[1]) * float(wpercent)))
|
||||
img = img.resize((basewidth, hsize), Image.ANTIALIAS)
|
||||
img.save('resized_image.jpg')
|
||||
```
|
||||
|
||||
这几行 Python 代码使用 Pillow 将一张图片 (`fullsized_image.jpg`) 调整为 300 像素的宽度,宽度在变量 `basewidth` 中设置,高度则与新的宽度成比例。比例高度的计算方法是:确定 300 像素占原宽度 (`img.size[0]`) 的百分比,然后将原高度(`img.size[1]`) 乘以该百分比。所得的高度值保存在变量 `hsize` 中。
|
||||
|
||||
如果你需要不同的图片宽度,你可以将 `basewidth` 改为任何其他数字。另外,请注意,因为我想保留全尺寸的图片 (`fullsized_image.jpg`),因此我将调整后的图片以一个不同的名称 `resized_image.jpg` 保存。当然,你不必这么做。如果你想,你可以使用相同的文件名将调整后的图片覆盖全尺寸的图片。
|
||||
|
||||
### 按高度缩放
|
||||
|
||||
如果高度是固定的,而宽度是按比例变化的,那也基本差不多,你只需要把东西换一下:
|
||||
|
||||
```
|
||||
from PIL import Image
|
||||
|
||||
baseheight = 560
|
||||
img = Image.open('fullsized_image.jpg')
|
||||
hpercent = (baseheight / float(img.size[1]))
|
||||
wsize = int((float(img.size[0]) * float(hpercent)))
|
||||
img = img.resize((wsize, baseheight), Image.ANTIALIAS)
|
||||
img.save('resized_image.jpg')
|
||||
```
|
||||
|
||||
注意 `basewidth` 现在换成了 `baseheight`,因为高度是固定的。在第三行中,我们在计算高度百分比,所以我们需要 `img.size[1]` 而不是 `img.size[0]`。`size` 属性是一个元组,包含宽度和高度,单位是像素,`size[0]` 指的是第一个元组元素,也就是宽度,`size[1]` 是第二个元素,也就是高度。第 4 行也有这样的切换,`size[0]` 代表宽度,`size[1]` 代表高度。
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/life/15/2/resize-images-python
|
||||
|
||||
作者:[Dayo Ntwari][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/dayontwari
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/life-python.jpg?itok=F2PYP2wT (Python in a tree)
|
||||
[2]: http://python.org/ (Python Programming Language – Official Website)
|
||||
[3]: https://pypi.org/project/Pillow/ (Python Imaging Library)
|
||||
[4]: https://dayontwari.wordpress.com/2015/01/06/how-to-resize-images-with-python/
|
@ -0,0 +1,144 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (wxy)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-13046-1.html)
|
||||
[#]: subject: (4 lines of code to improve your Ansible play)
|
||||
[#]: via: (https://opensource.com/article/21/1/improve-ansible-play)
|
||||
[#]: author: (Jeff Warncia https://opensource.com/users/jeffwarncia)
|
||||
|
||||
改进你的 Ansible 剧本的 4 行代码
|
||||
======
|
||||
|
||||
> 只要付出一点点努力,你就可以帮助下一个人,不只是绘制出安全路径,还可以留下危险的警告。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202101/23/225612fowskoyyk1gtwtog.jpg)
|
||||
|
||||
在博客圈里,人们对基础架构即代码、持续集成/持续交付(CI/CD)管道、代码审查和测试制度赞不绝口,但人们很容易忘记,这种精心设计的象牙塔只是一种理想,而不是现实。虽然不完美的系统困扰着我们,但我们必须交付一些东西。
|
||||
|
||||
在系统自动化的过程中,很少有比那些通过粘合 API 创建的象牙塔更脆弱的塔。这是一个脆弱的世界。要让它“工作起来”,交付它,然后继续前进,压力巨大。
|
||||
|
||||
### 要解决的问题
|
||||
|
||||
想象一个简单的功能请求:编写一些 [Ansible][2] 代码,在外部系统中创建几条记录,以记录一个 VLAN 的一些详细信息。我最近很想做一些实验室的管理工作来完成这个任务。这个外部系统是一个常见的<ruby>互联网协议地址管理<rt>Internet Protocol Address Management</rt></ruby>(IPAM)工具,但对于一个更抽象的<ruby>配置管理数据库<rt>Configuration Management DataBase</rt></ruby>(CMDB)或一个与网络无关的记录来说,困难是一样的。在这个例子中,我创建一个记录的直接愿望就是让系统保存记录而已。
|
||||
|
||||
如果我们的目标是一个超紧凑的、直接的、笨拙的宏,那么它可能用 100 行代码就能写出来。如果我记得 API,我也许能在一个小时内把它敲出来,该代码的作用不会超过预期,除了确切的成品之外,什么也没留下。对它的目的而言是完美的,但是对未来的扩展毫无用处。
|
||||
|
||||
如今,我希望几乎每个人都能从一个<ruby>角色<rt>role</rt></ruby>和几个<ruby>任务<rt>task</rt></ruby>文件开始这项任务,准备扩展到十几个创建、读取、更新和删除(CRUD)操作。因为我不了解这个 API,我可能会花上几个小时到几天的时间,仅仅是摆弄它,弄清楚它的内部模式和工艺,弥和它的功能和我用代码编写出来的意图之间的差距。
|
||||
|
||||
在研究 API 的时候,我发现创建一个 VLAN 记录需要一个父对象引用 `vlan_view_ref`。这看起来像一个路径片段,里面有随机字符。也许它是一个哈希,也许它真的是随机的,我不确定。我猜想,许多在泥泞中挣扎的人,在迫在眉睫的截止日期前,可能会把这个任意的字符串复制粘贴到 Ansible 中,然后继续混下去。忽略这个<ruby>角色<rt>role</rt></ruby>的实现细节,显而易见这个<ruby>剧本<rt>playbook</rt></ruby>级的任务应该是这样:
|
||||
|
||||
```
|
||||
- name: "Create VLAN"
|
||||
include_role:
|
||||
name: otherthing
|
||||
tasks_from: vlan_create.yml
|
||||
vars:
|
||||
vlan_name: "lab-infra"
|
||||
vlan_tag: 100
|
||||
vlan_view_ref: "vlan_view/747f602d-0381"
|
||||
```
|
||||
|
||||
不幸的是,除了通过 API,`vlan_view_ref` 标识符是不可用的,所以即使把它移到<ruby>清单文件<rt>inventory</rt></ruby>或额外的变量中也没有什么帮助。<ruby>剧本<rt>playbook</rt></ruby>的用户需要对系统有一些更深入的理解,才能找出正确的引用 ID。
|
||||
|
||||
在实验室建设的情况下,我会经常重新部署这个记录系统。因此,这个父对象引用 ID 每天都会发生变化,我不希望每次都要手动找出它。所以,我肯定要按名称搜索该引用。没问题:
|
||||
|
||||
```
|
||||
- name: Get Lab vlan view reference
|
||||
include_role:
|
||||
name: otherthing
|
||||
tasks_from: search_for.yml
|
||||
vars:
|
||||
_resource: vlan_view
|
||||
_query: "name={{ vlan_parent_view_name }}"
|
||||
```
|
||||
|
||||
最终,它进行了一个 REST 调用。这将“返回” 一个 JSON,按照惯例,为了便于在角色外访问,我把它填充进了 `_otherthing_search_result` 中,。`search_for.yml` 的实现是抽象的,它总是返回一个包含零或多个结果的字典。
|
||||
|
||||
正如我读过的几乎所有真实世界的 Ansible 代码所证明的那样,大多数 Ansible 开发者将会继续前进,好像一切都很好,并且可以直接访问预期的单个结果:
|
||||
|
||||
```
|
||||
- name: Remember our default vlan view ref
|
||||
set_fact:
|
||||
_thatthig_vlan_view_ref: "{{ _otherthing_search_result[0]._ref }}"
|
||||
|
||||
- name: "Create VLAN"
|
||||
include_role:
|
||||
name: otherthing
|
||||
tasks_from: vlan_create.yml
|
||||
vars:
|
||||
vlan_name: "lab-infra"
|
||||
vlan_tag: 100
|
||||
vlan_view_ref: "{{ vlan_parent_view_name }}"
|
||||
```
|
||||
|
||||
但有时 `_otherthing_search_result[0]` 是未定义的,所以 `_thatthig_vlan_view_ref` 也将是未定义的。很有可能是因为代码运行在不同的真实环境中,而有人忘记了在清单中或在命令行中更新 `{{ vlan_parent_view_name }}`。或者,无论公平与否,也许有人进入了工具的图形用户界面(GUI),删除了记录或更改了它的名称什么的。
|
||||
|
||||
我知道你在想什么。
|
||||
|
||||
_“好吧,不要这样做。这是一个没有哑巴的场所。不要那么笨。”_。
|
||||
|
||||
也许我对这种情况还算满意,反驳道:“Ansible 会很正确的告诉你`错误是:list 对象没有元素 0`,甚至会带个行号。你还想怎样?”作为开发者,我当然知道这句话的意思 —— 我刚写的代码。我刚从三天的和 API 斗智斗勇中走出来,我的脑子很清醒。
|
||||
|
||||
### 明天是另一个故事
|
||||
|
||||
但是到了明天,我可能会忘记什么是父对象引用,我肯定会忘记第 30 行上的内容。如果一个月后出了问题,就算你能找到我,我也得花一个下午的时间重新解读 API 指南,才能搞清楚到底出了什么问题。
|
||||
|
||||
而如果我出门了呢?如果我把代码交给了一个运维团队,也许是一个实习生通过 [Tower][3] 来运行,把 `vlan_view_name` 手动输入到表单之类的东西呢?那第 30 行出的问题是对他们没有帮助的。
|
||||
|
||||
你说,加注释吧! 嗯,是的。我可以在代码中写一些梗概,以帮助下周或下个月的开发人员。这对运行代码的人没有帮助,他的“工作”刚刚失败,当然对于企业也无济于事。
|
||||
|
||||
记住,我们此刻无所不能。在写代码或者跳过写代码的时候,我们是站在实力和知识的立场上进行的。我们花了几个小时,甚至几天的时间,研究了文档、现实、其他 bug、其他问题,我们留下了代码、注释,甚至可能还有文档。我们写的代码是分享成功的,而成功正是我们用户想要的。但是在这种学习中也有很多失败的地方,我们也可以留下这些。
|
||||
|
||||
### 在代码中留言
|
||||
|
||||
“第 30 行有错误”对任何人都没有帮助。至少,我可以用更好的错误信息来处理明显的错误情况:
|
||||
|
||||
```
|
||||
- name: Fail if zero vlan views returned
|
||||
fail:
|
||||
msg: "Got 0 results from searching for VLAN view {{ vlan_parent_view_name }}. Please verify exists in otherthing, and is accessible by the service account."
|
||||
when: _otherthing_search_result | length == 0
|
||||
```
|
||||
|
||||
在这四行代码中(没有额外的思考),我把具体的、有用的建议留给了下一个人 —— 那个无助的运维团队成员,或者更有可能是一个月后的我 —— 这是关于现实世界中的问题,其实根本不是关于代码的。这条消息可以让任何人发现一个简单的复制/粘贴错误,或者记录系统发生了变化。不需要 Ansible 知识,不需要凌晨 3 点给开发人员发短信“看看第 30 行”。
|
||||
|
||||
但是等等!还有更多!
|
||||
|
||||
在了解 `otherthing` 的过程中,我了解到它在一个关键的方面,嗯,还挺笨的。它的许多记录类型(如果不是全部的话)没有唯一性约束,可能存在几个相同的记录。VLAN 视图被定义为有一个名称、一个开始 ID 和一个结束 ID;其他记录类型也同样简单,显然这应该是一个唯一的元组 —— 基于现实和数据库规范化的抽象概念。但 `otherthing` 允许重复的元组,尽管在概念上讲永远不可能。
|
||||
|
||||
在我的实验室里,我很乐意尝试并记住不要这样做。在企业生产环境中,我可能会写一个策略。不管是哪种方式,经验告诉我,系统会被破坏,会在倒霉的时候被破坏,而且可能需要很长时间才能让这些问题发酵成,嗯,一个问题。
|
||||
|
||||
对于 “第 30 行有错误”,一个本来有丰富经验的 Ansible 开发者可能会认识到这是“记录没有找到”,而不用知道其他的事情就足以解决这个问题。但如果 `_otherthing_search_result[0]` 只有有时是正确的 `vlan_view_ref`,那就糟糕多了,它让整个世界被破坏,而悄无声息。而这个错误可能完全表现在其他地方,也许六个月后的安全审计会将其标记为记录保存不一致,如果有多种工具和人工访问方式,可能需要几天或几周的时间才能发现这个特定代码出错的事实。
|
||||
|
||||
在几天对 API 的摸索中,我学到了这一点。我不是在找问题,如果有记录,我没有看到。所以我来到了这篇文章的重点。我没有因为它是一个实验室,修复它,然后继续前进而忽略了这种不可能的情况,而是花了两分钟留下了_代码_ —— 不是注释,不是心理笔记,不是文档 —— 而是会一直运行的代码,涵盖了这种不可能的情况:
|
||||
|
||||
```
|
||||
- name: Fail if > 1 views returned
|
||||
fail:
|
||||
msg: "Got {{ _otherthing_search_result | length }} results from searching for VLAN view {{ vlan_parent_view_name }}. Otherthing allows this, but is not handled by this code."
|
||||
when: _otherthing_search_result | length > 1
|
||||
```
|
||||
|
||||
我手动创建了失败条件,所以我可以手动测试这个条件。我希望它永远不会在实际使用中运行,但我觉得它会。
|
||||
|
||||
如果(当)这个错误发生在生产环境中,那么有人可以决定该怎么做。我希望他们能修复坏数据。如果它经常发生,我希望他们能追踪到另一个损坏的系统。如果他们要求删除这段代码,而这段代码做了未定义和错误的事情,那是他们的特权,也是我不想工作的地方。代码是不完美的,但它是完整的。这是匠人的工作。
|
||||
|
||||
现实世界中的自动化是一个迭代的过程,它与不完美的系统进行斗争,并平等地使用。它永远不会处理所有的特殊情况。它甚至可能无法处理所有的正常情况。通过 Lint、代码审查和验收测试的工作代码是处理安全和所需路径的代码。只要付出一点点努力,你就可以帮助下一个人,不仅仅是绘制安全路径,还可以对你发现的危险留下警告。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/21/1/improve-ansible-play
|
||||
|
||||
作者:[Jeff Warncia][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/jeffwarncia
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/computer_keyboard_laptop_development_code_woman.png?itok=vbYz6jjb (A person programming)
|
||||
[2]: https://www.ansible.com/
|
||||
[3]: https://www.ansible.com/products/tower
|
150
published/20210106 Learn C by writing a simple game.md
Normal file
150
published/20210106 Learn C by writing a simple game.md
Normal file
@ -0,0 +1,150 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (qfzy1233)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-13013-1.html)
|
||||
[#]: subject: (Learn C by writing a simple game)
|
||||
[#]: via: (https://opensource.com/article/21/1/learn-c)
|
||||
[#]: author: (Jim Hall https://opensource.com/users/jim-hall)
|
||||
|
||||
通过编写一个简单的游戏学习 C 语言
|
||||
======
|
||||
|
||||
> 当你学习一门新的编程语言时,这个“猜数字”游戏是一个很好的入门程序。下面是如何用 C 语言来编写它。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202101/13/232713lh91stdahcxfyfhe.jpg)
|
||||
|
||||
我在小学时就开始 [自学编程][2]。我的第一个程序是在 Apple II 上编写的,但最终,我还是通过看书和编程练习学会了 C 语言。练习编程的最佳方法是编写示例程序,它能帮助你练习新知识。
|
||||
|
||||
在我学习一种新的编程语言时,我喜欢编写一个简单的“猜数字”游戏来练习。电脑从 1 到 100 中随机挑选一个数字,你必须通过猜测来算出来。在另一篇文章中,我展示了如何用 Bash 语言编写这个[“猜数字”游戏][3],我的同事也写了一些文章,介绍如何用 [Java][4]、[Julia][5] 和其他计算机语言编写它。
|
||||
|
||||
“猜数字”游戏的伟大之处在于它践行了几个编程概念:如何使用变量、如何比较值、如何打印输出以及如何读取输入。
|
||||
|
||||
整个夏天,我录制了[一个系列视频][6],教人们如何用 [C 语言][7]编写程序。从那以后,我听到了很多人都在跟着它学习 C 语言编程的消息。所以,我想接着用 C 语言写一个“猜数字”的游戏。
|
||||
|
||||
### 去取一个随机数
|
||||
|
||||
从写一个函数来选择一个随机数字来开始“猜数字”游戏。在编写函数时,优秀的程序员会尽量使它们具有灵活性,这样他们就可以重用它们来解决略有不同的问题。因此,与其硬编码函数来选择 1 到 100 之间的一个随机数,不如编写函数来选择 1 到某个整数 `maxval` 之间的一个随机数:
|
||||
|
||||
```
|
||||
#include <stdio.h>
|
||||
#include <sys/random.h>
|
||||
|
||||
int
|
||||
randnum(int maxval)
|
||||
{
|
||||
/* pick a random number from 1 to maxval */
|
||||
|
||||
int randval;
|
||||
|
||||
getrandom(&randval, sizeof(int), GRND_NONBLOCK);
|
||||
|
||||
/* could be negative, so ensure it's positive */
|
||||
|
||||
if (randval < 0) {
|
||||
return (-1 * randval % maxval + 1);
|
||||
}
|
||||
else {
|
||||
return (randval % maxval + 1);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
该函数使用 Linux 的系统调用 `getrandom` 来生成一系列随机数。你可以在手册页中了解关于这个系统调用的更多信息,但请注意,`getrandom` 将用随机的 0 和 1 填充变量。这意味着最终值可以是正的,也可以是负的,因此你需要在之后进行测试,以确保 `randnum` 函数的结果是正值。
|
||||
|
||||
### 编写程序
|
||||
|
||||
你可以用这个函数来写你的“猜数字”程序:
|
||||
|
||||
```
|
||||
#include <stdio.h>
|
||||
#include <sys/random.h>
|
||||
|
||||
int
|
||||
randnum(int maxval)
|
||||
{
|
||||
...
|
||||
}
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
int number;
|
||||
int guess;
|
||||
|
||||
number = randnum(100);
|
||||
|
||||
puts("Guess a number between 1 and 100");
|
||||
|
||||
do {
|
||||
scanf("%d", &guess);
|
||||
|
||||
if (guess < number) {
|
||||
puts("Too low");
|
||||
}
|
||||
else if (guess > number) {
|
||||
puts("Too high");
|
||||
}
|
||||
} while (guess != number);
|
||||
|
||||
puts("That's right!");
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
程序首先使用 `randnum` 函数从 1 到 100 之间选择一个随机数。在向用户输出一个提示后,程序进入一个 `do-while` 循环,以便用户可以猜测数字。
|
||||
|
||||
在循环的每次迭代中,程序测试用户的猜测的数值。如果用户的猜测小于随机数,程序将输出“Too low”,如果猜测大于随机数,程序将输出“Too high”。循环继续,直到用户的猜测与随机数相同。
|
||||
|
||||
当循环退出时,程序输出 “That's right!”,然后立即结束:
|
||||
|
||||
```
|
||||
$ gcc -o guess -Wall guess.c
|
||||
|
||||
$ ./guess
|
||||
Guess a number between 1 and 100
|
||||
50
|
||||
Too high
|
||||
30
|
||||
Too low
|
||||
40
|
||||
Too low
|
||||
45
|
||||
Too high
|
||||
42
|
||||
Too low
|
||||
43
|
||||
Too low
|
||||
44
|
||||
That's right!
|
||||
```
|
||||
|
||||
### 尝试动手
|
||||
|
||||
在学习一门新的编程语言时,这个“猜数字”游戏是一个很好的入门程序,因为它以一种非常直接的方式练习了几个常见的编程概念。通过用不同的编程语言实现这个简单的游戏,你可以演示一些核心概念,并比较每种语言的细节。
|
||||
|
||||
你有最喜欢的编程语言吗?你会如何用它来编写“猜数字”游戏呢?关注本系列文章,查看你可能感兴趣的其他编程语言的示例。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/21/1/learn-c
|
||||
|
||||
作者:[Jim Hall][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[qfzy1233](https://github.com/qfzy1233)
|
||||
校对:[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/lenovo-thinkpad-laptop-concentration-focus-windows-office.png?itok=-8E2ihcF (Woman using laptop concentrating)
|
||||
[2]: https://opensource.com/article/20/8/learn-open-source
|
||||
[3]: https://linux.cn/article-12962-1.html
|
||||
[4]: https://opensource.com/article/20/12/learn-java
|
||||
[5]: https://opensource.com/article/20/12/julia
|
||||
[6]: https://opensource.com/article/20/8/teaching-c
|
||||
[7]: https://opensource.com/article/20/8/c-programming-cheat-sheet
|
||||
[8]: http://www.opengroup.org/onlinepubs/009695399/functions/puts.html
|
||||
[9]: http://www.opengroup.org/onlinepubs/009695399/functions/scanf.html
|
@ -0,0 +1,89 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-13016-1.html)
|
||||
[#]: subject: (My 3 favorite open source productivity apps)
|
||||
[#]: via: (https://opensource.com/article/21/1/open-source-productivity-apps)
|
||||
[#]: author: (Taz Brown https://opensource.com/users/heronthecli)
|
||||
|
||||
我最喜欢的 3 个开源生产力应用
|
||||
======
|
||||
|
||||
> 简化你的敏捷工作流程,提高你的工作效率。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202101/14/215039op8zl611f8p76vrf.jpg)
|
||||
|
||||
生产力应用确实可以让你的工作流程变得更加轻松。在本文中,我将分享一些我用来简化工作流程、提高整体生产力的开源应用。本文中所有的生产力应用都是免费的 Linux 生产力应用。
|
||||
|
||||
### Tomboy/Gnote
|
||||
|
||||
[Tomboy][2] 是一款可以在 Linux、Windows 和 macOS 上使用的简单记事本应用。它是 GNU LGPLv2 下许可的开源软件。
|
||||
|
||||
Tomboy 使用起来非常简单。你写下一张纸条,选择是否将它贴在桌面上,完成后就可以删除它。
|
||||
|
||||
![Tomboy and Gnote][3]
|
||||
|
||||
它(以及它的克隆版 [Gnote][5])是一个很好的快速记笔记的小程序。很多时候,当我在做某件事情的时候,会有一些想法或思路想要回忆。Tomboy 可以让我快速创建一个笔记,在我忘记之前把我的想法记下来。然后我就可以把这些想法转移到一个更长久的地方。
|
||||
|
||||
### Joplin
|
||||
|
||||
[Joplin][6] 是一个开源的记事和待办事项应用。它是跨平台的,可以在 Linux、Windows、macOS、iOS 和 Android 上使用,并且采用 MIT 许可开源。
|
||||
|
||||
![Joplin][7]
|
||||
|
||||
它可以使用 Dropbox、OneDrive、Nextcloud 等云同步服务进行同步。它很容易安装,可能就在你的 Linux 仓库里。当你在桌面上安装它时,它一个应用中实际包含了两个:你会得到一个标准的图形用户界面 (GUI),或者打开一个终端,在那里使用 Joplin。
|
||||
|
||||
桌面版有一个非常漂亮的界面。笔记被组织在笔记本中,这基本上使它们成为你的手册页。而且因为笔记是 Markdown 格式的,所以它们会被渲染,你可以实时编辑它们。我喜欢使用 Markdown,因为它让我写笔记的速度很快。你也可以导出或导入 Joplin 笔记。
|
||||
|
||||
### Evolution
|
||||
|
||||
[Evolution][9] 是一款开源的个人信息管理应用,它与 Outlook 非常相似,但我认为更适合我使用。它具有电子邮件、工作、笔记、链接、日历和地址簿功能。它是 LGPL 和其他[许可证][10]下的开源软件。
|
||||
|
||||
![GNOME Evolution][11]
|
||||
|
||||
我在运行 Fedora 的台式电脑上使用它。它的效率很高,绝对能帮助我度过繁忙的一天。它让我能够使用 Linux 开展业务;我还能要求什么呢?
|
||||
|
||||
要在 Fedora 中使用它,打开一个终端并输入以下命令:
|
||||
|
||||
```
|
||||
sudo dnf remove evolution
|
||||
sudo dnf update
|
||||
sudo dnf install evolution
|
||||
sudo dnf install evolution-ews
|
||||
```
|
||||
|
||||
### 我的常用工具
|
||||
|
||||
这些工具是我的主力军,我已经依赖了一段时间。使用它们超越了它们的基本功能,使我更有效率、更有效果、更有生产力。作为一名技术产品经理和敏捷专家,我很自豪,我仍然使用 Linux 和其他开源软件,即使我工作的公司不这样做。
|
||||
|
||||
* * *
|
||||
|
||||
_本文原载于 [Course Hero][13],经授权转载。_
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/21/1/open-source-productivity-apps
|
||||
|
||||
作者:[Taz Brown][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/heronthecli
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/team_dev_email_chat_video_work_wfm_desk_520.png?itok=6YtME4Hj (Working on a team, busy worklife)
|
||||
[2]: https://wiki.gnome.org/Apps/Tomboy
|
||||
[3]: https://opensource.com/sites/default/files/uploads/tomboy-gnote.png (Tomboy and Gnote)
|
||||
[4]: https://creativecommons.org/licenses/by-sa/4.0/
|
||||
[5]: https://wiki.gnome.org/Apps/Gnote
|
||||
[6]: https://joplinapp.org/
|
||||
[7]: https://opensource.com/sites/default/files/uploads/joplin_0.jpg (Joplin)
|
||||
[8]: https://github.com/laurent22/joplin
|
||||
[9]: https://wiki.gnome.org/Apps/Evolution
|
||||
[10]: https://gitlab.gnome.org/GNOME/evolution/-/blob/master/COPYING
|
||||
[11]: https://opensource.com/sites/default/files/uploads/evolution.png (GNOME Evolution)
|
||||
[12]: https://help.gnome.org/users/evolution/stable/intro-main-window.html.en
|
||||
[13]: https://www.coursehero.com/file/74086904/Personal-productivity-using-open-source-software-tools/
|
@ -0,0 +1,81 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (wxy)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-12996-1.html)
|
||||
[#]: subject: (8 open source software cheat sheets you'll need in 2021)
|
||||
[#]: via: (https://opensource.com/article/21/1/cheat-sheets)
|
||||
[#]: author: (Jim Hall https://opensource.com/users/jim-hall)
|
||||
|
||||
2021 的 8 个开源软件速查表
|
||||
======
|
||||
|
||||
> 当那个讨厌的命令就在你的指间,但是就是想不起来,一个方便的速查表就可以拯救你。这份速查表清单涵盖了从编程语言到协作工具的各种内容。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202101/09/131938ktycoc99i2l6dlly.jpg)
|
||||
|
||||
有时候,你需要一个简短的提示。你知道自己想做什么,但就是想不起具体怎么做。这时候速查表就派上用场了。在这篇文章中,我给大家提供了 MariaDB 和 MySQL 的速查表。这个速查表对于偶尔使用数据库的人来说是非常有用的。接下来,我列出了两个树莓派速查表。第一张可以让你入门这台单板计算机。一旦你有了一定的基础知识,就可以把它变成一个家庭实验室,可以开始使用 Kubernetes 进行容器管理。一定要同时看看下一张速查表,因为它涵盖了 `kubectl` 工具。接下来,有一个很棒的 Emacs 的速查表,以及还有一个 C 编程语言的速查表。最后,这个列表以两个非常实用的速查表结束:协作工具和开源替代品。
|
||||
|
||||
下面是这份清单:
|
||||
|
||||
### MariaDB 和 MySQL 速查表
|
||||
|
||||
MariaDB 是一个企业级数据库。学习 MariaDB 是使用它来管理 Web 应用程序或编程语言库的重要一步。这个 [MariaDB 和 MySQL 速查表][2]涵盖了连接到服务器、分析数据和其他关键活动的有用命令。本速查表上的命令对交互式提示符和 SQL 脚本有效,但很多内容推断可以用于编程库。
|
||||
|
||||
### 树莓派:如何入门
|
||||
|
||||
自 2012 年以来,树莓派一直是学习编程技能、构建硬件项目、进行家庭自动化和创建应用程序的必备工具。它实惠的价格使它对任何技能水平的开源爱好者都有吸引力。这本[可下载的指南][3]将为你提供挑选树莓派、保持更新、使用它进行 Linux 游戏、为社区做贡献等方面的提示,让你获得成功。
|
||||
|
||||
### 在你的树莓派家庭实验室上运行 Kubernetes
|
||||
|
||||
由于树莓派单板计算机的经济性和多功能性,建立一个家庭实验室变得越来越容易。你可以用树莓派做成千上万的事情,包括实验 Kubernetes。在这本[电子书][4]中,作者 [Chris Collins][5] 演示了如何开始在树莓派上运行 Kubernetes。本指南的每个部分都可以单独学习,也可以作为一个整体项目来学习。无论你的日常工作是什么,阅读这些教程并按照自己的节奏进行尝试,一定会提升你的云技术实力。
|
||||
|
||||
### kubectl 速查表
|
||||
|
||||
`kubectl` 是维护 Kubernetes 集群的强大命令行工具。这个 2 页的[速查表][6]涵盖了常用的命令,让你超越一般的集群管理。它分为三个不同的部分,包括基本命令、故障排除命令和高级命令。掌握这九个关键的 `kubectl` 命令,可以帮助你排除故障和管理 Kubernetes 集群。
|
||||
|
||||
### Emacs 速查表
|
||||
|
||||
要记住每一个 Emacs 的快捷键几乎是不可能的。通过这个[速查表][7],你可以熟悉最常见的组合,从而提高工作效率。当你有这个指南在身边时,你可以不用担心忘记 Emacs 键盘快捷键。通过学习这个速查表中演示的基本键盘快捷键,成为 Emacs 高手。
|
||||
|
||||
### C 语言编程速查表
|
||||
|
||||
C 是一种直接的编译编程语言。许多其他编程语言从 C 语言中借用了概念,如果你想学习 Lua、C++、Java 或 Go 等编程语言,C 语言是一个很好的起点。Jim Hall 的这份双面[速查表][8]包含了所有的基础知识,因此你可以立即获得 C 语法的所有要领。通过下载这个速查表来学习 C 语言,并将语法要领随身携带。
|
||||
|
||||
### 5 个开源协作工具
|
||||
|
||||
[Kevin Sonney][10] 的生产力指南通过[五个开源工具教程][9]让协作变得轻而易举。下载的速查表所涉及的工具包括开源邮件客户端、Google Docs 的替代方案等。让团队沟通不畅成为过去,迎接团队生产力的提升。
|
||||
|
||||
### 开放源码软件替代方案速查表
|
||||
|
||||
在我们广阔的开源世界里,有很多通用的专有软件工具的替代品。然而,有时要找到合适的开源替代品以满足你的特定需求是令人生畏的。这就是为什么我们整理了这一页的[速查表][11],涵盖了主要的软件工具类别,包括团队聊天、文件共享、文字处理等。我们并没有止步于办公工具。我们还包括游戏、社交媒体和个人理财的顶级开源应用。通过这个速查表,可以快速找到常见的专有软件工具的替代品。
|
||||
|
||||
### 总结
|
||||
|
||||
这个列表涵盖了很多主题。在我们的[下载页面][12]上可以查看更多的速查表和指南。请在下面的评论中告诉我们你最喜欢的是哪一个。不要忘了为你最喜欢的开源工具写和提交速查表。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/21/1/cheat-sheets
|
||||
|
||||
作者:[Jim Hall][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/jim-hall
|
||||
[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/mariadb-mysql-cheat-sheet
|
||||
[3]: https://opensource.com/downloads/raspberry-pi-guide
|
||||
[4]: https://opensource.com/downloads/kubernetes-raspberry-pi
|
||||
[5]: https://opensource.com/users/clcollins
|
||||
[6]: https://opensource.com/downloads/kubectl-cheat-sheet
|
||||
[7]: https://opensource.com/downloads/emacs-cheat-sheet
|
||||
[8]: https://opensource.com/downloads/c-programming-cheat-sheet
|
||||
[9]: https://opensource.com/downloads/collaboration-tools-ebook
|
||||
[10]: https://opensource.com/users/ksonney
|
||||
[11]: https://opensource.com/downloads/open-source-software-alternatives-cheat-sheet
|
||||
[12]: https://opensource.com/downloads/cheat-sheets
|
73
published/20210108 Why I like the FED text editor.md
Normal file
73
published/20210108 Why I like the FED text editor.md
Normal file
@ -0,0 +1,73 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-13019-1.html)
|
||||
[#]: subject: (Why I like the FED text editor)
|
||||
[#]: via: (https://opensource.com/article/21/1/fed-editor)
|
||||
[#]: author: (Jim Hall https://opensource.com/users/jim-hall)
|
||||
|
||||
我为什么喜欢 FED 文本编辑器
|
||||
======
|
||||
|
||||
> FED 编辑器让我可以轻松有效地对我的 FreeDOS 项目进行编码。学习如何充分利用这个灵活的 Linux、Windows 和 DOS 编辑器。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202101/16/114344hgra9oq4q45mgz9r.jpg)
|
||||
|
||||
当我不[在我的 Linux 桌面上工作][2]的时候,我通常是在为一个旧版的 16 位系统写代码。[FreeDOS][3] 是一个开源的 DOS 兼容操作系统,你可以用它来玩经典的 DOS 游戏,运行旧版的商业软件,或者开发嵌入式系统。任何在 MS-DOS 上运行的程序在 FreeDOS 上也应该可以运行。
|
||||
|
||||
我是和 DOS 一起长大的。我家的第一台个人电脑是一台 Apple II 兼容机,但我们最终升级到了一台运行 DOS 的 IBM PC。从 1980 年代早期到 1993 年我[发现 Linux][4] 这段时间,我做了十多年的 DOS 用户。
|
||||
|
||||
Linux 和开源软件所提供的自由度给我留下了深刻的印象。所以当微软在 1994 年宣布 DOS 的终结,以及即将推出的 Windows 95 时,我决定编写自己的开源 DOS。这就是 [FreeDOS 的开始][4]。
|
||||
|
||||
这么多年过去了,我还在继续研究 FreeDOS。它是一个很好的业余兴趣系统,在这里我可以运行我最喜欢的 DOS 应用和游戏。是的,我仍然在为 FreeDOS 写代码。
|
||||
|
||||
我最喜欢的 DOS 编程编辑器是 FED 编辑器。FED 是一个极简的文本编辑器,没有太多的视觉效果。这种精简的方法帮助我充分利用了 DOS 中标准的 80x25 屏幕。当编辑一个文件时,FED 会在屏幕底部显示一行状态行,让你在剩下的 24 行来编写你的代码。FED 还支持彩色语法高亮显示,以不同的颜色显示代码的不同部分,使你更容易发现错别字,以免它们变成错误。
|
||||
|
||||
![Writing a Solitaire game with FED][5]
|
||||
|
||||
*用 FED 写一个纸牌游戏*
|
||||
|
||||
当你需要菜单时,按下键盘上的 `Alt` 键,FED 就会在最上面一行显示一个菜单。FED 也支持键盘快捷键,但要注意默认值。例如,`Ctrl-C` 会关闭文件,`Ctrl-V` 会改变视图。如果你不喜欢这些默认键,你可以在 **Config** 菜单中更改键位映射。
|
||||
|
||||
![Tap the Alt key to bring up the menu][6]
|
||||
|
||||
*按下 Alt 键弹出菜单*
|
||||
|
||||
如果你不喜欢默认的白底黑字显示,你可以在 **Config** 菜单下更改颜色。我更喜欢蓝底白字的正文,关键词用亮白色,注释用亮蓝色,特殊字符用青色,数字用绿色。FED 可以很容易地设置你想要的颜色。
|
||||
|
||||
![My preferred colors when programming on DOS][7]
|
||||
|
||||
*我在 DOS 上编程时喜欢的颜色*
|
||||
|
||||
FED 也是一个折叠式文本编辑器,这意味着它可以折叠或展开我的部分代码,以便我可以看到更多的文件。在函数名上按下 `Ctrl-F`,FED 会折叠整个函数。折叠在其他代码上也可以使用。我也使用折叠来隐藏 `for` 和 `while` 循环或其他流程控制,如 `if` 和 `switch` 块。
|
||||
|
||||
![Folding a function lets you see more of the file][8]
|
||||
|
||||
*折叠函数可以让你看到更多的文件*
|
||||
|
||||
Shawn Hargreaves 从 1994 年至 2004 年编写并维护 FED。Robert Riebisch 从那时起就开始维护 FED。FED 在 GNU GPL 许可下发布,支持 DOS、Linux 和 Windows。
|
||||
|
||||
你可以在 <https://www.bttr-software.de/products/fed/> 下载 FED。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/21/1/fed-editor
|
||||
|
||||
作者:[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/laptop_screen_desk_work_chat_text.png?itok=UXqIDRDD (Person using a laptop)
|
||||
[2]: https://opensource.com/article/19/9/business-creators-open-source-tools
|
||||
[3]: https://opensource.com/article/19/6/freedos-anniversary
|
||||
[4]: https://opensource.com/article/17/5/how-i-got-started-linux-jim-hall-freedos
|
||||
[5]: https://opensource.com/sites/default/files/1-fed.png
|
||||
[6]: https://opensource.com/sites/default/files/2-fed.png
|
||||
[7]: https://opensource.com/sites/default/files/3-fed.png
|
||||
[8]: https://opensource.com/sites/default/files/4-fed.png
|
112
published/20210109 Homura- A WINE-based Game Launcher for BSD.md
Normal file
112
published/20210109 Homura- A WINE-based Game Launcher for BSD.md
Normal file
@ -0,0 +1,112 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-13026-1.html)
|
||||
[#]: subject: (Homura: A WINE-based Game Launcher for BSD)
|
||||
[#]: via: (https://itsfoss.com/homura-game-launcher-bsd/)
|
||||
[#]: author: (John Paul https://itsfoss.com/author/john/)
|
||||
|
||||
Homura:基于 WINE 的 BSD 游戏启动器
|
||||
======
|
||||
|
||||
BSD 不只是用于服务器。人们也将其用于桌面,并执行通常任务,包括休闲游戏。为了帮助实现这一点,我们将看看一个能让你在 FreeBSD 上运行 Windows 游戏的应用。
|
||||
|
||||
### 什么是 Homura?
|
||||
|
||||
![][1]
|
||||
|
||||
[Homura][2] 是一个能让你在 FreeBSD 上玩 Windows 游戏的工具。它的灵感来自于 [Lutris][3]。它允许你安装和管理多个 Windows 游戏和游戏商店启动器。它主要使用 Wine,但也附带了一些修复和变通的方法来让游戏工作。
|
||||
|
||||
Homura 的创建者 [Alexander Vereeken][4] 说,他创建这个应用是因为“当我开始使用 FreeBSD 时,没有能用的可以在 Wine 中安装游戏或启动器的程序,所以我自己创建了一个”。当时,Wine 是唯一的选择。Linux 版本的 Steam 并不存在。
|
||||
|
||||
![Homura install list][5]
|
||||
|
||||
以下是你可以用 Homura 安装的清单:
|
||||
|
||||
* Anarchy Online
|
||||
* Arc
|
||||
* Bethesda 启动器
|
||||
* 暴雪启动器
|
||||
* 暗黑破坏神 II
|
||||
* Discord
|
||||
* 龙歌 OL
|
||||
* GOG
|
||||
* 建造乌托邦
|
||||
* 英雄联盟
|
||||
* Origin 启动器
|
||||
* PokeMMO
|
||||
* 精灵宝可梦 绿铀
|
||||
* RuneScape
|
||||
* Steam
|
||||
* 地铁跑酷
|
||||
* Teamspeak
|
||||
* 猴岛大冒险 2
|
||||
* UC 浏览器
|
||||
* 育碧
|
||||
* 战游游戏中心
|
||||
* Itch.io
|
||||
|
||||
Homura 是以动画 [Madoka Magica][6] 中的一个角色命名的。在创建者转移到 GitLab 之前,它最初托管在 GitHub 上。目前它被托管在 Codeberg 上。希望它现在还能留在那里。
|
||||
|
||||
![Homura][7]
|
||||
|
||||
### 在 BSD 上安装 Homura 游戏启动器
|
||||
|
||||
你可以用这个命令从 FreeBSD 仓库中安装 Homura:
|
||||
|
||||
```
|
||||
pkg install games/homura
|
||||
```
|
||||
|
||||
你也可以使用这个命令从 ports 构建并安装它:
|
||||
|
||||
```
|
||||
cd /usr/ports/games/homura/ && make install clean
|
||||
```
|
||||
|
||||
安装完成后,你可以从菜单中选择 Homura,或在命令行中输入 `Homura` 来运行它。(在终端中名字必须大写开头,否则将无法运行。)
|
||||
|
||||
如果你通过 Homura 安装 Steam,你需要从 Homura 启动它。如果你想从操作系统的菜单中启动它,它当前不会显示在那里。
|
||||
|
||||
Steam 的库和商店标签由内置的 Web 浏览器显示。由于某些原因,这在 FreeBSD 上是不行的。但如果你从 Homura 的菜单中启动 Steam,它将使用列表模式,工作没有问题。
|
||||
|
||||
### 体验
|
||||
|
||||
我在 GhostBSD 上安装了 Homura,并用它来安装 Steam。之后,我安装了几个游戏来测试它。并不是所有的游戏都能正常运行,主要是因为它们试图使用或安装一个不可用的 Windows 专用软件。然而,我能够玩我最喜欢的游戏之一,微软的“国家的崛起”,没有任何问题。(我的测试变成了几个小时的游戏。)
|
||||
|
||||
![Homura Main Menu][8]
|
||||
|
||||
我也尝试安装 GOG 启动器。由于某些原因,它对我不起作用。加载页面会弹出,但什么都不会发生。我打算提交一个议题。我没有测试过任何安装程序/启动器,因为我没有使用它们。
|
||||
|
||||
### 总结
|
||||
|
||||
并不是所有的东西都能顺利地与 Homura 一起使用,但我可以玩一些我最喜欢的游戏。
|
||||
|
||||
![Rise of Nation on BSD][9]
|
||||
|
||||
这款应用是一个典型的用户有了需求,并决定去填补它的案例。通过这样做,他让其他人的生活变得更轻松。希望这个应用能让人们更容易地开始使用 FreeBSD 作为他们的操作系统。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://itsfoss.com/homura-game-launcher-bsd/
|
||||
|
||||
作者:[John Paul][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/john/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2021/01/homura.jpg?resize=800%2C450&ssl=1
|
||||
[2]: https://codeberg.org/Alexander88207/Homura
|
||||
[3]: https://lutris.net/
|
||||
[4]: https://codeberg.org/Alexander88207
|
||||
[5]: https://i2.wp.com/itsfoss.com/wp-content/uploads/2021/01/homura-install.jpg?resize=800%2C421&ssl=1
|
||||
[6]: https://madoka.fandom.com/wiki/Puella_Magi_Madoka_Magica
|
||||
[7]: https://i0.wp.com/itsfoss.com/wp-content/uploads/2021/01/homura-about.jpg?resize=800%2C411&ssl=1
|
||||
[8]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2021/01/homura-main-menu.jpg?resize=500%2C776&ssl=1
|
||||
[9]: https://i1.wp.com/itsfoss.com/wp-content/uploads/2021/01/rise-of-nation-bsd.jpg?resize=800%2C450&ssl=1
|
||||
[10]: https://%0Areddit.com/r/linuxusersgroup
|
211
published/20210111 Deploy Ceph in a Raspberry Pi cluster.md
Normal file
211
published/20210111 Deploy Ceph in a Raspberry Pi cluster.md
Normal file
@ -0,0 +1,211 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-13020-1.html)
|
||||
[#]: subject: (Deploy Ceph in a Raspberry Pi cluster)
|
||||
[#]: via: (https://opensource.com/article/21/1/ceph-raspberry-pi)
|
||||
[#]: author: (AJ Canlas https://opensource.com/users/ajscanlas)
|
||||
|
||||
在树莓派集群中部署 Ceph
|
||||
======
|
||||
|
||||
> 使用 ceph-ansible 安装 Ceph 存储,并将其部署在树莓派集群中。
|
||||
|
||||
![](https://img.linux.net.cn/data/attachment/album/202101/16/135445mquduh2idu2pft22.jpg)
|
||||
|
||||
[Ceph][2] 是一个开源软件存储平台,它在统一的存储集群中提供对象、块和文件系统存储。我第一次使用 Ceph 是在 [OpenStack 中集成它][3]的时候。一开始,我很困惑,既然存储设备广泛存在,为什么要使用 Ceph。但在使用了三年多之后,这个平台的稳定性和完整性一再证明了它的价值。
|
||||
|
||||
本文将告诉你如何使用 [ceph-ansible][4](Ceph 官方支持的 Ansible playbook)安装 Ceph,并将其部署在树莓派集群中。
|
||||
|
||||
**材料:**
|
||||
|
||||
1. 树莓派 4B 4GB 型号四台。
|
||||
2. 四张 32GB 的 microSD 卡(用于启动操作系统)
|
||||
3. 四个树莓派外壳,带风扇和散热片(非常重要)
|
||||
4. 四个树莓派充电器
|
||||
5. 6 个 32GB U 盘(用于 Ceph OSD 节点)
|
||||
|
||||
**架构:**
|
||||
|
||||
![Project architecture][5]
|
||||
|
||||
关于配置:
|
||||
|
||||
* 前端和后端网络都在同一个子网中
|
||||
* [Ceph Monitor][7] 软件使用 4GB 内存的树莓派 4B。
|
||||
* [Ceph OSD][8] 节点使用相同的树莓派型号,但有两个 U 盘用于 OSD 磁盘
|
||||
|
||||
### 使用 ceph-ansible 部署 Ceph
|
||||
|
||||
使用 Ceph 的 Ansible 仓库可以让部署变得顺畅简单
|
||||
|
||||
#### 1、复制 ssh 密钥到所有服务器
|
||||
|
||||
我在所有的服务器上都有一个名为 `cephadmin` 的共同用户(在此背景下,每个树莓派都是一台服务器)。`cephadmin` 用户配置了无密码的 `sudo`,以方便工作。
|
||||
|
||||
使用 `ssh-keygen` 生成密钥后,使用 `ssh-copy-id` 部署所有密钥。
|
||||
|
||||
我使用了一个 Bash `for` 循环,因为我使用的是一致并递增的主机名:
|
||||
|
||||
```
|
||||
$ for i in {0..3}; \
|
||||
do ssh-copy-id cephadmin@rpi4b4-$i; \
|
||||
done
|
||||
```
|
||||
|
||||
你需要每个接受并输入密码,但你可以用 `expect` 来自动完成。
|
||||
|
||||
#### 2、克隆 ceph-ansible 并安装依赖
|
||||
|
||||
安装 Git 来克隆仓库:
|
||||
|
||||
```
|
||||
$ sudo yum install git -y
|
||||
```
|
||||
|
||||
克隆 ceph-ansible 仓库:
|
||||
|
||||
```
|
||||
$ git clone https://github.com/ceph/ceph-ansible.git
|
||||
$ cd ceph-ansible/
|
||||
```
|
||||
|
||||
我使用的是 CentOS 7 的 AArch64 构建,所以在继续之前,我必须安装一些所需的包。
|
||||
|
||||
首先安装 Python `pip`:
|
||||
|
||||
```
|
||||
$ sudo yum install python3-pip -y
|
||||
```
|
||||
|
||||
接着是 ceph-ansible 需要的包:
|
||||
|
||||
```
|
||||
$ sudo yum install python3-devel libffi-devel openssl-devel -y
|
||||
```
|
||||
|
||||
最后,ceph-ansible 需要的依赖:
|
||||
|
||||
```
|
||||
$ pip3 install -r requirements.txt --user
|
||||
```
|
||||
|
||||
我收到了这个错误:
|
||||
|
||||
```
|
||||
You are linking against OpenSSL 1.0.2, which is no longer supported by the OpenSSL project.
|
||||
To use this version of cryptography you need to upgrade to a newer version of OpenSSL. For
|
||||
this version only you can also set the environment variable
|
||||
CRYPTOGRAPHY_ALLOW_OPENSSL_102 to allow OpenSSL 1.0.2.
|
||||
```
|
||||
|
||||
这可能与架构有关,因为我无法在 CentOS 7 虚拟机中复现该错误。
|
||||
|
||||
部署时,将 `CRYPTOGRAPHY_ALLOW_OPENSSL_102` 导出为 `True`,这样 Ansible 就可以运行了。
|
||||
|
||||
```
|
||||
$ export CRYPTOGRAPHY_ALLOW_OPENSSL_102=True
|
||||
```
|
||||
|
||||
#### 3、配置 ceph-ansible 进行部署
|
||||
|
||||
现在你可以使用 ceph-ansible 部署 Ceph 了。
|
||||
|
||||
复制 `site.yml.sample` 到 `site.yml`:
|
||||
|
||||
```
|
||||
$ mv site.yml.sample site.yml
|
||||
```
|
||||
|
||||
在 `group_vars` 目录下创建 `all.yml`:
|
||||
|
||||
```
|
||||
$ cat << EOF >> group_vars/all.yml
|
||||
ceph_origin: repository
|
||||
ceph_repository: community
|
||||
ceph_repository_type: cdn
|
||||
ceph_stable_release: nautilus
|
||||
monitor_interface: wlan0
|
||||
public_network: "192.168.100.0/24"
|
||||
cluster_network: "192.168.100.0/24"
|
||||
dashboard_enabled: false
|
||||
configure_firewall: false
|
||||
EOF
|
||||
```
|
||||
|
||||
在 `group_vars` 目录下创建 `osds.yml`:
|
||||
|
||||
```
|
||||
$ cat << EOF >> group_vars/all.yml
|
||||
osd_scenario: collocated
|
||||
devices:
|
||||
- /dev/sda
|
||||
- /dev/sdb
|
||||
EOF
|
||||
```
|
||||
|
||||
创建一个 `inventory` 文件:
|
||||
|
||||
```
|
||||
$ cat << EOF >> inventory
|
||||
[mons]
|
||||
rpi4b4-0
|
||||
|
||||
[osds]
|
||||
rpi4b4-1
|
||||
rpi4b4-2
|
||||
rpi4b4-3
|
||||
EOF
|
||||
```
|
||||
|
||||
在写这篇文章的时候,ceph-ansible 仓库里有一个 bug(根据这个 [bug 工单][9])。你可以通过编辑角色的第 85 行和第 86 行来减轻这个 bug。
|
||||
|
||||
```
|
||||
- (wait_for_all_osds_up.stdout | from_json)["osdmap"]["num_osds"] | int > 0
|
||||
- (wait_for_all_osds_up.stdout | from_json)["osdmap"]["num_osds"] == (wait_for_all_osds_up.stdout | from_json)["osdmap"]["num_up_osds"]
|
||||
```
|
||||
|
||||
#### 4、部署 Ceph
|
||||
|
||||
用你的 `inventory` 文件运行 Ansible 剧本:
|
||||
|
||||
```
|
||||
$ ansible-playbook -i inventory site.yml
|
||||
```
|
||||
|
||||
15-20 分钟后,你应该看到这个结果:
|
||||
|
||||
![Ceph deployment][10]
|
||||
|
||||
### 下面的步骤
|
||||
|
||||
之前,我在另一个树莓派集群中[手动部署][11]了一个 OpenStack 集群。我希望能将其与这个集群整合在一起。我也在研究用 [TripleO][12] 部署。
|
||||
|
||||
树莓派、Ansible 和 OpenStack 的可能性是无穷的。开始做你自己的实验,并在评论中告诉我结果如何。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://opensource.com/article/21/1/ceph-raspberry-pi
|
||||
|
||||
作者:[AJ Canlas][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/ajscanlas
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/raspberrypi_board_vector_red.png?itok=yaqYjYqI (Vector, generic Raspberry Pi board)
|
||||
[2]: https://ceph.io/
|
||||
[3]: https://opensource.com/business/15/1/introduction-ceph-storage-openstack
|
||||
[4]: https://docs.ceph.com/projects/ceph-ansible/en/latest/index.html#
|
||||
[5]: https://opensource.com/sites/default/files/uploads/architecture_0_0.png (Project architecture)
|
||||
[6]: https://creativecommons.org/licenses/by-sa/4.0/
|
||||
[7]: https://docs.ceph.com/en/latest/glossary/#term-Ceph-Monitor
|
||||
[8]: https://docs.ceph.com/en/latest/glossary/#term-OSD
|
||||
[9]: https://tracker.ceph.com/issues/43430
|
||||
[10]: https://opensource.com/sites/default/files/uploads/ceph.png (Ceph deployment)
|
||||
[11]: https://opensource.com/article/20/12/openstack-raspberry-pi
|
||||
[12]: https://wiki.openstack.org/wiki/TripleO
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user