2018年1月

Q:我需要将所有包含 *.c 文件的文件夹从名为 hostA 的本地笔记本复制到 hostB。我使用的是下面的 scp 命令,但不知道如何排除特定的文件(如 *.out):

$ scp -r ~/projects/ user@hostB:/home/delta/projects/

如何告诉 scp 命令在 Linux/Unix 命令行中排除特定的文件或目录?

人们可以使用 scp 命令在网络主机之间安全地复制文件。它使用 ssh 进行数据传输和身份验证。典型的语法是:

scp file1 user@host:/path/to/dest/
scp -r /path/to/source/ user@host:/path/to/dest/ 

scp 排除文件

我不认为你可以在使用 scp 命令时过滤或排除文件。但是,有一个很好的解决方法来排除文件并使用 ssh 安全地复制它。本页面说明如何在使用 scp 递归复制目录时过滤或排除文件。

如何使用 rsync 命令排除文件

语法是:

rsync av -e ssh --exclude='*.out' /path/to/source/ user@hostB:/path/to/dest/

这里:

  1. -a :递归到目录,即复制所有文件和子目录。另外,打开归档模式和所有其他选项(相当于 -rlptgoD
  2. -v :详细输出
  3. -e ssh :使用 ssh 作为远程 shell,这样所有的东西都被加密
  4. --exclude='*.out' :排除匹配模式的文件,例如 *.out 或 *.c 等。

rsync 命令的例子

在这个例子中,从 ~/virt/ 目录递归地复制所有文件,但排除所有 *.new 文件:

$ rsync -av -e ssh --exclude='*.new' ~/virt/ root@centos7:/tmp

示例输出:

Scp exclude files but using rsync exclude command

如果远程服务器上找不到 rsync,那么 rsync 命令将失败。在这种情况下,请尝试使用以下 scp 命令,该命令在当前目录中使用 bash shell 模式匹配 (它不能与 -r 选项一起使用):

$ ls

示例输出:

centos71.log centos71.qcow2 centos71.qcow2.new centos71.v2.qcow2.new meta-data user-data

复制除 .new 之外的当前目录中的所有内容:

$ shopt -s extglob
$ scp !(*.new) root@centos7:/tmp/

示例输出:

centos71.log 100 % 4262 1.3MB/s 00:00
centos71.qcow2 100 % 836MB 32.7MB/s 00: 25 
meta-data 100 % 47 18.5KB/s 00:00
user-data 100 % 1543 569.7KB/s 00:00

有关更多信息,请参阅以下手册页:

$ man rsync
$ man bash
$ man scp

via: https://www.cyberciti.biz/faq/scp-exclude-files-when-using-command-recursively-on-unix-linux/

作者:Vivek Gite 译者:geekpi 校对:wxy

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

这篇文章对 Linux 图形环境做了一番介绍,展示了在不同的 Linux 发行版上的各种选择。

这是我们迁移到 Linux 系统系列的第三篇文章。如果你错过了先前的两篇,这里有两文的链接《入门介绍》 和 《磁盘、文件、和文件系统》。本文中,我们将讨论图形操作环境。在 Linux 系统中,你可以依照喜好选择并且定制一个图形界面,你有很大的选择余地,这也是 Linux 优越的体验之一。

一些主流的 Linux 图形界面包括:Cinnamon、Gnome、KDE Plasma、Xfce 和 MATE,总之这里有很多选择。

有一点经常混淆 Linux 新手,虽然某个 Linux 系统分配了一个缺省的图形环境,但是一般你可以随时更换这个图形界面。这和 Windows 或 Mac OS 的惯用者的定势思维不同。安装图形环境是一件独立的事情,很多时候,Linux 和其图形环境的连接并不紧密。此外,你在一个图形环境构建运行的程序同样适用于另一个图形环境。比如说一个为 KDE Plasma 图形环境编写的应用程序完全适用于 Gnome 桌面图形环境。

由于人们熟悉 Windows 和 MacOS 系统,部分 Linux 操作系统的图形环境在一定程度上尝试着去模仿它们,但另一些 Linux 图形界面则是独特的。

下面,我将就一些不同的 Linux 发行版,展示几个 Linux 图形环境。如果你不确定应该采用那个 Linux 发行版,那我建议你从 Ubuntu 开始,获取其长期支持(LTS)的版本(Ubuntu 16.04.3 LTS 正在开发)。Ubuntu 稳定且真的非常好用。

由 Mac 过渡

Elementary OS 发行版提供了和 Mac 系统风格很接近的界面。它的默认图形环境被称作 Pantheon,是一款很适合 Mac 用户过渡使用的图形环境。这款图形界面发行版的屏幕底部有一个停靠栏,专为极简者使用而设计。为了保持简约的风格,很多默认的应用程序甚至都不会有自己的菜单。相反,它们的按钮和控件在应用程序的标题栏上(图 1)。

 title=

图 1: Elementary OS Pantheon.

Ubuntu 发行版提供的一个默认的图形界面,也和 Mac 相似。Ubuntu 17.04 或者更老的版本都使用 Unity 图形环境,Unity 停靠栏的默认位置在屏幕的左边,屏幕顶部有一个全局应用程序共享的菜单栏。

由 Windows 过渡

ChaletOS 亦步亦趋模仿 Windows 界面,可以帮助 Windows 用户轻松的过渡到 Linux。ChaletOS 使用的图形环境是 Xfce(图 2)。在屏幕的左下角有一个开始(主)菜单和搜索栏。屏幕的右下角是一个桌面图标和一些通知信息。这看起来和 Windows 非常像,乍一看,可能都会以为桌面跑的是 Windows。

ChaletOS

图 2: ChaletOS with Xfce.

Zorin OS 发行版同样尝试模仿 Windows。 Zorin OS 使用的 Gnome 的改进桌面,工作起来和 Windows 的图形界面很相似。左下角的开始按钮、右下角的通知栏和信息通知栏。开始按钮会弹出一个和 Windows 无异的应用程序列表和搜索框。

独有的图形环境

Gnome 桌面(图 3)是最常用的图形环境之一。许多发行版将 Gnome 作为默认的图形环境。Gnome 并不打算模仿 Windows 或是 MacOS,而是以其自身的优雅和易用为目标。

图 3:openSUSE with Gnome.

Gnome 桌面环境从版本 2 到 版本 3 发生了巨变,Cinnamon 环境为消除该改变带来的不利影响而创造。尽管 Cinnamon 和前辈 Gnome 2 外观不相似,但是它依旧尝试提供一个简约的界面,而且它的功能和 Windows XP 类似。

MATE 图形环境直接模仿于 Gnome 2,在它的屏幕顶部有一个用作设置和存放应用的菜单栏,底部提供了一个应用程序运行选项卡和一些其他组件。

KDE plasma 围绕组件界面而构建,组件可以安装在桌面或是面板上(图 4)。

 title=

图 4: 安装了 KDE Plasma 的 Kubuntu 操作系统。

没有那个图形环境比另外一个更好。不同的风格适用不同的用户风格。另外,如果选择太多无从下手,那就从 Ubuntu 开始吧。

相似与不同

不同的操作系统处理方式不同,这会给使用者的过渡带来挑战。比如说,菜单栏可能出现在不同的位置,然后设置有可能用不同的选项入口路径。我列举了一些相似或不同地方来帮助减少 Linux 调整。

鼠标

Linux 的鼠标通常和 Windows 与 MacOS 的工作方式有所差异。在 Windows 或 Mac,双击标签,你几乎可以打开任何事物,而这在 Linux 图形界面中很多都被设置为单击。

此外在 Windows 系统中,你通常通过单击窗口获取焦点。在 Linux,很多窗口的焦点获取方式被设置为鼠标悬停,即便鼠标悬停下的窗口并不在屏幕顶端。这种微妙的差异有时候会让人很吃惊。比如说,在 Windows 中,假如有一个后台应用(不在屏幕顶层),你移动鼠标到它的上面,不点击鼠标仅仅转动鼠标滚轮,顶层窗口会滚动。而在 Linux 中,后台窗口(鼠标悬停的那个窗口)会滚动。

菜单

应用菜单是电脑程序的一个主要集中位置,最近似乎可以调整移动菜单栏到不碍事的地方,甚至干脆完全删除。大概,当你迁移到 Linux,你可能找不到你期待的菜单。应用程序菜单会像 MacOS一样出现在全局共享菜单栏内。和很多移动应用程序一样,该菜单可能在“更多选项”的图标里。或者,这个菜单干脆被完全移除被一个按钮取代,正如在 Elementary OS Pantheon 环境里的一些程序一样。

工作空间

很多 Linux 图形环境提供了多个工作空间。一个工作空间包含的正在运行的程序窗口充盈了整个屏幕。切换到不同的工作空间将会改变程序的可见性。这个概念是把当前项目运行使用的全部应用程序分组到一个工作空间,而一些为另一个项目使用的应用程序会被分组到不同的工作空间。

不是每一个人都需要甚至是喜欢工作空间,但是我提到它是因为,作为一个新手,你可能无意间通过一个组合键切换了工作空间,然后,“喂!我的应用程序哪去了?” 如果你看到的还是你熟悉的桌面壁纸,那你可能只是切换了工作空间,你所有的应用程序还在一个工作空间运行,只是现在不可见而已。在很多 Linux 环境中,通过敲击 Alt+Ctrl 和一个箭头(上、下、左或右)可以切换工作空间。很有可能发现你的应用程序一直都在另一个工作空间里运行。

当然,如果你刚好喜欢工作空间(很多人都喜欢),然后你就发现了一个 Linux 很有用的默认功能。

设置

许多 Linux 图形环境提供一些类型的设置程序或是面板让你在机器上配置设置。值得注意的是类似 Windows 和 MacOS,Linux 可以配置好很多细节,但不是所有的详细设置都可以在设置程序上找到。但是这些设置项已经足够满足大部分典型的桌面系统,比如选择桌面壁纸,改变熄屏时间,连接打印机等其他一些设置。

和 Windows 或者 MacOS 相比,Linux 的应用程序设置的分组或是命名都有不同的方式。甚至同是 Linux 系统,不同的图形界面也会出现不同的设置,这可能需要时间适应。当然,在你的图形环境中设置配置的问题可以通过在线查询这样不错的方法解决。

应用程序

最后,Linux 的应用程序也可能不同。你可能会发现一些熟悉的应用程序,但是对你来说更多的将会是崭新的应用。比如说,你能在 Linux 上找到 Firefox、Chrome 和 Skype。如果不能找到特定的应用程序,通常你能使用一些替代程序。如果还是不能,那你可以使用 WINE 这样的兼容层来运行 Windows 的应用程序。

在很多 Linux 图形环境中,你可以通过敲击 Windows 的标志键来打开应用程序菜单栏。在其他一些情况中,你不得不点击开始(主)按钮或应用程序菜单。很多图形环境中,你可以通过分类搜索到应用程序而不一定需要它的特定程序名。比如说,你要使用一个你不清楚名字的编辑器程序,这时候,你可以在应用程序菜单栏键的搜索框中键入“editor”字样,它将为你展示一个甚至更多的被认为是编辑器类的应用程序。

为帮你起步,这里列举了一点可能成为 Linux 系统使用的替代程序。

请注意,Linux 提供了大量的满足你需求的选择,这张表里列举的一点也不完整。


via: https://www.linux.com/blog/learn/2017/12/migrating-linux-graphical-environments

作者:John Bonesio 译者:CYLeft 校对:wxy

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

《黑客帝国》是 1999 年,由 Wachowki 兄弟编导的科幻动作片。这部电影的荧屏里有无尽的绿色字符降落。数字雨模拟着《黑客帝国》中的虚拟现实活动。现在,Linux 和 Unix 终端上,你也可以通过 CMatrix 模仿出矩阵数字雨。

安装 cmatrix

根据你的 Linux/Unix 发行版或操作系统安装并且设置 CMatrix。

如何在 Debian/Ubuntu Linux 发行版中安装 cmatrix

在 Debian/Ubuntu/Mint 系统中键入以下命令 apt-get 命令/apt 命令

$ sudo apt install cmatrix

示例输出:

[sudo] password for vivek: 
Reading package lists... Done
Building dependency tree       
Reading state information... Done
Suggested packages:
  cmatrix-xfont
The following NEW packages will be installed:
  cmatrix
0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded.
Need to get 15.8 kB of archives.
After this operation, 50.2 kB of additional disk space will be used.
Get:1 http://in.archive.ubuntu.com/ubuntu artful/universe amd64 cmatrix amd64 1.2a-5build2 [15.8 kB]
Fetched 15.8 kB in 0s (19.7 kB/s)
Selecting previously unselected package cmatrix.
(Reading database ... 205388 files and directories currently installed.)
Preparing to unpack .../cmatrix_1.2a-5build2_amd64.deb ...
Unpacking cmatrix (1.2a-5build2) ...
Setting up cmatrix (1.2a-5build2) ...
Processing triggers for man-db (2.7.6.1-2) ...

如何在 Arch Linux 发行版安装 cmatrix

键入 pacman 命令:

$ sudo pacman -S cmatrix

如何在 FreeBCD 系统中安装 cmatrix

运行如下命令安装 port:

# cd /usr/ports/misc/cmatrix/ && make install clean

或者使用 pkg 命令添加二进制包:

# pkg install cmatrix

如何在 macOS Unix 发行版中安装 cmatrix

键入下列命令:

$ brew install cmatrix

如何在 OpenBSD 系统中安装 cmatrix

键入 pkg\_add 命令:

# pkg_add cmatrix

使用 cmatrix

简单键入命令:

$ cmatrix

cmtarix 运转中

使用键盘

在执行期间,下列按键有效(-s 模式下,按键无效):

按键说明
a切换异步滚动
b随机字符加粗
B全部字符加粗
n关闭字符加粗
0-9调整更新时间
! @ # $ % ^ & )改变对应的矩阵颜色: ! – 红、@ – 绿、# – 黄、$ – 蓝、% – 洋红、^ – 青、 & – 白、 ) – 黑。
q退出程序

你可以通过以下命令获取 cmatrix 选项:

$ cmatrix -h
  • -a: 异步滚动
  • -b: 开启字符加粗
  • -B: 所有字符加粗(优先于 -b 选项)
  • -f: 强制开启 Linux $TERM 模式
  • -l: Linux 模式(使用 matrix 控制台字体)
  • -o: 启用旧式滚动
  • -h: 输出使用说明并退出
  • -n: 关闭字符加粗 (优先于 -b and -B,默认)
  • -s: “屏保”模式, 第一次按键时退出
  • -x: X 窗口模式,如果你使用的时 mtx.pcf 终端
  • -V: 输出版本信息并且退出
  • -u delay (0 - 10,默认 4): 屏幕更新延时
  • -C [color]: 调整 matrix 颜色(默认绿色)

现在,你拥有了一款最炫酷的终端应用!


via: https://www.cyberciti.biz/open-source/command-line-hacks/matrix-digital-rain-on-linux-macos-unix-terminal/

作者:nixCraft 译者:CYLeft 校对:校对者ID

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

很多时候我们诸如 SD 卡和 U 盘这样的储存器可能会被损坏,并且因此或其他原因不能继续使用。

这可能是因为使用这个设备创建了一个引导媒体或者是通过错误的平台格式化亦或是创建了一个新的分区在这个设备上。

恢复损坏的 USB 设备至初始状态

Linux 系统磁盘管理器

警告:接下来的操作会将你设备上的所有数据格式化。

无论是上面提及的什么原因,最终的结果是我们无法继续使用这个设备。

所以这里有一个恢复 USB 设备或者是 SD 卡到出厂状态的方法。

大多数时候通过文件浏览器进行一次简单格式化可以解决问题,但是在一些极端情况下,比如文件管理器没有作用,而你又需要你的设备可以继续工作时,你可以使用下面的指导:

我们将会使用一个叫做 mkusb 的小工具来实现目标,这个工具的安装非常简单。

添加 mkusb 的仓库:

sudo apt add repository ppa:mkusb/ppa

现在更新你的包列表:

sudo apt-get update

安装 `mkusb:

sudo apt-get install mkusb

现在运行 mkusb 你将会看到这个提示,点击 ‘Yes’。

运行 mkusb dus

现在 mkusb 将会最后一次询问你是否希望继续格式化你的数据,‘Stop’是被默认选择的,你现在选择 ‘Go’ 并点击 ‘OK’。

Linux mkusb

窗口将会关闭,此时你的终端看起来是这样的。

mkusb usb 控制台

在几秒钟之后,整个过程将会完成,并且你将看到一个这样的弹出窗口。

恢复损坏的 USB 设备

你现在需要把你的设备从系统推出,然后再重新插进去。你的设备将被恢复成为一个普通设备而且还能像原来一样的工作。

Linux 磁盘管理器

我们现在所做的操作本可以通过终端命令或是 gparted 或者其他的软件来完成,但是那将会需要一些关于分区管理的知识。

所以有一个像这样可以自动解决专一问题的小工具总是一个好事。

结论

mkusb 是一个很容易使用的程序,它可以修复你的 USB 储存设备和 SD 卡。mkusb 通过 mkusb 的 PPA 来下载。所有在 mkusb 上的操作都需要超级管理员的权限,并且你在这个设备上的所有数据将会被格式化。

一旦操作完成,你将会重置这个设备并让它继续工作。

如果你感到任何疑惑,你可以在下面的评论栏里免费发表。


via: http://www.linuxandubuntu.com/home/restore-corrupted-usb-drive-to-original-state-in-linux

作者:LINUXANDUBUNTU 译者:Drshu 校对:wxy

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

十月初的时候我在贝洛奥里藏特的 巴西 Python 大会 Python Brasil 上做了主题演讲。这是稍加改动过的演讲文稿。你可以在这里观看演讲视频。

我爱 bug

我目前是 Pilot.com 的一位高级工程师,负责给创业公司提供自动记账服务。在此之前,我曾是 Dropbox 的桌面客户端组的成员,我今天将分享关于我当时工作的一些故事。更早之前,我是 Recurse Center 的导师,给身在纽约的程序员提供临时的训练环境。在成为工程师之前,我在大学攻读天体物理学并在金融界工作过几年。

但这些都不重要——关于我你唯一需要知道的是,我爱 bug。我爱 bug 因为它们有趣。它们富有戏剧性。调试一个好的 bug 的过程可以非常迂回曲折。一个好的 bug 像是一个有趣的笑话或者或者谜语——你期望看到某种结果,但却事与愿违。

在这个演讲中我会给你们讲一些我曾经热爱过的 bug,解释为什么我如此爱 bug,然后说服你们也同样去热爱 bug。

Bug 1 号

好,让我们直接来看第一个 bug。这是我在 Dropbox 工作时遇到的一个 bug。你们或许听说过,Dropbox 是一个将你的文件从一个电脑上同步到云端和其他电脑上的应用。

        +--------------+     +---------------+
        |              |     |               |
        |  元数据服务器  |     |     块服务器    |
        |              |     |               |
        +-+--+---------+     +---------+-----+
          ^  |                         ^
          |  |                         |
          |  |     +----------+        |
          |  +---> |          |        |
          |       |   客户端   +--------+
          +--------+          |
                   +----------+

这是个极度简化的 Dropbox 架构图。桌面客户端在你的电脑本地运行,监听文件系统的变动。当它检测到文件改动时,它读取改变的文件,并把它的内容 hash 成 4 MB 大小的文件块。这些文件块被存放在后端一个叫做 块服务器 blockserver 的巨大的 键值对数据库 key-value store 中。

当然,我们想避免多次上传同一个文件块。可以想见,如果你在编写一份文档,你应该大部分时候都在改动文档最底部——我们不想一遍又一遍地上传开头部分。所以在上传文件块到块服务器之前之前,客户端会先和一个负责管理元数据和权限等等的服务器沟通。客户端会询问这个 元数据服务器 metaserver 它是需要这个文件块,还是已经见过这个文件块了。元数据服务器会返回每一个文件块是否需要上传。

所以这些请求和响应看上去大概是这样:客户端说“我有一个改动过的文件,分为这些文件块,它们的 hash 是 'abcd,deef,efgh'。服务器响应说“我有前两块,但需要你上传第三块”。然后客户端会把那个文件块上传到块服务器。

                +--------------+     +---------------+
                |              |     |               |
                |  元数据服务器  |     |     块服务器    |
                |              |     |               |
                +-+--+---------+     +---------+-----+
                  ^  |                         ^
                  |  | '有, 有, 无'             |
'abcd,deef,efgh'  |  |     +----------+        | efgh: [内容]
                  |  +---> |          |        |
                  |        |   客户端   +--------+
                  +--------+          |
                           +----------+

这是问题的背景。下面是 bug。

                +--------------+
                |              |
                |    块服务器    |
                |              |
                +-+--+---------+
                  ^  |
                  |  |   '???'
'abcdldeef,efgh'  |  |     +----------+
     ^            |  +---> |          |
     ^            |        |   客户端  +
                  +--------+          |
                           +----------+

有时候客户端会提交一个奇怪的请求:每个 hash 值应该包含 16 个字母,但它却发送了 33 个字母——所需数量的两倍加一。服务器不知道该怎么处理它,于是会抛出一个异常。我们收到这个异常的报告,于是去查看客户端的记录文件,然后会看到非常奇怪的事情——客户端的本地数据库损坏了,或者 python 抛出 MemoryError,没有一个合乎情理的。

如果你以前没见过这个问题,可能会觉得毫无头绪。但当你见过一次之后,你以后每次看到都能轻松地认出它来。给你一个提示:在那些 33 个字母的字符串中,l 经常会代替逗号出现。其他经常出现的字符是:

l \x0c < $ ( . -

英文逗号的 ASCII 码是 44。l 的 ASCII 码是 108。它们的二进制表示如下:

bin(ord(',')): 0101100  
bin(ord('l')): 1101100  

你会注意到 l 和逗号只差了一位。问题就出在这里:发生了位反转。桌面客户端使用的内存中的一位发生了错误,于是客户端开始向服务器发送错误的请求。

这是其他经常代替逗号出现的字符的 ASCII 码:

,    : 0101100
l    : 1101100
\x0c : 0001100
<    : 0111100
$    : 0100100
(    : 0101000
.    : 0101110
-    : 0101101

位反转是真的!

我爱这个 bug 因为它证明了位反转是可能真实发生的事情,而不只是一个理论上的问题。实际上,它在某些情况下会比平时更容易发生。其中一种情况是用户使用的是低配或者老旧的硬件,而运行 Dropbox 的电脑很多都是这样。另外一种会造成很多位反转的地方是外太空——在太空中没有大气层来保护你的内存不受高能粒子和辐射的影响,所以位反转会十分常见。

你大概非常在乎在宇宙中运行的程序的正确性——你的代码或许事关国际空间站中宇航员的性命,但即使没有那么重要,也还要考虑到在宇宙中很难进行软件更新。如果你的确需要让你的程序能够处理位反转,有很多硬件和软件措施可供你选择,Katie Betchold 还关于这个问题做过一个非常有意思的讲座

在刚才那种情况下,Dropbox 并不需要处理位反转。出现内存损坏的是用户的电脑,所以即使我们可以检测到逗号字符的位反转,但如果这发生在其他字符上我们就不一定能检测到了,而且如果从硬盘中读取的文件本身发生了位反转,那我们根本无从得知。我们能改进的地方很少,于是我们决定无视这个异常并继续程序的运行。这种 bug 一般都会在客户端重启之后自动解决。

不常见的 bug 并非不可能发生

这是我最喜欢的 bug 之一,有几个原因。第一,它提醒我注意不常见和不可能之间的区别。当规模足够大的时候,不常见的现象会以值得注意的频率发生。

覆盖面广的 bug

这个 bug 第二个让我喜欢的地方是它覆盖面非常广。每当桌面客户端和服务器交流的时候,这个 bug 都可能悄然出现,而这可能会发生在系统里很多不同的端点和组件当中。这意味着许多不同的 Dropbox 工程师会看到这个 bug 的各种版本。你第一次看到它的时候,你 真的 会满头雾水,但在那之后诊断这个 bug 就变得很容易了,而调查过程也非常简短:你只需找到中间的字母,看它是不是个 l

文化差异

这个 bug 的一个有趣的副作用是它展示了服务器组和客户端组之间的文化差异。有时候这个 bug 会被服务器组的成员发现并展开调查。如果你的 服务器 上发生了位反转,那应该不是个偶然——这很可能是内存损坏,你需要找到受影响的主机并尽快把它从集群中移除,不然就会有损坏大量用户数据的风险。这是个事故,而你必须迅速做出反应。但如果是用户的电脑在破坏数据,你并没有什么可以做的。

分享你的 bug

如果你在调试一个难搞的 bug,特别是在大型系统中,不要忘记跟别人讨论。也许你的同事以前就遇到过类似的 bug。若是如此,你可能会节省很多时间。就算他们没有见过,也不要忘记在你解决了问题之后告诉他们解决方法——写下来或者在组会中分享。这样下次你们组遇到类似的问题时,你们都会早有准备。

Bug 如何帮助你进步

Recurse Center

在加入 Dropbox 之前,我曾在 Recurse Center 工作。它的理念是建立一个社区让正在自学的程序员们聚到一起来提高能力。这就是 Recurse Center 的全部了:我们没有大纲、作业、截止日期等等。唯一的前提条件是我们都想要成为更好的程序员。参与者中有的人有计算机学位但对自己的实际编程能力不够自信,有的人已经写了十年 Java 但想学 Clojure 或者 Haskell,还有各式各样有着其他的背景的参与者。

我在那里是一位导师,帮助人们更好地利用这个自由的环境,并参考我们从以前的参与者那里学到的东西来提供指导。所以我的同事们和我本人都非常热衷于寻找对成年自学者最有帮助的学习方法。

刻意练习

在学习方法这个领域有很多不同的研究,其中我觉得最有意思的研究之一是刻意练习的概念。刻意练习理论意在解释专业人士和业余爱好者的表现的差距。它的基本思想是如果你只看内在的特征——不论先天与否——它们都无法非常好地解释这种差距。于是研究者们,包括最初的 Ericsson、Krampe 和 Tesch-Romer,开始寻找能够解释这种差距的理论。他们最终的答案是在刻意练习上所花的时间。

他们给刻意练习的定义非常精确:不是为了收入而工作,也不是为了乐趣而玩耍。你必须尽自己能力的极限,去做一个和你的水平相称的任务(不能太简单导致你学不到东西,也不能太难导致你无法取得任何进展)。你还需要获得即时的反馈,知道自己是否做得正确。

这非常令人兴奋,因为这是一套能够用来建立专业技能的系统。但难点在于对于程序员来说这些建议非常难以实施。你很难知道你是否处在自己能力的极限。也很少有即时的反馈帮助你改进——有时候你能得到任何反馈都已经算是很幸运了,还有时候你需要等几个月才能得到反馈。对于在 REPL 中做的简单的事情你可以很快地得到反馈,但如果你在做一个设计上的决定或者技术上的选择,你在很长一段时间里都无法得到反馈。

但是在有一类编程工作中刻意练习是非常有用的,它就是 debug。如果你写了一份代码,那么当时你是理解这份代码是如何工作的。但你的代码有 bug,所以你的理解并不完全正确。根据定义来说,你正处在你理解能力的极限上——这很好!你马上要学到新东西了。如果你可以重现这个 bug,那么这是个宝贵的机会,你可以获得即时的反馈,知道自己的修改是否正确。

像这样的 bug 也许能让你学到关于你的程序的一些小知识,但你也可能会学到一些关于运行你的代码的系统的一些更复杂的知识。我接下来要讲一个关于这种 bug 的故事。

Bug 2 号

这也是我在 Dropbox 工作时遇到的 bug。当时我正在调查为什么有些桌面客户端没有像我们预期的那样持续发送日志。我开始调查客户端的日志系统并且发现了很多有意思的 bug。我会挑一些跟这个故事有关的 bug 来讲。

和之前一样,这是一个非常简化的系统架构。

                                   +--------------+
                                   |              |
               +---+  +----------> |   日志服务器   |
               |日志|  |            |              |
               +---+  |            +------+-------+
                      |                   |
                +-----+----+              |  200 ok
                |          |              |
                |  客户端   |  <-----------+
                |          |
                +-----+----+
                      ^
                      +--------+--------+--------+
                      |        ^        ^        |
                   +--+--+  +--+--+  +--+--+  +--+--+
                   | 日志 |  | 日志 |  | 日志 |  | 日志 |
                   |     |  |     |  |     |  |     |
                   |     |  |     |  |     |  |     |
                   +-----+  +-----+  +-----+  +-----+

桌面客户端会生成日志。这些日志会被压缩、加密并写入硬盘。然后客户端会间歇性地把它们发送给服务器。客户端从硬盘读取日志并发送给日志服务器。服务器会将它解码并存储,然后返回 200。

如果客户端无法连接到日志服务器,它不会让日志目录无限地增长。超过一定大小之后,它会开始删除日志来让目录大小不超过一个最大值。

最初的两个 bug 本身并不严重。第一个 bug 是桌面客户端向服务器发送日志时会从最早的日志而不是最新的日志开始。这并不是很好——比如服务器会在客户端报告异常的时候让客户端发送日志,所以你可能最在乎的是刚刚生成的日志而不是在硬盘上的最早的日志。

第二个 bug 和第一个相似:如果日志目录的大小达到了上限,客户端会从最新的日志而不是最早的日志开始删除。同理,你总是会丢失一些日志文件,但你大概更不在乎那些较早的日志。

第三个 bug 和加密有关。有时服务器会无法对一个日志文件解码(我们一般不知道为什么——也许发生了位反转)。我们在后端没有正确地处理这个错误,而服务器会返回 500。客户端看到 500 之后会做合理的反应:它会认为服务器停机了。所以它会停止发送日志文件并且不再尝试发送其他的日志。

对于一个损坏的日志文件返回 500 显然不是正确的行为。你可以考虑返回 400,因为问题出在客户端的请求上。但客户端同样无法修复这个问题——如果日志文件现在无法解码,我们后也永远无法将它解码。客户端正确的做法是直接删除日志文件然后继续运行。实际上,这正是客户端在成功上传日志文件并从服务器收到 200 的响应时的默认行为。所以我们说,好——如果日志文件无法解码,就返回 200。

所有这些 bug 都很容易修复。前两个 bug 出在客户端上,所以我们在 alpha 版本修复了它们,但大部分的客户端还没有获得这些改动。我们在服务器代码中修复了第三个 bug 并部署了新版的服务器。

激增

突然日志服务器集群的流量开始激增。客服团队找到我们并问我们是否知道原因。我花了点时间把所有的部分拼到一起。

在修复之前,这四件事情会发生:

  1. 日志文件从最早的开始发送
  2. 日志文件从最新的开始删除
  3. 如果服务器无法解码日志文件,它会返回 500
  4. 如果客户端收到 500,它会停止发送日志

一个存有损坏的日志文件的客户端会试着发送这个文件,服务器会返回 500,客户端会放弃发送日志。在下一次运行时,它会尝试再次发送同样的文件,再次失败,并再次放弃。最终日志目录会被填满,然后客户端会开始删除最新的日志文件,而把损坏的文件继续保留在硬盘上。

这三个 bug 导致的结果是:如果客户端在任何时候生成了损坏的日志文件,我们就再也不会收到那个客户端的日志了。

问题是,处于这种状态的客户端比我们想象的要多很多。任何有一个损坏文件的客户端都会像被关在堤坝里一样,无法再发送日志。现在这个堤坝被清除了,所有这些客户端都开始发送它们的日志目录的剩余内容。

我们的选择

好的,现在文件从世界各地的电脑如洪水般涌来。我们能做什么?(当你在一个有 Dropbox 这种规模,尤其是这种桌面客户端的规模的公司工作时,会遇到这种有趣的事情:你可以非常轻易地对自己造成 DDoS 攻击)。

当你部署的新版本发生问题时,第一个选项是回滚。这是非常合理的选择,但对于这个问题,它无法帮助我们。我们改变的不是服务器的状态而是客户端的——我们删除了那些出错文件。将服务器回滚可以防止更多客户端进入这种状态,但它并不能解决根本问题。

那扩大日志集群的规模呢?我们试过了——然后因为处理能力增加了,我们开始收到更多的请求。我们又扩大了一次,但你不可能一直这么下去。为什么不能?因为这个集群并不是独立的。它会向另一个集群发送请求,在这里是为了处理异常。如果你的一个集群正在被 DDoS,而你持续扩大那个集群,你最终会把它依赖的集群也弄坏,然后你就有两个问题了。

我们考虑过的另一个选择是减低负载——你不需要每一个日志文件,所以我们可以直接无视一些请求。一个难点是我们并没有一个很好的方法来区分好的请求和坏的请求。我们无法快速地判断哪些日志文件是旧的,哪些是新的。

我们最终使用的是一个 Dropbox 里许多不同场合都用过的一个解决方法:我们有一个自定义的头字段,chillout,全世界所有的客户端都遵守它。如果客户端收到一个有这个头字段的响应,它将在字段所标注的时间内不再发送任何请求。很早以前一个英明的程序员把它加到了 Dropbox 客户端里,在之后这些年中它已经不止一次地起了作用。

了解你的系统

这个 bug 的第一个教训是要了解你的系统。我对于客户端和服务器之间的交互有不错的理解,但我并没有考虑到当服务器和所有这些客户端同时交互的时候会发生什么。这是一个我没有完全搞懂的层面。

了解你的工具

第二个教训是要了解你的工具。如果出了差错,你有哪些选项?你能撤销你做的迁移吗?你如何知道事情出了差错,你又如何发现更多信息?所有这些事情都应该在危机发生之前就了解好——但如果你没有,你会在危机发生时学到它们并不会再忘记。

功能开关 & 服务器端功能控制

第三个教训是专门针对移动端和桌面应用开发者的:你需要服务器端功能控制和功能开关。当你发现一个问题时如果你没有服务器端的功能控制,你可能需要几天或几星期来推送新版本或者提交新版本到应用商店中,然后问题才能得到解决。这是个很糟糕的处境。Dropbox 桌面客户端不需要经过应用商店的审查过程,但光是把一个版本推送给上千万的用户就已经要花很多时间。相比之下,如果你能在新功能遇到问题的时候在服务器上翻转一个开关:十分钟之后你的问题就已经解决了。

这个策略也有它的代价。加入很多的功能开关会大幅提高你的代码的复杂度。而你的测试代码更是会成指数地复杂化:要考虑 A 功能和 B 功能都开启,或者仅开启一个,或者都不开启的情况——然后每个功能都要相乘一遍。让工程师们在事后清理他们的功能开关是一件很难的事情(我自己也有这个毛病)。另外,桌面客户端会同时有好几个版本有人使用,也会加大思考难度。

但是它的好处——啊,当你需要它的时候,你真的是很需要它。

如何去爱 bug

我讲了几个我爱的 bug,也讲了为什么要爱 bug。现在我想告诉你如何去爱 bug。如果你现在还不爱 bug,我知道唯一一种改变的方法,那就是要有成长型心态。

社会学家 Carol Dweck 做了很多关于人们如何看待智力的研究。她找到两种不同的看待智力的心态。第一种,她叫做固定型心态,认为智力是一个固定的特征,人类无法改变自己智力的多寡。另一种心态叫做成长型心态。在成长型心态下,人们相信智力是可变的而且可以通过努力来增强。

Dweck 发现一个人看待智力的方式——固定型还是成长型心态——可以很大程度地影响他们选择任务的方式、面对挑战的反应、认知能力、甚至是他们的诚信度。

【我在新西兰 Kiwi Pycon 会议所做的主题演讲中也讨论过成长型心态,所以在此只摘录一部分内容。你可以在这里找到完整版的演讲稿】

关于诚信的发现:

在这之后,他们让学生们给笔友写信讲这个实验,信中说“我们在学校做了这个实验,这是我得的分数”。他们发现 因智力而受到表扬的学生中几乎一半人谎报了自己的分数 ,而因努力而受表扬的学生则几乎没有人不诚实。

关于努力:

数个研究发现有着固定型心态的人会不愿真正去努力,因为他们认为这意味着他们不擅长做他们正努力去做的这件事情。Dweck 写道,“如果每当一个任务需要努力的时候你就会怀疑自己的智力,那么你会很难对自己的能力保持自信。”

关于面对困惑:

他们发现有成长型心态的学生大约能理解 70% 的内容,不论里面是否有难懂的段落。在有固定型心态的学生中,那些被分配没有难懂段落的手册的学生同样可以理解大约 70%。但那些看到了难懂段落的持固定型心态的学生的记忆则降到了 30%。有着固定型心态的学生非常不擅长从困惑中恢复。

这些发现表明成长型心态对 debug 至关重要。我们必须从从困惑中重整旗鼓,诚实地面对我们理解上的不足,并时不时地在寻找答案的路上努力奋斗——成长型心态会让这些都变得更简单而且不那么痛苦。

热爱你的 bug

我在 Recurse Center 工作时会直白地欢迎挑战,我就是这样学会热爱我的 bug 的。有时参与者会坐到我身边说“唉,我觉得我遇到了个奇怪的 Python bug”,然后我会说“太棒了,我 奇怪的 Python bug!” 首先,这百分之百是真的,但更重要的是,我这样是在对参与者强调,找到让自己觉得困难的事情是一种成就,而他们做到了这一点,这是件好事。

像我之前说过的,在 Recurse Center 没有截止日期也没有作业,所以这种态度没有任何成本。我会说,“你现在可以花一整天去在 Flask 里找出这个奇怪的 bug 了,多令人兴奋啊!”在 Dropbox 和之后的 Pilot,我们有产品需要发布,有截止日期,还有用户,于是我并不总是对在奇怪的 bug 上花一整天而感到兴奋。所以我对有截止日期的现实也是感同身受。但是如果我有 bug 需要解决,我就必须得去解决它,而抱怨它的存在并不会帮助我之后更快地解决它。我觉得就算在截止日期临近的时候,你也依然可以保持这样的心态。

如果你热爱你的 bug,你可以在解决困难问题时获得更多乐趣。你可以担心得更少而更加专注,并且从中学到更多。最后,你可以和你的朋友和同事分享你的 bug,这将会同时帮助你自己和你的队友们。

鸣谢!

在此向给我的演讲提出反馈以及给我的演讲提供其他帮助的人士表示感谢:

  • Sasha Laundy
  • Amy Hanlon
  • Julia Evans
  • Julian Cooper
  • Raphael Passini Diniz 以及其他的 Python Brasil 组织团队成员

via: http://akaptur.com/blog/2017/11/12/love-your-bugs/

作者:Allison Kaptur 译者:yixunx 校对:wxy

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

unhide 是一个小巧的网络取证工具,能够发现那些借助 rootkit、LKM 及其它技术隐藏的进程和 TCP/UDP 端口。这个工具在 Linux、UNIX 类、MS-Windows 等操作系统下都可以工作。根据其 man 页面的说明:

Unhide 通过下述三项技术来发现隐藏的进程。

  1. 进程相关的技术,包括将 /proc 目录与 /bin/ps 命令的输出进行比较。
  2. 系统相关的技术,包括将 /bin/ps 命令的输出结果同从系统调用方面得到的信息进行比较。
  3. 穷举法相关的技术,包括对所有的进程 ID 进行暴力求解,该技术仅限于在基于 Linux2.6 内核的系统中使用。

绝大多数的 Rootkit 工具或者恶意软件借助内核来实现进程隐藏,这些进程只在内核内部可见。你可以使用 unhide 或者诸如 rkhunter 等工具,扫描 rootkit 程序 、后门程序以及一些可能存在的本地漏洞

这篇文章描述了如何安装 unhide 并搜索隐藏的进程和 TCP/UDP 端口。

如何安装 unhide

首先建议你在只读介质上运行这个工具。如果使用的是 Ubuntu 或者 Debian 发行版,输入下述的 apt-get/apt 命令以安装 Unhide:

$ sudo apt-get install unhide

一切顺利的话你的命令行会输出以下内容:

[sudo] password for vivek: 
Reading package lists... Done
Building dependency tree       
Reading state information... Done
Suggested packages:
  rkhunter
The following NEW packages will be installed:
  unhide
0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded.
Need to get 46.6 kB of archives.
After this operation, 136 kB of additional disk space will be used.
Get:1 http://in.archive.ubuntu.com/ubuntu artful/universe amd64 unhide amd64 20130526-1 [46.6 kB]
Fetched 46.6 kB in 0s (49.0 kB/s)
Selecting previously unselected package unhide.
(Reading database ... 205367 files and directories currently installed.)
Preparing to unpack .../unhide_20130526-1_amd64.deb ...
Unpacking unhide (20130526-1) ...
Setting up unhide (20130526-1) ...
Processing triggers for man-db (2.7.6.1-2) ...

如何在 RHEL/CentOS/Oracle/Scientific/Fedora 上安装 unhide

输入下列 yum Type the following yum command (first turn on EPLE repo on a CentOS/RHEL version 6.x or version 7.x):

输入以下的 yum 命令(CentOS/RHEL 6.x7.x 上首先打开 EPEL 仓库):

$ sudo yum install unhide

在 Fedora 上则使用以下 dnf 命令:

$ sudo dnf install unhide

如何在 Arch 上安装 unhide

键入以下 pacman 命令安装:

$ sudo pacman -S unhide

如何在 FreeBSD 上安装 unhide

可以通过以下的命令使用 port 来安装 unhide:

# cd /usr/ports/security/unhide/
# make install clean

或者可以通过二进制文件安装 hide,使用 pkg 命令安装:

# pkg install unhide

如何使用 unhide 工具?

unhide 的语法是:

unhide [options] test_list

test_list 参数可以是以下测试列表中的一个或者多个标准测试:

  1. brute
  2. proc
  3. procall
  4. procfs
  5. quick
  6. reverse
  7. sys

或基本测试:

  1. checkbrute
  2. checkchdir
  3. checkgetaffinity
  4. checkgetparam
  5. checkgetpgid
  6. checkgetprio
  7. checkRRgetinterval
  8. checkgetsched
  9. checkgetsid
  10. checkkill
  11. checknoprocps
  12. checkopendir
  13. checkproc
  14. checkquick
  15. checkreaddir
  16. checkreverse
  17. checksysinfo
  18. checksysinfo2
  19. checksysinfo3

你可以通过以下示例命令使用 unhide

# unhide proc
# unhide sys
# unhide quick

示例输出:

Unhide 20130526
Copyright © 2013 Yago Jesus & Patrick Gouin
License GPLv3+ : GNU GPL version 3 or later
http://www.unhide-forensics.info

NOTE : This version of unhide is for systems using Linux >= 2.6 

Used options: 
[*]Searching for Hidden processes through  comparison of results of system calls, proc, dir and ps

如何使用 unhide-tcp 工具辨明 TCP/UDP 端口的身份

以下是来自 man 页面的介绍:

unhide-tcp 取证工具通过对所有可用的 TCP/IP 端口进行暴力求解的方式,辨别所有正在监听,却没有列入 /bin/netstat 或者 /bin/ss 命令输出的 TCP/IP 端口身份。

注一:对于 FreeBSD、OpenBSD系统,一般使用 netstat 命令取代在这些操作系统上不存在的 iproute2,此外,sockstat 命令也用于替代 fuser。

注二:如果操作系统不支持 iproute2 命令,在使用 unhide 时需要在命令上加上 -n 或者 -s 选项。

# unhide-tcp

示例输出:

Unhide 20100201
http://www.security-projects.com/?Unhide

Starting TCP checking

Starting UDP checking

上述操作中,没有发现隐藏的端口。

但在下述示例中,我展示了一些有趣的事。

# unhide-tcp

示例输出:

Unhide 20100201
http://www.security-projects.com/?Unhide


Starting TCP checking

Found Hidden port that not appears in netstat: 1048
Found Hidden port that not appears in netstat: 1049
Found Hidden port that not appears in netstat: 1050
Starting UDP checking

可以看到 netstat -tulpnss 命令确实没有反映出这三个隐藏的端口:

# netstat -tulpn | grep 1048
# ss -lp
# ss -l | grep 1048

通过下述的 man 命令可以更多地了解 unhide

$ man unhide
$ man unhide-tcp

Windows 用户如何安装使用 unhide

你可以通过这个页面获取 Windows 版本的 unhide。


via: https://www.cyberciti.biz/tips/linux-unix-windows-find-hidden-processes-tcp-udp-ports.html

作者:Vivek Gite 译者:ljgibbslf 校对:wxy

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

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