分类 技术 下的文章

使 Linux 变得丰富多彩(或单色)。

你可以使用特殊的 ANSI 编码设置为 Linux 终端添加颜色,可以在终端命令或配置文件中动态添加,也可以在终端仿真器中使用现成的主题。无论哪种方式,你都可以黑色屏幕上找回怀旧的绿色或琥珀色文本。本文演示了如何使 Linux 变得丰富多彩(或单色)的方法。

终端的功能特性

现代系统的终端的颜色配置通常默认至少是 xterm-256color,但如果你尝试为终端添加颜色但未成功,则应检查你的 TERM 设置。

从历史上看,Unix 终端从字面上讲是:用户可以输入命令的共享计算机系统上实际的物理端点(终点)。它们专指通常用于远程发出命令的电传打字机(这也是我们今天在 Linux 中仍然使用 /dev/tty 设备的原因)。终端内置了 CRT 显示器,因此用户可以坐在办公室的终端上直接与大型机进行交互。CRT 显示器价格昂贵 —— 无论是制造还是使用控制;比担心抗锯齿和现代计算机专家理所当然认为的漂亮信息,让计算机吐出原始 ASCII 文本更容易。然而,即使在那时,技术的发展也很快,很快人们就会发现,随着新的视频显示终端的设计,他们需要新的功能特性来提供可选功能。

例如,1978 年发布的花哨的新 VT100 支持 ANSI 颜色,因此如果用户将终端类型识别为 vt100,则计算机可以提供彩色输出,而基本串行设备可能没有这样的选项。同样的原则适用于今天,它是由 TERM 环境变量设定的。你可以使用 echo 检查你的 TERM 定义:

$ echo $TERM
xterm-256color

过时的(但在一些系统上仍然为了向后兼容而维护)/etc/termcap 文件定义了终端和打印机的功能特性。现代的版本是 terminfo,位于 /etc/usr/share 中,具体取决于你的发行版。 这些文件列出了不同类型终端中可用的功能特性,其中许多都是由历史上的硬件定义的,如 vt100 到 vt220 的定义,以及 xterm 和 Xfce 等现代软件仿真器。大多数软件并不关心你使用的终端类型; 在极少数情况下,登录到检查兼容功能的服务器时,你可能会收到有关错误的终端类型的警告或错误。如果你的终端设置为功能特性很少的配置文件,但你知道你所使用的仿真器能够支持更多功能特性,那么你可以通过定义 TERM 环境变量来更改你的设置。你可以通过在 ~/.bashrc 配置文件中导出 TERM 变量来完成此操作:

export TERM=xterm-256color

保存文件并重新载入设置:

$ source ~/.bashrc

ANSI 颜色代码

现代终端继承了用于“元”特征的 ANSI 转义序列。这些是特殊的字符序列,终端将其解释为操作而不是字符。例如,此序列将清除屏幕,直到下一个提示符:

$ printf '\033[2J'

它不会清除你的历史信息;它只是清除终端仿真器中的屏幕,因此它是一个安全且具有示范性的 ANSI 转义序列。

ANSI 还具有设置终端颜色的序列。例如,键入此代码会将后续文本更改为绿色:

$ printf '\033[32m'

只要你对相同的计算机使用同一个颜色,就可以使用颜色来帮助你记住你登录的系统。例如,如果你经常通过 SSH 连接到服务器,则可以将服务器的提示符设置为绿色,以帮助你一目了然地将其与本地的提示符区分开来。 要设置绿色提示符,请在提示符前使用 ANSI 代码设置为绿色,并使用代表正常默认颜色的代码结束:

export PS1=`printf "\033[32m$ \033[39m"`

前景色和背景色

你不仅可以设置文本的颜色。使用 ANSI 代码,你还可以控制文本的背景颜色以及做一些基本的样式。

