Xiaodong Xu
2014-06-15T20:39:13-07:00
http://toy.linuxtoy.org/
Xiaodong Xu
将 Python 文档打包成 ePub 格式
2014-06-16T11:23:00-07:00
http://toy.linuxtoy.org//2014/06/16/python-epub-doc
<p>虽然 Python 官方文档针对最新版本提供有 ePub 格式,但是这个
包包含所有的内容,在我的手机上打开十分慢。另外,Python 2.x
系列并不提供 ePub 格式。于是,我编写了 <a href="https://github.com/xuxiaodong/pydoc-epub">pydocepub</a> 这个
脚本用来将 Python 文档自动打包成 ePub 格式。</p>
<p>要使用 pydocepub,首先需要安装 Mercurial 和 <a href="http://sphinx-doc.org/">Sphinx</a>,
在 Debian 下可执行:</p>
<div class="highlight"><pre><code class="text language-text" data-lang="text">apt-get install mercurial sphinx-doc
</code></pre></div>
<p>接着,从 GitHub 克隆该脚本:</p>
<div class="highlight"><pre><code class="text language-text" data-lang="text">git clone https://github.com/xuxiaodong/pydoc-epub.git
</code></pre></div>
<p>比如,要打包 Python 2.7.7 的教程:</p>
<div class="highlight"><pre><code class="text language-text" data-lang="text">./pydocepub 2.7.7 tutorial
</code></pre></div>
<p>打包完成后的 ePub 文件可在以下目录中找到:</p>
<div class="highlight"><pre><code class="text language-text" data-lang="text">2.7.7/tutorial/build/epub
</code></pre></div>
Debian Jessie 切换 systemd
2014-06-13T12:56:00-07:00
http://toy.linuxtoy.org//2014/06/13/switching-to-systemd-on-debian-jessie
<p>目前,许多 Linux 发行版都相继切换到了 systemd。在 Debian Jessie
中,要从 SysVinit 切换到 systemd,可执行如下命令:</p>
<div class="highlight"><pre><code class="text language-text" data-lang="text">apt-get update
apt-get install systemd systemd-sysv
reboot
</code></pre></div>
<p>在切换前,注意查看系统<a href="https://wiki.debian.org/systemd">是否满足需求</a>。</p>
使用 Pure-FTPd 架设 FTP 服务
2014-05-09T11:34:00-07:00
http://toy.linuxtoy.org//2014/05/09/pure-ftpd
<p>最近需要与同事交换一些数据文件,于是考虑架设一个 FTP
服务。这里,我使用 Pure-FTPd 来加以实现。</p>
<p><strong>安装</strong></p>
<p>在 Debian 中,执行:</p>
<div class="highlight"><pre><code class="text language-text" data-lang="text">apt-get install pure-ftpd
</code></pre></div>
<p><strong>允许匿名用户访问</strong></p>
<p>编辑 <code>/etc/pure-ftpd/conf/NoAnonymous</code> 将其中的 yes
改为 no。</p>
<p>添加一个名为 ftp 的用户:</p>
<div class="highlight"><pre><code class="text language-text" data-lang="text">adduser ftp
</code></pre></div>
<p>再重启服务:</p>
<div class="highlight"><pre><code class="text language-text" data-lang="text">service pure-ftpd restart
</code></pre></div>
sed 中通过 /n 指定匹配出现次数
2014-04-17T14:36:00-07:00
http://toy.linuxtoy.org//2014/04/17/sed-specifying-which-occurrence
<p>在 sed 中,通过 <code>/n</code> (n 代表数字) 可以指定匹配出现的次数。</p>
<p>例 1:</p>
<div class="highlight"><pre><code class="text language-text" data-lang="text">sed 's/[a-zA-Z]* //2' <old >new
</code></pre></div>
<p>这里的 <code>/2</code> 将匹配到的第二个单词删除。</p>
<p>例 2:</p>
<div class="highlight"><pre><code class="text language-text" data-lang="text">sed 's/./&:/80' <file >new
</code></pre></div>
<p>这里的 <code>/80</code> 在第 80 个字符后面添加一个 <code>:</code>。</p>
<p>例 3:</p>
<div class="highlight"><pre><code class="text language-text" data-lang="text">sed 's/[a-zA-Z]* /DELETED /2g' <old >new
</code></pre></div>
<p>与 <code>/g</code> 连用,将匹配到的第二个、第三个……替换成 DELETED。</p>
<p><code>/n</code> 中的 n 可以取 1 ~ 512 中的数。</p>
<p>注意,<code>/n</code> 与 <code>\n</code> 的区别,后者指引用捕获匹配的内容,n 取 1 ~ 9。</p>
利用 Synergy 共享鼠标和键盘
2014-03-19T14:46:00-07:00
http://toy.linuxtoy.org//2014/03/19/share-mouse-and-keyboard-with-synergy
<p>在办公室工作的时候,如果想要将台式机的鼠标和键盘共享
给笔记本使用,通过 Synergy 是很方便的。</p>
<p>要达到上述目的,首先在台式机和笔记本上都安装 Synergy,
注意保证两边的版本一致,以免出现兼容问题。</p>
<p><strong>台式机:服务端</strong></p>
<p>因为我们是打算共享台式机的鼠标和键盘,所以这里将台式
机作为 Synergy 的服务端。同时,在 <code>/etc/synergy.conf</code>
中添加下列内容:</p>
<div class="highlight"><pre><code class="text language-text" data-lang="text">section: screens
codefun:
codetoy:
end
section: links
codefun:
left = codetoy
codetoy:
right = codefun
end
</code></pre></div>
<p>其中,<code>codetoy</code> 和 <code>codefun</code> 分别为台式机和笔记本的主机
名。<code>screens</code> 节定义要使用共享鼠标和键盘的两台机器,也
可以同时定义多台。<code>links</code> 节则定义两台机器的屏幕所处的
位置,这里我们将台式机设置在左边,相应地笔记本则在台式机
的右边。除了左右关系,也能定义上下关系。</p>
<p>配置好后,通过以下命令启动 Synergy 的服务端:</p>
<div class="highlight"><pre><code class="text language-text" data-lang="text">synergys -f -n codetoy
</code></pre></div>
<p><strong>笔记本:客户端</strong></p>
<p>客户端无需配置,直接使用如下命令连接服务端即可:</p>
<div class="highlight"><pre><code class="text language-text" data-lang="text">synergyc -f -n codetoy 192.168.1.58
</code></pre></div>
<p>其中,<code>192.168.1.58</code> 为 Synergy 服务端所在机器的 IP。 </p>
<p>现在,当将鼠标指针从台式机的屏幕右边移出时,你会发现它
已经进到笔记本的屏幕了。如果要返回台式机屏幕,则从笔记
本屏幕的左边移出即可。</p>
Asus EeePC X101CH 双显屏设置
2014-03-19T11:06:00-07:00
http://toy.linuxtoy.org//2014/03/19/eeepc-dual-monitor-setup
<p>最近用 <code>xrandr</code> 为这台 Asus EeePC X101CH 设置双显示屏时,遇到
了下列错误:</p>
<div class="highlight"><pre><code class="text language-text" data-lang="text">xrandr: Failed to get size of gamma for output default
Screen 0: minimum 1024 x 600, current 1024 x 600, maximum 1024 x 600
default connected 1024x600+0+0 0mm x 0mm
1024x600 0.0*
</code></pre></div>
<p>从 xrandr 的输出信息并不能看到 VGA、DVI 等其他输出接口。实事
上,这些接口是存在的。经过查证,在安装 xf86-video-modesetting 包,
并创建 <code>/usr/share/X11/xorg.conf.d/00-modesetting.conf</code> 文件后,
<code>xrandr</code> 执行正常。</p>
<p>00-modesetting.conf 的内容如下:</p>
<div class="highlight"><pre><code class="text language-text" data-lang="text">Section "Device"
Identifier "gma500_gfx"
Driver "modesetting"
Option "SWCursor" "ON"
EndSection
</code></pre></div>
<p>连上外接显示器,再执行:</p>
<div class="highlight"><pre><code class="text language-text" data-lang="text">% xrandr --output VGA-0 --auto
</code></pre></div>
<p>屏幕输出正常显示。</p>
find 命令排除目录
2014-03-13T15:57:00-07:00
http://toy.linuxtoy.org//2014/03/13/exclude-directory-in-find
<p>在编写 <a href="https://github.com/xuxiaodong/bin/blob/master/mkme">mkme</a> 这个脚本的时候,我需要使用 <code>find</code> 命令来
找出当前目录下的可执行文件,但是要排除 <code>.git</code> 目录。查阅
find 的 Manpage 后,发现可以这样子来搞定:</p>
<div class="highlight"><pre><code class="text language-text" data-lang="text">find . -type f -executable ! -path "./.git/*"
</code></pre></div>
<p>其选项说明如下:</p>
<ul>
<li><code>.</code>:在当前目录下查找</li>
<li><code>-type f</code>:仅查找一般文件</li>
<li><code>-executable</code>:文件具有可执行权限</li>
<li><code>! -path "./.git/*"</code>:这里是关键,<code>!</code> 的作用是排除其后
<code>-path</code> 所跟的目录</li>
</ul>
快速查询语言 API
2014-03-11T16:28:00-07:00
http://toy.linuxtoy.org//2014/03/11/search-devdocs
<p>由 Thibaut Courouble 所创建的 <a href="http://devdocs.io/">DevDocs</a> 的确是相当不错的工具,
它将 CSS、HTML、JavaScript、PHP、Python、Ruby 等各种 API 文档整
合在一起,并提供统一的搜索接口,极大的方便了编写代码的程序员朋友。</p>
<p>为了便于从命令行下查询,我编写了 <code>search-api</code> 这个脚本。该脚本
支持如下两种方式来进行查询:</p>
<ol>
<li><p><code>search-api <keyword></code>:这将查询以 keyword 作为关键字的内容。</p></li>
<li><p><code>search-api <language> <keyword></code>:针对特定语言进行查询。</p></li>
</ol>
<p>例如,在 Vim 中我执行 <code>:!search-api js replace</code> 将查询 JavaScript
中 replace 的用法。脚本会调用 Firefox 打开一个窗口来展示查询的结果。</p>
hr in Perl
2014-03-07T16:57:00-08:00
http://toy.linuxtoy.org//2014/03/07/hr-in-perl
<p>熟悉 HTML 的朋友想必都知道 <code><hr /></code> 这个标签的用途是绘制
一条水平线。hr 则是适用于终端的 <code><hr /></code>。它将根据用户
输入的字符在终端中绘制水平线,默认是 <code>#</code> 符号,其长度跟
终端窗口的大小一样。例如:</p>
<div class="highlight"><pre><code class="text language-text" data-lang="text">$ hr #
##################################
$ hr '*'
**********************************
$ hr - '#' -
----------------------------------
##################################
----------------------------------
$ hr '-#-' '-' '-#-'
-#--#--#--#--#--#--#--#--#--#--#--
----------------------------------
-#--#--#--#--#--#--#--#--#--#--#--
</code></pre></div>
<p>hr 的原作者 <a href="https://github.com/LuRsT/hr">LuRsT</a> 是使用 Bash 编写的,只是为了好玩,我用
Perl 重新实现了一个版本。hr 的其他语言实现还包括 JavaScript、
Python、Ruby、Haskell 等等。</p>
增大 LVM root 分区空间
2014-03-05T14:20:00-08:00
http://toy.linuxtoy.org//2014/03/05/resize-lvm-root-partition-slash
<p>最近发现我的 Debian root 分区已经占满了,于是打算给它
增加一些新的空间。</p>
<p>因为我使用了 LVM,所以即便是 root 分区,也可以直接为
其扩容,不用 umount,也不用 reboot,真的是十分方便。</p>
<p>首先,利用 <code>lvdisplay</code> 可以看到目前逻辑卷的一些信息:</p>
<div class="highlight"><pre><code class="text language-text" data-lang="text">--- Logical volume ---
LV Path /dev/toy/root
LV Name root
VG Name toy
LV UUID wCBCHD-Ddrg-2tev-3xHV-ZXHI-tYB3-R2fhuu
LV Write Access read/write
LV Creation host, time toy, 2013-06-13 11:25:53 +0800
LV Status available
# open 1
LV Size 9.31 GiB
Current LE 2384
Segments 1
Allocation inherit
Read ahead sectors auto
- currently set to 256
Block device 254:0
</code></pre></div>
<p>接着,使用 <code>lvextend -L+7G /dev/toy/root -v</code> 来给 root 分区增加
7G。</p>
<div class="highlight"><pre><code class="text language-text" data-lang="text">Finding volume group toy
Archiving volume group "toy" metadata (seqno 5).
Extending logical volume root to 16.31 GiB
Found volume group "toy"
Found volume group "toy"
Loading toy-root table (254:0)
Suspending toy-root (254:0) with device flush
Found volume group "toy"
Resuming toy-root (254:0)
Creating volume group backup "/etc/lvm/backup/toy" (seqno 6).
Logical volume root successfully resized
</code></pre></div>
<p>最后,通过 <code>resize2fs /dev/toy/root</code> 将文件系统也进行扩容。
我的 root 分区的文件系统为 ext4,需要注意的是,目前的 Linux
内核可能对某些文件系统不支持这种 on-line 的调整方式。所以在动手
前先做好功课就显得很重要了。</p>
<div class="highlight"><pre><code class="text language-text" data-lang="text">resize2fs 1.42.9 (28-Dec-2013)
Filesystem at /dev/toy/root is mounted on /; on-line resizing required
old_desc_blocks = 1, new_desc_blocks = 2
The filesystem on /dev/toy/root is now 4276224 blocks long.
</code></pre></div>
<p>再用 <code>df -Th</code> 看一下,发现 root 分区的空间已经增大了。</p>
<div class="highlight"><pre><code class="text language-text" data-lang="text">Filesystem Type Size Used Avail Use% Mounted on
/dev/mapper/toy-root ext4 16G 7.7G 7.6G 51% /
udev devtmpfs 10M 0 10M 0% /dev
tmpfs tmpfs 402M 308K 402M 1% /run
tmpfs tmpfs 5.0M 0 5.0M 0% /run/lock
tmpfs tmpfs 804M 68K 804M 1% /run/shm
/dev/sda1 ext2 228M 44M 172M 21% /boot
/dev/mapper/toy-home ext4 442G 172G 248G 42% /home
</code></pre></div>
通过 Ratchet 为 Linuxtoy 构建移动界面
2014-02-27T21:07:00-08:00
http://toy.linuxtoy.org//2014/02/27/build-mobile-ui-with-ratchet
<p>今天在 HTML5 Weekly 中看到了对 Ratchet 的介绍,它是一个移动
应用构建框架,主要支持使用 HTML、CSS、JavaScript 等技术。鉴
于 Linuxtoy.org 一直缺少一个面向移动终端的界面,于是马上决定
试试 Ratchet。</p>
<p>初步的实现想法是:</p>
<ol>
<li>使用 jQuery 和 FeedEk 解析 Feed,以便获得内容</li>
<li>接着,使用 Ratchet 来渲染所得到的内容</li>
</ol>
<p>效果如下,可通过 <a href="http://m.linuxtoy.org">http://m.linuxtoy.org</a> 访问:</p>
<p><img src="/images/mtoy-index.png" alt="mtoy"></p>
<p>首页显示最新的 10 篇文章。</p>
<p><img src="/images/mtoy-single.png" alt="mtoy"></p>
<p>文章的具体内容。</p>
<p>通过试用,感觉 Ratchet 还是挺好上手的。有时间不妨再深入
研究下。</p>
<p>实现的源代码可从 <a href="http://git.linuxtoy.org/mtoy/">http://git.linuxtoy.org/mtoy/</a> 得到。</p>
使用 Perl 实现 tldr
2014-02-21T12:48:00-08:00
http://toy.linuxtoy.org//2014/02/21/my-tldr
<p>Romain Prieto 的 <a href="https://github.com/rprieto/tldr">tldr</a> 想法是好,但其依赖的一堆 Node
可能会让某些朋友不高兴。当是练手,我用 Perl 实现了自己的
<a href="https://github.com/xuxiaodong/bin/blob/master/tldr">tldr</a>。</p>
<p>使用方法如下:</p>
<div class="highlight"><pre><code class="text language-text" data-lang="text">% mkdir ~/tldr
% cd !$
% git clone https://github.com/rprieto/tldr.git
% wget https://github.com/xuxiaodong/bin/raw/master/tldr -O tldr.pl
% chmod +x tldr.pl
% ./tldr.pl tar
</code></pre></div>
<p>输出为:</p>
<div class="highlight"><pre><code class="text language-text" data-lang="text">> Archiving utility
> Optional compression with gzip / bzip
- create an archive from files
`tar cf \{\{target.tar}} \{\{file1 file2 file3}}`
- create a gzipped archive
`tar cfz \{\{target.tar.gz}} \{\{file1 file2 file3}}`
- extract an archive in a target folder
`tar xf \{\{source.tar}} -C \{\{folder}}`
- extract a gzipped archive in the current directory
`tar xzf \{\{source.tar.gz}}`
</code></pre></div>
修复 XFS 文件系统错误
2014-02-16T00:10:00-08:00
http://toy.linuxtoy.org//2014/02/16/repair-xfs
<p>在强制关机后,我的 Funtoo 重启时遇到了下面的错误:</p>
<div class="highlight"><pre><code class="text language-text" data-lang="text">mount: mount /dev/mapper/vg-home on /home failed: Structure
needs cleaning
</code></pre></div>
<p>从出错提示可以看出,将 <code>/dev/mapper/vg-home</code> 挂载到 <code>/home</code> 时
失败了。</p>
<p>通过 <code>TTY2</code> 登录系统后,执行 <code>xfs_repair</code> 命令对 XFS 文件系统
先进行检查。</p>
<div class="highlight"><pre><code class="text language-text" data-lang="text">xfs_repair -n -v /dev/mapper/vg-home
</code></pre></div>
<p>一番扫描下来果然发现了错误。接着,修复这些错误:</p>
<div class="highlight"><pre><code class="text language-text" data-lang="text">xfs_repair -L -v /dev/mapper/vg-home
</code></pre></div>
<p>完成后,再次 mount 正常。</p>
Debian 下阻止包升级
2014-01-23T09:56:00-08:00
http://toy.linuxtoy.org//2014/01/23/debian-hold-package
<p>在执行系统更新时,有时候我想阻止某些个别的包升级,
Debian 下可以使用 <code>apt-mark</code> 命令。</p>
<p><strong>阻止包</strong></p>
<div class="highlight"><pre><code class="text language-text" data-lang="text">apt-mark hold <pkg>
</code></pre></div>
<p>比如,阻止升级 Perl,执行 <code>apt-mark hold perl</code> 即可。</p>
<p><strong>取消阻止</strong></p>
<p>如果不想阻止了,那么可以通过 <code>apt-mark unhold</code> 取消:</p>
<div class="highlight"><pre><code class="text language-text" data-lang="text">apt-mark unhold <pkg>
</code></pre></div>
<p><strong>显示已阻止的包</strong></p>
<p>要查看已经被阻止的包,则可以执行:</p>
<div class="highlight"><pre><code class="text language-text" data-lang="text">apt-mark showhold
</code></pre></div>
在 Godaddy 中添加泛域名解析
2013-12-31T10:53:00-08:00
http://toy.linuxtoy.org//2013/12/31/add-wildcard-subdomain-in-godaddy
<p>最近因为玩各种有趣的东东,所以为 <linuxtoy.org> 添加了不少
子域。为了避免频繁的添加过程,于是想到用泛域名解析来解决。</p>
<p>在 Godaddy 中添加泛域名解析十分简单,只要追加一条 <code>A</code> 记录
,并分别将 Host 设为 <code>*</code>、Points To 设为目标 IP 地址即可。</p>
<p>Godaddy 的 DNS 设置生效时间非常快,几乎是设置完成后便可以
使用。</p>
自底向上理解 Git
2013-12-30T16:03:00-08:00
http://toy.linuxtoy.org//2013/12/30/git-from-bottom-up
<p>Git from bottom up 这篇文章写得相当不错,对于理解 Git 的原理
非常具有帮助。文章从 Git 的基本构成要素 blob 讲起,之后逐渐
说明了 blob、tree、commit、branch、tag 的内在联系,以及阐述了
rebase、reset、stash、reflog 的用途。读罢给人一种豁然开朗的
感觉。</p>
修复 pycrypto AttributeError
2013-12-20T10:05:00-08:00
http://toy.linuxtoy.org//2013/12/20/fix-attributeerror
<p>在将 Ansible 升级到 1.4.2 时,其依赖模块 pycrpyto 也进行了
更新,执行 <code>ansible</code> 报如下错误:</p>
<div class="highlight"><pre><code class="text language-text" data-lang="text">Traceback (most recent call last):
File "/usr/bin/ansible", line 24, in <module>
from ansible.runner import Runner
File "/usr/lib/python2.6/site-packages/ansible/runner/__init__.py", line 53, in <module>
from Crypto.Random import atfork
File "/usr/lib64/python2.6/site-packages/Crypto/Random/__init__.py", line 29, in <module>
from Crypto.Random import _UserFriendlyRNG
File "/usr/lib64/python2.6/site-packages/Crypto/Random/_UserFriendlyRNG.py", line 38, in <module>
from Crypto.Random.Fortuna import FortunaAccumulator
File "/usr/lib64/python2.6/site-packages/Crypto/Random/Fortuna/FortunaAccumulator.py", line 39, in <module>
import FortunaGenerator
File "/usr/lib64/python2.6/site-packages/Crypto/Random/Fortuna/FortunaGenerator.py", line 34, in <module>
from Crypto.Util.number import ceil_shift, exact_log2, exact_div
File "/usr/lib64/python2.6/site-packages/Crypto/Util/number.py", line 56, in <module>
if _fastmath is not None and not _fastmath.HAVE_DECL_MPZ_POWM_SEC:
AttributeError: 'module' object has no attribute 'HAVE_DECL_MPZ_POWM_SEC'
</code></pre></div>
<p>打开 <code>/usr/lib64/python2.6/site-packages/Crypto/Util/number.py</code> 文件,可以
看到 56 行上的注释说明,要求 libgmp 为 v5 以上版本。而系统现有版本为
4.1.4,把 56 和 57 行暂时注释掉,Ansible 执行正常。</p>
<p>不过,此方法只是临时加以解决,更好的方式是去将 libgmp
升级到符合要求的版本。</p>
bootstrap-sortable: 给 Bootstrap Table 添加排序功能
2013-12-18T17:17:00-08:00
http://toy.linuxtoy.org//2013/12/18/bootstrap-sortable
<p>bootstrap-sortable 这个 JS 库能够给 Bootstrap 的 Table 增添排序
功能,用起来相当简单。</p>
<p>首先,在 HTML 页面中引用以下三个文件:</p>
<div class="highlight"><pre><code class="text language-text" data-lang="text"><link href="css/bootstrap-sortable.css" rel="stylesheet" media="screen">
<script src="js/moment.min.js"></script>
<script src="js/bootstrap-sortable.js"></script>
</code></pre></div>
<p>接着,在 Table 标签中追加 <code>sortable</code> 类即可:</p>
<div class="highlight"><pre><code class="text language-text" data-lang="text"><table class="table table-striped table-hover sortable">
...
</table>
</code></pre></div>
玩玩 Ansible API
2013-12-13T14:00:00-08:00
http://toy.linuxtoy.org//2013/12/13/playing-with-ansible-api
<p>如果了解一点 Python,我们还可以从 API 的角度来使用 Ansible。
这是我喜欢使用 Ansible 的另一个原因。</p>
<p>虽然 Ansible 提供的 <code>--list-hosts</code> 选项可以看到 inventory 中
的主机,但却无法看到具体的组别。因此,我写了一段小程序来列出
这些组名:</p>
<div class="highlight"><pre><code class="text language-text" data-lang="text">from ansible.inventory import Inventory
def get_groups():
i = Inventory()
groups = i.list_groups()
return '\n'.join(groups)
if __name__ == '__main__':
print(get_groups())
</code></pre></div>
<p>如果保存为 ansible-groups,执行</p>
<div class="highlight"><pre><code class="text language-text" data-lang="text">./ansible-groups
</code></pre></div>
<p>就会输出类似下面的结果:</p>
<div class="highlight"><pre><code class="text language-text" data-lang="text">all
test
ungrouped
</code></pre></div>
pip 安装特定版本的 Python 包
2013-12-11T13:38:00-08:00
http://toy.linuxtoy.org//2013/12/11/installing-specific-package-versions-with-pip
<p>要用 <code>pip</code> 安装特定版本的 Python 包,只需通过 <code>==</code> 操作符
指定,例如:</p>
<div class="highlight"><pre><code class="text language-text" data-lang="text">pip install -v pycrypto==2.3
</code></pre></div>
<p>将安装 pycrypto 2.3 版本。</p>