例如,使用 \033[4m,你可以为文本加上下划线,或者使用 \033[5m 你可以将其设置为闪烁的文本。起初这可能看起来很愚蠢,因为你可能不会将你的终端设置为所有文本带有下划线并整天闪烁, 但它对某些功能很有用。例如,你可以将 shell 脚本生成的紧急错误设置为闪烁(作为对用户的警报),或者你可以为 URL 添加下划线。

作为参考,以下是前景色和背景色的代码。前景色在 30 范围内,而背景色在 40 范围内:

颜色前景色背景色
黑色\033[30m\033[40m
红色\033[31m\033[41m
绿色\033[32m\033[42m
橙色\033[33m\033[43m
蓝色\033[34m\033[44m
品红\033[35m\033[45m
青色\033[36m\033[46m
浅灰\033[37m\033[47m
回退到发行版默认值\033[39m\033[49m

还有一些可用于背景的其他颜色:

颜色背景色
深灰\033[100m
浅红\033[101m
浅绿\033[102m
黄色\033[103m
浅蓝\033[104m
浅紫\033[105m
蓝绿\033[106m
白色\033[107m

持久设置

在终端会话中设置颜色只是暂时的,相对无条件的。有时效果会持续几行;这是因为这种设置颜色的方法依赖于 printf 语句来设置一种模式,该模式仅持续到其他设置覆盖它。

终端仿真器通常获取使用哪种颜色的指令的方式来自于 LS_COLORS 环境变量的设置,该设置又由 dircolors 的设置填充。你可以使用 echo 语句查看当前设置:

$ echo $LS_COLORS
rs=0:di=38;5;33:ln=38;5;51:mh=00:pi=40;
38;5;11:so=38;5;13:do=38;5;5:bd=48;5;
232;38;5;11:cd=48;5;232;38;5;3:or=48;
5;232;38;5;9:mi=01;05;37;41:su=48;5;
196;38;5;15:sg=48;5;11;38;5;16:ca=48;5;
196;38;5;226:tw=48;5;10;38;5;16:ow=48;5;
[...]

或者你可以直接使用 dircolors

$ dircolors --print-database
[...]
# image formats
.jpg 01;35
.jpeg 01;35
.mjpg 01;35
.mjpeg 01;35
.gif 01;35
.bmp 01;35
.pbm 01;35
.tif 01;35
.tiff 01;35
[...]

这看起来很神秘。文件类型后面的第一个数字是属性代码,它有六种选择:

  • 00 无
  • 01 粗体
  • 04 下划线
  • 05 闪烁
  • 07 反白
  • 08 暗色

下一个数字是简化形式的颜色代码。你可以通过获取 ANSI 代码的最后一个数字来获取颜色代码(绿色前景为 32,绿色背景为 42;红色为 31 或 41,依此类推)。

你的发行版可能全局设置了 LS_COLORS,因此系统上的所有用户都会继承相同的颜色。如果你想要一组自定义的颜色,可以使用 dircolors。首先,生成颜色设置的本地副本:

$ dircolors --print-database > ~/.dircolors

根据需要编辑本地列表。如果你对自己的选择感到满意,请保存文件。你的颜色设置只是一个数据库,不能由 ls 直接使用,但你可以使用 dircolors 获取可用于设置 LS_COLORS 的 shellcode:

$ dircolors --bourne-shell ~/.dircolors
LS_COLORS='rs=0:di=01;34:ln=01;36:mh=00:
pi=40;33:so=01;35:do=01;35:bd=40;33;01:
cd=40;33;01:or=40;31;01:mi=00:su=37;41:
sg=30;43:ca=30;41:tw=30;42:ow=34;
[...]
export LS_COLORS

将输出复制并粘贴到 ~/.bashrc 文件中并重新加载。或者,你可以将该输出直接转储到 .bashrc 文件中并重新加载。

$ dircolors --bourne-shell ~/.dircolors >> ~/.bashrc
$ source ~/.bashrc

你也可以在启动时使 Bash 解析 .dircolors 而不是手动进行转换。实际上,你可能不会经常改变颜色,所以这可能过于激进,但如果你打算改变你的配色方案,这是一个选择。在 .bashrc 文件中,添加以下规则:

[[ -e $HOME/.dircolors ]] && eval "`dircolors --sh $HOME/.dircolors`"

如果你的主目录中有 .dircolors 文件,Bash 会在启动时对其进行评估并相应地设置 LS_COLORS

颜色

在终端中使用颜色是一种可以为你自己提供特定信息的快速视觉参考的简单方法。但是,你可能不希望过于依赖它们。毕竟,颜色不是通用的,所以如果其他人使用你的系统,他们可能不会像你那样看懂颜色代表的含义。此外,如果你使用各种工具与计算机进行交互,你可能还会发现某些终端或远程连接无法提供你期望的颜色(或根本不提供颜色)。

除了上述警示之外,颜色在某些工作流程中可能很有用且很有趣,因此创建一个 .dircolor 数据库并根据你的想法对其进行自定义吧。


via: https://opensource.com/article/19/9/linux-terminal-colors

作者:Seth Kenlon 选题:lujun9972 译者:wxy 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

有时当你需要移动一个文件时,mv 命令似乎不是最佳选项,那么你会如何做呢?

不起眼的 mv 命令是在你见过的每个 POSIX 系统中都能找到的有用工具之一。它的作用是明确定义的,并且做得很好:将文件从文件系统中的一个位置移动到另一个位置。但是 Linux 非常灵活,还有其他移动文件的办法。使用不同的工具可以完美匹配一些特殊用例,这算一个小优势。

在远离 mv 之前,先看看这个命令的默认结果。首先,创建一个目录并生成一些权限为 777 的文件:

$ mkdir example
$ touch example/{foo,bar,baz}
$ for i in example/*; do ls /bin > "${i}"; done
$ chmod 777 example/*

你可能不会这么认为,但是文件在一个文件系统中作为条目存在,称为索引节点(通常称为 inode),你可以使用 ls 命令及其 --inode 选项查看一个文件占用的 inode:

$ ls --inode example/foo
7476868 example/foo

作为测试,将文件从示例目录移动到当前目录,然后查看文件的属性:

$ mv example/foo .
$ ls -l -G -g --inode
7476868 -rwxrwxrwx. 1 29545 Aug  2 07:28 foo

如你所见,原始文件及权限已经被“移动”,但它的 inode 没有变化。

这就是 mv 工具用来移动的方式:保持 inode 不变(除非文件被移动到不同的文件系统),并保留其所有权和权限。

其他工具提供了不同的选项。

复制和删除

在某些系统上,移动操作是真的在做移动:比特从文件系统中的某个位置删除并重新分配给另一个位置。这种行为在很大程度上已经失宠。现在,移动操作要么是属性重新分配(inode 现在指向文件组织中的不同位置),要么是复制和删除操作的组合。这种设计的哲学意图是确保在移动失败时,文件不会碎片化。

mv 不同,cp 命令会在文件系统中创建一个全新的数据对象,它有一个新的 inode 位置,并取决于 umask。你可以使用 cprm(如果有的话,或者 trash —— LCTT 译注:它是一个命令行回收站工具)命令来模仿 mv 命令。

$ cp example/foo .
$ ls -l -G -g --inode
7476869 -rwxrwxr-x. 29545 Aug  2 11:58 foo
$ trash example/foo

示例中的新 foo 文件获得了 755 权限,因为此处的 umask 明确排除了写入权限。

$ umask
0002

有关 umask 的更多信息,阅读 Alex Juarez 这篇关于文件权限的文章。

查看和删除

与复制和删除类似,使用 cat(或 tac)命令在创建“移动”文件时分配不同的权限。假设当前目录中是一个没有 foo 的新测试环境:

$ cat example/foo > foo
$ ls -l -G -g --inode
7476869 -rw-rw-r--. 29545 Aug 8 12:21 foo
$ trash example/foo

这次,创建了一个没有事先设置权限的新文件,所以文件最终权限完全取决于 umask 设置,它不会阻止用户和组的权限位(无论 umask 是什么,都不会为新文件授予可执行权限),但它会阻止其他人的写入(值为 2)。所以结果是一个权限是 664 的文件。

Rsync

rsync 命令是一个强大的多功能工具,用于在主机和文件系统位置之间发送文件。此命令有许多可用选项,包括使其目标镜像成为源。

你可以使用带有 --remove-source-files 选项的 rsync 复制,然后删除文件,并可以带上你选择执行同步的任何其他选项(常见的通用选项是 --archive):

$ rsync --archive --remove-source-files example/foo .
$ ls example
bar  baz
$ ls -lGgi
7476870 -rwxrwxrwx. 1 seth users 29545 Aug 8 12:23 foo

在这里,你可以看到保留了文件权限和所有权,只是更新了时间戳,并删除了源文件。

警告:不要将此选项与 --delete 混淆,后者会从目标目录中删除(源目录中不存在的)文件。误用 --delete 会清除很多数据,建议你不要使用此选项,除非是在测试环境中。

你可以覆盖其中一些默认值,更改权限和修改设置:

$ rsync --chmod=666 --times \
    --remove-source-files example/foo .
$ ls example
bar  baz
$ ls -lGgi
7476871 -rw-rw-r--. 1 seth users 29545 Aug 8 12:55 foo

这里,目标的 umask 会生效,因此 --chmod=666 选项会产生一个权限为 644 的文件。

好处不仅仅是权限,与简单的 mv 命令相比,rsync 命令有很多有用的选项(其中最重要的是 --exclude 选项,这样你可以在一个大型移动操作中排除某些项目),这使它成为一个更强大的工具。例如,要在移动文件集合时排除所有备份文件:

$ rsync --chmod=666 --times \
    --exclude '*~' \
    --remove-source-files example/foo .

使用 install 设置权限

install 命令是一个专门面向开发人员的复制命令,主要是作为软件编译安装例程的一部分调用。它并不为用户所知(我经常想知道为什么它有这么一个直观的名字,而剩下的包管理器却只能使用缩写和昵称),但是 install 实际上是一种将文件放在你想要地方的有用方法。

install 命令有很多选项,包括 --backup--compare 命令(以避免更新文件的新副本)。

cpcat 命令不同,但与 mv 完全相同,install 命令可以在复制文件的同时而保留其时间戳:

$ install --preserve-timestamp example/foo .
$ ls -l -G -g --inode
7476869 -rwxr-xr-x. 1 29545 Aug  2 07:28 foo
$ trash example/foo

在这里,文件被复制到一个新的 inode,但它的 mtime(修改时间)没有改变。但权限被设置为 install 的默认值 755

你可以使用 install 来设置文件的权限,所有者和组:

$ install --preserve-timestamp \
    --owner=skenlon \
    --group=dialout \
    --mode=666 example/foo .
$ ls -li
7476869 -rw-rw-rw-. 1 skenlon dialout 29545 Aug  2 07:28 foo
$ trash example/foo

移动、复制和删除

文件包含数据,而真正重要的文件包含你的数据。学会聪明地管理它们是很重要的,现在你有了确保以你想要的方式来处理数据的工具包。

你是否有不同的数据管理方式?在评论中告诉我们你的想法。


via: https://opensource.com/article/19/8/moving-files-linux-without-mv

作者:Seth Kenlon 选题:lujun9972 译者:MjSeven 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

像源代码一样对待时间并在 Git 的帮助下维护你的日历。

Git 是一个少有的能将如此多的现代计算封装到一个程序之中的应用程序,它可以用作许多其他应用程序的计算引擎。虽然它以跟踪软件开发中的源代码更改而闻名,但它还有许多其他用途,可以让你的生活更轻松、更有条理。在这个 Git 系列中,我们将分享七种鲜为人知的使用 Git 的方法。

今天,我们将使用 Git 来跟踪你的日历。

使用 Git 跟踪你的日程安排

如果时间本身只是可以管理和版本控制的源代码呢?虽然证明或反驳这种理论可能超出了本文的范围,但在 Git 的帮助下,你可以将时间视为源代码并管理你的日程安排。

日历的卫冕冠军是 CalDAV 协议,它支撑了如 NextCloud 这样的流行的开源及闭源的日历应用程序。CalDAV 没什么问题(评论者,请注意),但它并不适合所有人,除此之外,它还有一种不同于单一文化的鼓舞人心的东西。

因为我对大量使用 GUI 的 CalDAV 客户端没有兴趣(如果你正在寻找一个好的终端 CalDAV 查看器,请参阅 khal),我开始研究基于文本的替代方案。基于文本的日历具有在明文中工作的所有常见好处。它很轻巧,非常便携,只要它结构化,就很容易解析和美化(无论美丽对你意味着什么)。

最重要的是,它正是 Git 旨在管理的内容。

Org 模式不是一种可怕的方式

如果你没有对你的明文添加结构,它很快就会陷入一种天马行空般的混乱,变成恶魔才能懂的符号。幸运的是,有一种用于日历的标记语法,它包含在令人尊敬的生产力 Emacs 模式 —— Org 模式 中(承认吧,你其实一直想开始使用它)。

许多人没有意识到 Org 模式的惊人之处在于你不需要知道甚至不需要使用 Emacs来利用 Org 模式建立的约定。如果你使用 Emacs,你会得到许多很棒的功能,但是如果 Emacs 对你来说太难了,那么你可以实现一个基于 Git 的 Org 模式的日历系统,而不需要安装 Emacs。

关于 Org 模式你唯一需要知道的部分是它的语法。Org 模式的语法维护成本低、直观。使用 Org 模式而不是 GUI 日历应用程序进行日历记录的最大区别在于工作流程:你可以创建一个任务列表,然后每天分配一个任务,而不是转到日历并查找要安排任务的日期。

组织模式中的列表使用星号(*)作为项目符号。这是我的游戏任务列表:

* Gaming
** Build Stardrifter character
** Read Stardrifter rules
** Stardrifter playtest

** Blue Planet @ Mike's

** Run Rappan Athuk
*** Purchase hard copy
*** Skim Rappan Athuk
*** Build Rappan Athuk maps in maptool
*** Sort Rappan Athuk tokens

如果你熟悉 CommonMark 或 Markdown,你会注意到,Org 模式不是使用空格来创建子任务,而是更明确地使用了其它项目符号。无论你的使用背景和列表是什么,这都是一种构建列表的直观且简单的方法,它显然与 Emacs 没有内在联系(尽管使用 Emacs 为你提供了快捷方式,因此你可以快速地重新排列列表)。

要将列表转换为日历中的计划任务或事件,请返回并添加关键字 SCHEDULED 和(可选):CATEGORY:

* Gaming
:CATEGORY: Game
** Build Stardrifter character
SCHEDULED: <2019-03-22 18:00-19:00>
** Read Stardrifter rules
SCHEDULED: <2019-03-22 19:00-21:00>
** Stardrifter playtest
SCHEDULED: <2019-03-25 0900-1300>
** Blue Planet @ Mike's
SCHEDULED: <2019-03-18 18:00-23:00 +1w>

and so on...

SCHEDULED 关键字将该条目标记为你希望收到通知的事件,并且可选的 :CATEGORY: 关键字是一个可供你自己使用的任意标记系统(在 Emacs 中,你可以根据类别对条目使用颜色代码)。

对于重复事件,你可以使用符号(如+1w)创建每周事件或 +2w 以进行每两周一次的事件,依此类推。

所有可用于 Org 模式的花哨标记都记录于文档,所以不要犹豫,找到更多技巧来让它满足你的需求。

放进 Git

如果没有 Git,你的 Org 模式的日程安排只不过是本地计算机上的文件。这是 21 世纪,所以你至少需要可以在手机上使用你的日历,即便不是在你所有的个人电脑上。你可以使用 Git 为自己和他人发布日历。

首先,为 .org 文件创建一个目录。我将我的存储在 ~/cal 中。

$ mkdir ~/cal

转到你的目录并使其成为 Git 存储库:

$ cd cal
$ git init

.org 文件移动到你本地的 Git 存储库。在实践中,我为每个类别维护一个 .org 文件。

$ mv ~/*.org ~/cal
$ ls
Game.org Meal.org Seth.org Work.org

暂存并提交你的文件:

$ git add *.org
$ git commit -m 'cal init'

创建一个 Git 远程源

要在任何地方提供日历,你必须在互联网上拥有 Git 存储库。你的日历是纯文本,因此任何 Git 存储库都可以。你可以将日历放在 GitLab 或任何其他公共 Git 托管服务(甚至是专有服务)上,只要你的主机允许,你甚至可以将该存储库标记为私有库。如果你不想将日历发布到你无法控制的服务器,则可以自行托管 Git 存储库,或者为单个用户使用裸存储库,或者使用 GitoliteGitea 等前端服务。

为了简单起见,我将假设一个自托管的 Git 裸存储库。你可以使用 Git 命令在任何具有 SSH 访问权限的服务器上创建一个远程裸存储库:

$ ssh -p 22122 [[email protected]][14]
[remote]$ mkdir cal.git
[remote]$ cd cal.git
[remote]$ git init --bare
[remote]$ exit

这个裸存储库可以作为你日历在互联网上的家。

将其设置为本地 Git 存储库(在你的计算机上,而不是你的服务器上)的远程源:

$ git remote add origin [email protected]:/home/seth/cal.git

然后推送你的日历到该服务器:

$ git push -u origin HEAD

将你的日历放在 Git 存储库中,就可以在任何运行 Git 的设备上使用它。这意味着你可以对计划进行更新和更改,并将更改推送到上游,以便在任何地方进行更新。

我使用这种方法使我的日历在我的工作笔记本电脑和家庭工作站之间保持同步。由于我每天大部分时间都在使用 Emacs,因此能够在 Emacs 中查看和编辑我的日历是一个很大的便利。对于大多数使用移动设备的人来说也是如此,因此下一步是在移动设备上设置 Org 模式的日历系统。

移动设备上的 Git

由于你的日历数据是纯文本的,严格来说,你可以在任何可以读取文本文件的设备上“使用”它。这是这个系统之美的一部分;你永远不会缺少原始数据。但是,要按照你希望的现代日历的工作方式将日历集成到移动设备上,你需要两个组件:移动设备上的 Git 客户端和 Org 模式查看器。

移动设备上的 Git 客户端

MGit 是 Android 上的优秀 Git 客户端。同样,iOS 也有 Git 客户端。

一旦安装了 MGit(或类似的 Git 客户端),你必须克隆日历存储库,以便在你的手机上有副本。要从移动设备访问服务器,必须设置 SSH 密钥进行身份验证。MGit 可以为你生成和存储密钥,你必须将其添加到服务器的 ~/.ssh/authorized_keys 文件或托管的 Git 的帐户设置中的 SSH 密钥中。

你必须手动执行此操作。MGit 没有登录你的服务器或托管的 Git 帐户的界面。如果你不这样做,你的移动设备将无法访问你的服务器以访问你的日历数据。

我是通过将我在 MGit 中生成的密钥文件通过 KDE Connect 复制到我的笔记本电脑来实现的(但你可以通过蓝牙、SD 卡读卡器或 USB 电缆进行相同操作,具体取决于你访问手机上的数据的首选方法)。 我用这个命令将密钥(一个名为 calkey 的文件)复制到我的服务器:

$ cat calkey | ssh [email protected] "cat >> /home/seth/.ssh/authorized_keys"

你可能有不同的方法,但如果你曾经将服务器设置为无密码登录,这是完全相同的过程。如果你使用的是 GitLab 等托管的 Git 服务,则必须将密钥文件的内容复制并粘贴到用户帐户的 SSH 密钥面板中。

 title=

完成后,你的移动设备可以向你的服务器授权,但仍需要知道在哪里查找你的日历数据。不同的应用程序可能使用不同的表示法,但 MGit 使用普通的旧式 Git-over-SSH。这意味着如果你使用的是非标准 SSH 端口,则必须指定要使用的 SSH 端口:

$ git clone ssh://[email protected]:22122//home/seth/git/cal.git

 title=

如果你使用其他应用程序,它可能会使用不同的语法,允许你在特殊字段中提供端口,或删除 ssh:// 前缀。如果遇到问题,请参阅应用程序文档。

将存储库克隆到手机。

 title=

很少有 Git 应用程序设置为自动更新存储库。有一些应用程序可以用来自动拉取,或者你可以设置 Git 钩子来推送服务器的更新 —— 但我不会在这里讨论这些。目前,在对日历进行更新后,请务必在 MGit 中手动提取新更改(或者如果在手机上更改了事件,请将更改推送到服务器)。

 title=

移动设备上的日历

有一些应用程序可以为移动设备上的 Org 模式提供前端。Orgzly 是一个很棒的开源 Android 应用程序,它为 Org 模式的从 Agenda 模式到 TODO 列表的大多数功能提供了一个界面。安装并启动它。

从主菜单中,选择“设置同步存储库”,然后选择包含日历文件的目录(即,从服务器克隆的 Git 存储库)。

给 Orgzly 一点时间来导入数据,然后使用 Orgzly 的汉堡包菜单选择日程视图。

 title=

在 Orgzly 的“设置提醒”菜单中,你可以选择在手机上触发通知的事件类型。你可以获得 SCHEDULED 任务,DEADLINE 任务或任何分配了事件时间的任何通知。如果你将手机用作任务管理器,那么你将永远不会错过 Org 模式和 Orgzly 的活动。

 title=

Orgzly 不仅仅是一个解析器。你可以编辑和更新事件,甚至标记事件为 DONE

 title=

专为你而设计

关于使用 Org 模式和 Git 的重要一点是,这两个应用程序都非常灵活,并且你可以自定义它们的工作方式和内容,以便它们能够适应你的需求。如果本文中的内容是对你如何组织生活或管理每周时间表的冒犯,但你喜欢此提案提供的其他部分,那么请丢弃你不喜欢的部分。如果需要,你可以在 Emacs 中使用 Org 模式,或者你可以将其用作日历标记。你可以将手机设置为在一天结束时从计算机上拉取 Git 数据,而不是从互联网上的服务器上,或者你可以将计算机配置为在手机插入时同步日历,或者你可以每天管理它,就像你把你工作日所需的所有东西都装到你的手机上一样。这取决于你,而这是关于 Git、Org 模式和开源的最重要的事情。


via: https://opensource.com/article/19/4/calendar-git

作者:Seth Kenlon 选题:lujun9972 译者:wxy 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

使用 Python 类使你的代码变得更加模块化。

在我上一篇文章中,我解释了如何通过使用函数、创建模块或者两者一起来使 Python 代码更加模块化。函数对于避免重复多次使用的代码非常有用,而模块可以确保你在不同的项目中复用代码。但是模块化还有另一种方法:类。

如果你已经听过 面向对象编程 object-oriented programming (OOP)这个术语,那么你可能会对类的用途有一些概念。程序员倾向于将类视为一个虚拟对象,有时与物理世界中的某些东西直接相关,有时则作为某种编程概念的表现形式。无论哪种表示,当你想要在程序中为你或程序的其他部分创建“对象”时,你都可以创建一个类来交互。

没有类的模板

假设你正在编写一个以幻想世界为背景的游戏,并且你需要这个应用程序能够涌现出各种坏蛋来给玩家的生活带来一些刺激。了解了很多关于函数的知识后,你可能会认为这听起来像是函数的一个教科书案例:需要经常重复的代码,但是在调用时可以考虑变量而只编写一次。

下面一个纯粹基于函数的敌人生成器实现的例子:

#!/usr/bin/env python3

import random

def enemy(ancestry,gear):
    enemy=ancestry
    weapon=gear
    hp=random.randrange(0,20)
    ac=random.randrange(0,20)
    return [enemy,weapon,hp,ac]

def fight(tgt):
    print("You take a swing at the " + tgt[0] + ".")
    hit=random.randrange(0,20)
    if hit > tgt[3]:
        print("You hit the " + tgt[0] + " for " + str(hit) + " damage!")
        tgt[2] = tgt[2] - hit
    else:
        print("You missed.")


foe=enemy("troll","great axe")
print("You meet a " + foe[0] + " wielding a " + foe[1])
print("Type the a key and then RETURN to attack.")

while True:
    action=input()

    if action.lower() == "a":
        fight(foe)

    if foe[2] < 1:
        print("You killed your foe!")
    else:
        print("The " + foe[0] + " has " + str(foe[2]) + " HP remaining")

enemy 函数创造了一个具有多个属性的敌人,例如谱系、武器、生命值和防御等级。它返回每个属性的列表,表示敌人全部特征。

从某种意义上说,这段代码创建了一个对象,即使它还没有使用类。程序员将这个 enemy 称为对象,因为该函数的结果(本例中是一个包含字符串和整数的列表)表示游戏中一个单独但复杂的东西。也就是说,列表中字符串和整数不是任意的:它们一起描述了一个虚拟对象。

在编写描述符集合时,你可以使用变量,以便随时使用它们来生成敌人。这有点像模板。

在示例代码中,当需要对象的属性时,会检索相应的列表项。例如,要获取敌人的谱系,代码会查询 foe[0],对于生命值,会查询 foe[2],以此类推。

这种方法没有什么不妥,代码按预期运行。你可以添加更多不同类型的敌人,创建一个敌人类型列表,并在敌人创建期间从列表中随机选择,等等,它工作得很好。实际上,Lua 非常有效地利用这个原理来近似了一个面向对象模型。

然而,有时候对象不仅仅是属性列表。

使用对象

在 Python 中,一切都是对象。你在 Python 中创建的任何东西都是某个预定义模板的实例。甚至基本的字符串和整数都是 Python type 类的衍生物。你可以在这个交互式 Python shell 中见证:

>>> foo=3
>>> type(foo)
<class 'int'>
>>> foo="bar"
>>> type(foo)
<class 'str'>

当一个对象由一个类定义时,它不仅仅是一个属性的集合,Python 类具有各自的函数。从逻辑上讲,这很方便,因为只涉及某个对象类的操作包含在该对象的类中。

在示例代码中,fight 的代码是主应用程序的功能。这对于一个简单的游戏来说是可行的,但对于一个复杂的游戏来说,世界中不仅仅有玩家和敌人,还可能有城镇居民、牲畜、建筑物、森林等等,它们都不需要使用战斗功能。将战斗代码放在敌人的类中意味着你的代码更有条理,在一个复杂的应用程序中,这是一个重要的优势。

此外,每个类都有特权访问自己的本地变量。例如,敌人的生命值,除了某些功能之外,是不会改变的数据。游戏中的随机蝴蝶不应该意外地将敌人的生命值降低到 0。理想情况下,即使没有类,也不会发生这种情况。但是在具有大量活动部件的复杂应用程序中,确保不需要相互交互的部件永远不会发生这种情况,这是一个非常有用的技巧。

Python 类也受垃圾收集的影响。当不再使用类的实例时,它将被移出内存。你可能永远不知道这种情况会什么时候发生,但是你往往知道什么时候它不会发生,因为你的应用程序占用了更多的内存,而且运行速度比较慢。将数据集隔离到类中可以帮助 Python 跟踪哪些数据正在使用,哪些不在需要了。

优雅的 Python

下面是一个同样简单的战斗游戏,使用了 Enemy 类:

#!/usr/bin/env python3

import random

class Enemy():
    def __init__(self,ancestry,gear):
        self.enemy=ancestry
        self.weapon=gear
        self.hp=random.randrange(10,20)
        self.ac=random.randrange(12,20)
        self.alive=True

    def fight(self,tgt):
        print("You take a swing at the " + self.enemy + ".")
        hit=random.randrange(0,20)

        if self.alive and hit > self.ac:
            print("You hit the " + self.enemy + " for " + str(hit) + " damage!")
            self.hp = self.hp - hit
            print("The " + self.enemy + " has " + str(self.hp) + " HP remaining")
        else:
            print("You missed.")

        if self.hp < 1:
            self.alive=False

# 游戏开始
foe=Enemy("troll","great axe")
print("You meet a " + foe.enemy + " wielding a " + foe.weapon)

# 主函数循环
while True:
   
    print("Type the a key and then RETURN to attack.")
        
    action=input()

    if action.lower() == "a":
        foe.fight(foe)
                
    if foe.alive == False:
        print("You have won...this time.")
        exit()

这个版本的游戏将敌人作为一个包含相同属性(谱系、武器、生命值和防御)的对象来处理,并添加一个新的属性来衡量敌人时候已被击败,以及一个战斗功能。

类的第一个函数是一个特殊的函数,在 Python 中称为 init 或初始化的函数。这类似于其他语言中的构造器,它创建了类的一个实例,你可以通过它的属性和调用类时使用的任何变量来识别它(示例代码中的 foe)。

Self 和类实例

类的函数接受一种你在类之外看不到的新形式的输入:self。如果不包含 self,那么当你调用类函数时,Python 无法知道要使用的类的哪个实例。这就像在一间充满兽人的房间里说:“我要和兽人战斗”,向一个兽人发起。没有人知道你指的是谁,所有兽人就都上来了。

 title=

CC-BY-SA by Buch on opengameart.org

类中创建的每个属性都以 self 符号作为前缀,该符号将变量标识为类的属性。一旦派生出类的实例,就用表示该实例的变量替换掉 self 前缀。使用这个技巧,你可以在一间满是兽人的房间里说:“我要和谱系是 orc 的兽人战斗”,这样来挑战一个兽人。当 orc 听到 “gorblar.orc” 时,它就知道你指的是谁(他自己),所以你得到是一场公平的战斗而不是斗殴。在 Python 中:

gorblar=Enemy("orc","sword")
print("The " + gorblar.enemy + " has " + str(gorblar.hp) + " remaining.")

通过检索类属性(gorblar.enemygorblar.hp 或你需要的任何对象的任何值)而不是查询 foe[0](在函数示例中)或 gorblar[0] 来寻找敌人。

本地变量

如果类中的变量没有以 self 关键字作为前缀,那么它就是一个局部变量,就像在函数中一样。例如,无论你做什么,你都无法访问 Enemy.fight 类之外的 hit 变量:

>>> print(foe.hit)
Traceback (most recent call last):
  File "./enclass.py", line 38, in <module>
    print(foe.hit)
AttributeError: 'Enemy' object has no attribute 'hit'

>>> print(foe.fight.hit)
Traceback (most recent call last):
  File "./enclass.py", line 38, in <module>
    print(foe.fight.hit)
AttributeError: 'function' object has no attribute 'hit'

hit 变量包含在 Enemy 类中,并且只能“存活”到在战斗中发挥作用。

更模块化

本例使用与主应用程序相同的文本文档中的类。在一个复杂的游戏中,我们更容易将每个类看作是自己独立的应用程序。当多个开发人员处理同一个应用程序时,你会看到这一点:一个开发人员负责一个类,另一个开发人员负责主程序,只要他们彼此沟通这个类必须具有什么属性,就可以并行地开发这两个代码块。

要使这个示例游戏模块化,可以把它拆分为两个文件:一个用于主应用程序,另一个用于类。如果它是一个更复杂的应用程序,你可能每个类都有一个文件,或每个逻辑类组有一个文件(例如,用于建筑物的文件,用于自然环境的文件,用于敌人或 NPC 的文件等)。

将只包含 Enemy 类的一个文件保存为 enemy.py,将另一个包含其他内容的文件保存为 main.py

以下是 enemy.py

import random

class Enemy():
    def __init__(self,ancestry,gear):
        self.enemy=ancestry
        self.weapon=gear
        self.hp=random.randrange(10,20)
        self.stg=random.randrange(0,20)
        self.ac=random.randrange(0,20)
        self.alive=True

    def fight(self,tgt):
        print("You take a swing at the " + self.enemy + ".")
        hit=random.randrange(0,20)

        if self.alive and hit > self.ac:
            print("You hit the " + self.enemy + " for " + str(hit) + " damage!")
            self.hp = self.hp - hit
            print("The " + self.enemy + " has " + str(self.hp) + " HP remaining")
        else:
            print("You missed.")

        if self.hp < 1:
            self.alive=False

以下是 main.py

#!/usr/bin/env python3

import enemy as en

# game start
foe=en.Enemy("troll","great axe")
print("You meet a " + foe.enemy + " wielding a " + foe.weapon)

# main loop
while True:
   
    print("Type the a key and then RETURN to attack.")

    action=input()

    if action.lower() == "a":
        foe.fight(foe)

    if foe.alive == False:
        print("You have won...this time.")
        exit()

导入模块 enemy.py 使用了一条特别的语句,引用类文件名称而不用带有 .py 扩展名,后跟你选择的命名空间指示符(例如,import enemy as en)。这个指示符是在你调用类时在代码中使用的。你需要在导入时添加指示符,例如 en.Enemy,而不是只使用 Enemy()

所有这些文件名都是任意的,尽管在原则上不要使用罕见的名称。将应用程序的中心命名为 main.py 是一个常见约定,和一个充满类的文件通常以小写形式命名,其中的类都以大写字母开头。是否遵循这些约定不会影响应用程序的运行方式,但它确实使经验丰富的 Python 程序员更容易快速理解应用程序的工作方式。

在如何构建代码方面有一些灵活性。例如,使用该示例代码,两个文件必须位于同一目录中。如果你只想将类打包为模块,那么必须创建一个名为 mybad 的目录,并将你的类移入其中。在 main.py 中,你的 import 语句稍有变化:

from mybad import enemy as en

两种方法都会产生相同的结果,但如果你创建的类足够通用,你认为其他开发人员可以在他们的项目中使用它们,那么后者更好。

无论你选择哪种方式,都可以启动游戏的模块化版本:

$ python3 ./main.py 
You meet a troll wielding a great axe
Type the a key and then RETURN to attack.
a
You take a swing at the troll.
You missed.
Type the a key and then RETURN to attack.
a
You take a swing at the troll.
You hit the troll for 8 damage!
The troll has 4 HP remaining
Type the a key and then RETURN to attack.
a
You take a swing at the troll.
You hit the troll for 11 damage!
The troll has -7 HP remaining
You have won...this time.

游戏启动了,它现在更加模块化了。现在你知道了面向对象的应用程序意味着什么,但最重要的是,当你向兽人发起决斗的时候,你知道是哪一个。


via: https://opensource.com/article/19/7/get-modular-python-classes

作者:Seth Kenlon 选题:lujun9972 译者:MjSeven 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

作为系统更新的一部分,你也许需要在基于 Red Hat 系统中由于应用依赖排除一些软件包。

如果是,如何排除?可以采取多少种方式?有三种方式可以做到,我们会在本篇中教你这三种方法。

包管理器是一组工具,它允许用户在 Linux 系统中轻松管理包。它能让用户在 Linux 系统中安装、更新/升级、删除、查询、重新安装和搜索软件包。

对于基于 Red Hat 的系统,我们使用 yum 包管理器rpm 包管理器 进行包管理。

什么是 yum?

yum 代表 “Yellowdog Updater, Modified”。Yum 是用于 rpm 系统的自动更新程序和包安装/卸载器。

它在安装包时自动解决依赖关系。

什么是 rpm?

rpm 代表 “Red Hat Package Manager”,它是一款用于 Red Hat 系统的功能强大的包管理工具。

RPM 指的是 .rpm 文件格式,它包含已编译的软件和必要的库。

你可能有兴趣阅读以下与本主题相关的文章。如果是的话,请进入相应的链接。

方法 1:手动或临时用 yum 命令排除包

我们可以在 yum 中使用 --exclude-x 开关来阻止 yum 命令获取特定包的更新。

我可以说,这是一种临时方法或按需方法。如果你只想将特定包排除一次,那么我们可以使用此方法。

以下命令将更新除 kernel 之外的所有软件包。

要排除单个包:

# yum update --exclude=kernel
或者
# yum update -x 'kernel'

要排除多个包。以下命令将更新除 kernel 和 php 之外的所有软件包。

# yum update --exclude=kernel* --exclude=php*
或者
# yum update --exclude httpd,php

方法 2:在 yum 命令中永久排除软件包

这是永久性方法,如果你经常执行修补程序更新,那么可以使用此方法。

为此,请在 /etc/yum.conf 中添加相应的软件包以永久禁用软件包更新。

添加后,每次运行 yum update 命令时都不需要指定这些包。此外,这可以防止任何意外更新这些包。

# vi /etc/yum.conf

[main]
cachedir=/var/cache/yum/$basearch/$releasever
keepcache=0
debuglevel=2
logfile=/var/log/yum.log
exactarch=1
obsoletes=1
gpgcheck=1
plugins=1
installonly_limit=3
exclude=kernel* php*

方法 3:使用 Yum versionlock 插件排除包

这也是与上面类似的永久方法。Yum versionlock 插件允许用户通过 yum 命令锁定指定包的更新。

为此,请运行以下命令。以下命令将从 yum update 中排除 freetype 包。

或者,你可以直接在 /etc/yum/pluginconf.d/versionlock.list 中添加条目。

# yum versionlock add freetype

Loaded plugins: changelog, package_upload, product-id, search-disabled-repos, subscription-manager, verify, versionlock
Adding versionlock on: 0:freetype-2.8-12.el7
versionlock added: 1

运行以下命令来检查被 versionlock 插件锁定的软件包列表。

# yum versionlock list

Loaded plugins: changelog, package_upload, product-id, search-disabled-repos, subscription-manager, verify, versionlock
0:freetype-2.8-12.el7.*
versionlock list done

运行以下命令清空该列表。

# yum versionlock clear

via: https://www.2daygeek.com/redhat-centos-yum-update-exclude-specific-packages/

作者:Magesh Maruthamuthu 选题:lujun9972 译者:geekpi 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

让 DevOps 少一点,OpsDev 多一点。

在这个 DevOps 世界中,看起来开发(Dev)这一半成为了关注的焦点,而运维(Ops)则是这个关系中被遗忘的另一半。这几乎就好像是领头的开发告诉尾随的运维做什么,几乎所有的“运维”都是开发说要做的。因此,运维被抛到后面,降级到了替补席上。

我想看到更多的 OpsDev。因此,让我们来看看 Ansible 在日常的运维中可以帮助你什么。

 title=

我选择在 Ansible Tower 中展示这些方案,因为我认为用户界面 (UI) 可以增色大多数的任务。如果你想模拟测试,你可以在 Tower 的上游开源版本 AWX 中测试它。

管理用户

在大规模环境中,你的用户将集中在活动目录或 LDAP 等系统中。但我敢打赌,仍然存在许多包含大量的静态用户的全负荷环境。Ansible 可以帮助你将这些分散的环境集中到一起。社区已为我们解决了这个问题。看看 Ansible Galaxy 中的 users 角色。

这个角色的聪明之处在于它允许我们通过数据管理用户,而无需更改运行逻辑。

 title=

通过简单的数据结构,我们可以在系统上添加、删除和修改静态用户。这很有用。

管理 sudo

提权有多种形式,但最流行的是 sudo。通过每个 usergroup 等离散文件来管理 sudo 相对容易。但一些人对给予特权感到紧张,并倾向于有时限地给予提权。因此下面是一种方案,它使用简单的 at 命令对授权访问设置时间限制。

 title=

管理服务

给入门级运维团队提供菜单以便他们可以重启某些服务不是很好吗?看下面!

 title=

管理磁盘空间

这有一个简单的角色,可在特定目录中查找字节大于某个大小的文件。在 Tower 中这么做时,启用回调有额外的好处。想象一下,你的监控方案发现文件系统已超过 X% 并触发 Tower 中的任务以找出是什么文件导致的。

 title=

调试系统性能问题

这个角色相当简单:它运行一些命令并打印输出。细节在最后输出,让你 —— 系统管理员快速浏览一眼。另外可以使用 正则表达式 在输出中找到某些条件(比如说 CPU 占用率超过 80%)。

 title=

总结

我已经录制了这五个任务的简短视频。你也可以在 Github 上找到所有代码


via: https://opensource.com/article/19/8/ops-tasks-ansible

作者:Mark Phillips 选题:lujun9972 译者:geekpi 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出