UbuntuManual:Ubuntu 小技巧:修订间差异

来自Ubuntu中文
跳到导航跳到搜索
Dbzhang800留言 | 贡献
新页面: {{UbuntuManual}} == 第 8 章 - Ubuntu 小技巧 == === 启动系统 === 关于系统启动提示的详细信息请参见 LDP [http://www.tldp.org/HOWTO/BootPrompt-HOWTO.html BootPrompt-H...
 
Qiii2006留言 | 贡献
 
第1,046行: 第1,046行:


参阅  恢复软件包选择状态的数据, 第 6.3.4 节。
参阅  恢复软件包选择状态的数据, 第 6.3.4 节。
[[Category:Ubuntu_参考手册]]

2010年4月23日 (五) 18:40的最新版本

序言 Ubuntu 基础 Ubuntu 系统安装提示 Ubuntu指南
发行版升级 Ubuntu 软件包管理 Ubuntu下的 Linux 内核 Ubuntu 小技巧
Ubuntu 系统微调 网络设置 编辑器 版本控制系统
编程 GnuPG Ubuntu 技术支持 附录

第 8 章 - Ubuntu 小技巧

启动系统

关于系统启动提示的详细信息请参见 LDP BootPrompt-HOWTO

“我忘记了 root 密码!”(一)

只要能访问控制台键盘,不需要 root 密码也可以启动系统并以 root 帐号登录。 (这里假设没有 BIOS 密码或 lilo 之类的启动引导器密码用于控制系统启动。)

下面是一个不需要额外的启动盘或对 BIOS 启动设置进行修改的过程。这里的“Linux”是代表在 Ubuntu 默认安装系统中启动 Linux 内核的标签。

在 lilo 的启动屏幕中,当 boot: 一出现时 (在某些系统中,您必须按 shift 键以阻止自动启动;如果 lilo 使用 framebuffer,您需要按 TAB 键才能看到自己输入的选项),就输入:

boot: Linux init=/bin/sh

这会让系统启动内核并运行 /bin/sh 而非其标准的 init。现在你已获得 root 权限和一个 root shell。由于当前 / 是以只读方式挂载,而其它的硬盘分区均未挂载,故你必须完成下列步骤才能获得一个有适当功能的系统。

init-2.03# mount -n -o remount,rw /
init-2.03# mount -avt nonfs,noproc,nosmbfs
init-2.03# cd /etc
init-2.03# vi passwd
init-2.03# vi shadow

(如果 /etc/passwd 文件中所有用户的第二个域的数据都为“x”,就表明系统使用了影子(shadow)密码,必须编辑 /etc/shadow。)要删除 root 密码,请编辑密码文件中第二个数据域,将它设置为空白。这样重启系统不用密码就能登录到 root。当系统启动进入 runlevel 1 时,Ubuntu 需要密码。

在 /bin 下装一个小编辑器是个好习惯,因为有时 /usr 是无法访问的(参阅 应急的编辑器, 第 11.2 节)。

另外可以安装 sash 软件包,当系统无法启动时,还可执行:

boot: Linux init=/bin/sash

当 /bin/sh 不可用时,sash 可作为 sh 的交互式替代品,它是静态链接,内建了许多标准工具(在系统提示符下输入“help”可获得参考列表)。

“我忘记了 root 密码!”(二)

从急救盘启动系统。假设 /dev/hda3 是原始 root 分区,可用下面的方法编辑密码文件,与上述方法一样容易。

# mkdir fixit
# mount /dev/hda3 fixit
# cd fixit/etc
# vi shadow
# vi passwd

与上面的方法相比,该方法的好处在于不需要知道 lilo 密码(如果有的话)。但如果系统没有预先设置为从软盘或 CD 启动,就需要访问 BIOS 的权限。

无法启动系统

没在安装过程中制作启动盘?没关系。如果 lilo 损坏了,从 Debian 安装套件中拿出启动盘,用它来启动系统。假设你的 root 分区在 /dev/hda12,你想进入 runlevel 3,在启动提示符后输入:

boot: rescue root=/dev/hda12 3

接下来,系统使用软盘上的内核启动,你可登录到一个几乎拥有全部功能的系统了。(可能有少量特性或模块不可用。)

如果系统崩溃,亦可参阅 为无法启动的系统安装软件包, 第 6.3.6 节。

如果想做张自定义启动盘,参阅急救盘中的 readme.txt 文档。

“我不想直接启动到 X!”

玩 edgy/dapper 很有趣,但在启动进程中执行不稳定的 xdm、gdm、kdm 和 wdm 会让你焦头烂额。

首先,在启动提示符后输入如下指令获得 root shell:

boot: Linux vga=normal s

这里的 Linux 是你要启动的内核的标记,“vga=normal”告诉 lilo 在普通 VGA 屏幕下运行,“s”(或“S”)是传给 init 的参数,告诉它进入单用户模式。在提示符后输入 root 密码。

有多种方法禁用 X 启动 daemons:

  • 运行 update-rc.d -f ?dm remove ; update-rc.d ?dm stop 99 1 2 3 4 5 6 .
  • 在所有 /etc/init.d/?dm 文件的最前面加上“exit 0”。
  • 把所有的 /etc/rc2.d/S99?dm 文件改名为 /etc/rc2.d/K99?dm。
  • 删除所有的 /etc/rc2.d/S99?dm 文件。
  • 运行 :>/etc/X11/default-display-manager

其中,rc2.d 中的数字必须与 /etc/inittab 中指定的 runlevel 一致。而 ?dm 的意思是你要将同一个命令运行多次,每次将其替换成 xdm、gdm、kdm 和 wdm 中的一个。

在 Ubuntu 下只有第一种方法是“唯一正确的方法”。最后一种方法比较简单但只适用于 Ubuntu,而且还需要使用 dpkg-reconfigure 重新设置一次。其它方法都是通用的中 daemons 的方法。

你仍可在任何控制台 shell 中用 startx 命令启动 X。

其它用于启动提示符的技巧

使用lilo启动提示符,可指定系统启动到特定的runlevel和配置。详情参阅BootPrompt-HOWTO (LDP)。

如果希望系统启动到runlevel 4,可以lilo启动提示符后输入:

boot: Linux 4

如果希望系统启动到正常功能的单用户模式,而且你知道root密码,可在lilo启动提示符后输入下列任一参数。

boot: Linux S
boot: Linux 1
boot: Linux -s

如果希望系统以少于实际内存数的内存启动(也就是说机器有64MB内存,只分配48MB给系统使用),在lilo启动提示符后输入:

boot: Linux mem=48M

注意,不要指定大于实际内存数的内存,否则内核会崩溃。如果你有多于64MB的内存,如128MB,应在系统启动时执行mem=128M或在/etc/lilo.conf中添加类似的命令行,否则旧内核或使用旧BIOS的主板将无法使用大于64MB的内存。

设置 GRUB 启动参数

GRUB是Hurd项目开发的新型启动管理器,比Lilo更灵活,不过启动参数也与之稍有不同。

grub> find /vmlinuz
grub> root (hd0,0)
grub> kernel /vmlinuz root=/dev/hda1
grub> initrd /initrd
grub> boot

请注意Hurd中的设备名:

HURD/GRUB           Linux               MSDOS/Windows
(fd0)               /dev/fd0            A:
(hd0,0)             /dev/hda1           C: (usually)
(hd0,3)             /dev/hda4           F: (usually)
(hd1,3)             /dev/hdb4           ?

详情参阅/usr/share/doc/grub/README.Debian和/usr/share/doc/grub-doc/html/。

活动记录

记录shell活动

比起普通的个人电脑环境,Unix环境的系统管理包含了更多细致的任务。必须掌握所有基本的配置方法以便进行系统故障恢复。基于 X11 的GUI配置工具看上去又好又方便,但不适用于紧急状况。

记录shell活动是个好习惯,特别是root用户。

Emacs:使用M-x shell在缓冲区中开始记录,使用 C-x C-w 将缓冲区中的记录写入文件。

Shell:使用screen命令和 用screen来定制控制台, 第 8.6.28 节 中描述的“^A H”;或者使用 script 命令。

$ script
Script started, file is typescript
... do whatever ...
Ctrl-D
$ col -bx <typescript >savefile
$ vi savefile

还可使用下面的方法:

$ bash -i 2>&1 | tee typescript

记录X活动

如果需要X应用程序的活动记录图,包括 xterm 屏显,可使用gimp(GUI)。它可以对每个窗口或整个屏幕进行拍照。还可以使用xwd(xbase-clients)、import(imagemagick) 和 scrot(scrot)。

拷贝及创建子目录

这些拷贝和归档命令提供系统和数据备份的基本功能。 在 the example scripts 中提供了一个名为 backup 的简单备份脚本例子。

拷贝整个子目录的基本命令

如果想重新整理文件组织结构,可使用下面的方法移动文件及文件链接:

标准方法:
# cp -a /source/directory /dest/directory # 要求 GNU cp
# (cd /source/directory && tar cf - . ) | \
(cd /dest/directory && tar xvfp - )
如果包含硬链接,则需要更严谨的方法:
# cd /path/to/old/directory
# find . -depth -print0 | afio -p -xv -0a /mount/point/of/new/directory
如果是远程操作:
# (cd /source/directory && tar cf - . ) | \
ssh [email protected] (cd /dest/directory && tar xvfp - )
如果没有链接文件:
# scp -pr [email protected]:/source/directory \
[email protected]:/dest/directory

其中,scp <==> rcp,ssh <==> rsh。

下面的有关拷贝整个子目录的信息由 Manoj Srivastava [email protected] 发表于 [email protected]

cp

传统上,cp并不能真正完成这个任务,因为它既没对符号链接进行区别对待,又不能保存硬链接。另一件需要注意的事就是稀疏文件(有洞的文件)。

GNU cp克服了这缺陷,然而对于非GNU系统,cp仍存在问题。而且使用cp无法生成小巧轻便的文档包。

% cp -a . newdir

tar

Tar克服了cp在处理符号链接时出现的问题,然而,cpio可以处理特殊文件,传统的tar却不行。

对于某个有多重硬链接的文件,tar的处理方法是只将其中一个链接拷贝到磁带上,所以日后你只能找回拷贝中所保留那个的链接所指的文件;cpio会为每个链接做一个拷贝,日后你可以找回任意一个链接所指的文件。

pax

全新的,符合POSIX(IEEE Std 1003.2-1992, pages 380–388 (section 4.48) and pages 936–940 (section E.4.48))标准的,众望所归的,轻便的文档包交互工具。pax可以读、写以及列出文档包的成员,并能拷贝文件目录层次。pax的操作独立于特定的文档包格式,支持各种各样不同的文档包格式。

pax工具刚刚成形,还很新。

# apt-get install pax
$ pax -rw -p e . newdir
or
$ find . -depth  | pax -rw -p e  newdir

cpio

cpio从cpio或tar文档包提取/放入文件。该文档包可以是硬盘上的另一个文件,也可以是磁带或管道。

$ find . -depth -print0 | cpio --null --sparse -pvd new-dir

afio

afio更善于处理cpio格式的文档包。通常它比 cpio 要快,且提供了更多磁带选项,并且能更友好的处理有讹误的输入数据。它支持交互式处理多卷文档包。用afio制作压缩文档包比压缩tar或cpio文档包更安全。在备份处理脚本中afio是更佳的“文档处理引擎”。

$ find . -depth -print0 | afio -px -0a new-dir

对所有的磁带备份我都使用afio。

差异备份与数据同步

要进行差异备份和数据同步可使用下列几种方法:

  • rcs:备份并进行历史记录,只支持文本。
  • rdiff-backup:备份并进行历史记录。支持链接。
  • pdumpfs:对文件系统进行备份和历史记录。支持链接。
  • rsync:单路同步。
  • unison:双路同步。
  • arch:多路同步服务器备份并进行历史记录,但包括“处于工作中的目录”。
  • subversion:多路同步服务器备份并进行历史记录,专用于Apache。

有关将这些方法与文档包操作结合应用的讨论参阅拷贝及创建子目录, 第 8.3 节,有关自动进行备份的讨论参阅日程安排(cron,at), 第 8.6.27 节

我只讲解三个较容易使用的工具。

使用rdiff进行差异备份

rdiff-backup提供了简单好用的方法对任何文件包括链接进行历史差异备份。例如要对~/目录下的所有文件备份到/mnt/backup:

$ rdiff-backup --include ~/tmp/keep --exclude ~/tmp  ~/ /mnt/backup

从该文档包中取出3天前的旧数据恢复到~/old目录:

$ rdiff-backup -r 3D /mnt/backup ~/old

参阅rdiff-backup(1)。

使用pdumpfs进行每日备份

pdumpfs是一种简单的每日备份系统,与Plan9的dumpfs一样,它每天都保存系统快照。任何时候都可以用它来恢复到某天的系统状态。请使用pdumpfs和cron来备份你的home目录。

在目标目录中,pdumpfs以YYYY/MM/DD的方式来组织系统快照。 当 pdumpfs 第一次运行时,它将所有源文件拷贝到快照目录。从每二次运行起,pdumpfs仅拷贝更新的或新建的文件,对于没有改变的文件用硬链接方式指向前一天的系统快照,以此来节省硬盘空间。

$ pdumpfs src-dir dest-dir [dest-basename]

参阅 pdumpfs(8)。

使用RCS进行定期差异备份

Changetrack会定期对RCS文档包中基于文本格式的配置文件的变化进行记录。参阅changetrack(1)。

# apt-get install changetrack
# vi changetrack.conf

系统冻结恢复

中止一个进程

运行top看看什么进程的活动有异常。按“P”以 CPU 使用率排序,“M”以内存使用率排序,“k”可以中止一个进程。还有一种方法,使用BSD风格的ps aux | less或System V风格的ps -efH | less。System V风格的排列会显示父进程ID (PPID),这对中止出错的(死掉的)子进程十分有用。

知道了进程的ID,就可使用kill中止(或发信号给)某个进程,killall的作用正如其名一样。经常使用的信号有:

1: HUP,重启daemon
15: TERM,普通中止
9: KILL,强令中止

Alt-SysRq

内核编译选项“Magic SysRq key”提供系统强心针。在i386机器上按下 ALT-SysRq 组合键后,试试按下列各键r 0 k e i s u b,奇迹产生了:

Un'r'aw让键盘从X崩溃中重生。将控制台loglevel改为'0'以减少错误信息。sa'k'(system attention key)中止当前虚拟控制台的所有进程。t'e'rminate中止当前终端除 init 外的所有进程。k'i'll中止除 init 外的所有进程。

'S'ync,'u'mount和re'b'oot帮你逃离真正的险境。

本文写作之时,Ubuntu默认安装的内核并未将该选项编译进去,需要重新编译内核激活该功能。详情参阅/usr/share/doc/kernel-doc-version/Documentation/sysrq.txt.gz或/usr/src/kernel-version/Documentation/sysrq.txt.gz。

记住这些可爱的小命令

Pager

less就是默认的 pager(文件内容浏览器)。按“h”可获得帮助。它比more更有用。在shell启动脚本中运行eval $(lesspipe)或eval $(lessfile)可以让less活力四射。详情参阅/usr/share/doc/lessf/LESSOPEN。使用-R选项可输出生癖字符and enables ANSI color escape sequences.参阅less(1)。

对于某些编码系统(EUC)w3m可能是更好的选择。

释放内存

free和top能让你了解内存资源的许多有用信息。别担心“Mem:”行中“used”的大小,看看它下面的数字(本例的数字是38792)。

$ free -k # 用 256MB 内存的机器
total       used       free     shared    buffers cached
Mem:        257136     230456      26680      45736     116136 75528
-/+ buffers/cache:      38792     218344
Swap:       264996          0     264996

物理内存的准确大小可通过grep '^Memory' /var/log/dmesg得到,本例将显示“Memory: 256984k/262144k available (1652k kernel code, 412k reserved, 2944k data, 152k init)”。

Total         ==== 262144k ==== 256M (1k=1024, 1M=1024k)
Free to dmesg ==== 256984k ==== Total - kernel - reserved - data - init
Free to shell ==== 257136k ==== Total - kernel - reserved - data

约有5MB内存系统不能使用,因为内核需要它。

设定时间(BIOS)

# date MMDDhhmmCCYY
# hwclock --utc --systohc
# hwclock --show

设定系统时间和硬件时间为MM/DD hh:mm, CCYY。显示时间为本地时间而硬件时间使用UTC。

如果硬件(BIOS)时间设置为 GMT,在文件 /etc/default/rcS 中改变设置 UTC=yes。

设定时间(NTP)

参考:Managing Accurate Date and Time HOWTO

拥有永久Internet连接的系统设置时间

设置系统时钟通过远程服务器自动对时:

# ntpdate server 

如果你的系统拥有永久的Internet连接,应该将该命令加入/etc/cron.daily/。

偶尔进行Internet连接的系统设置时间

使用chrony软件包。

如何禁用屏幕保护程序

禁用屏幕保护程序,使用下面的命令。

对于Linux控制台:

# setterm -powersave off

启动 kon2 (kanji)控制台可执行:

# kon -SaveTime 0

运行X可执行:

# xset s off
或
# xset -dpms
或
# xscreensaver-command -prefs

控制其它的控制台特征,请参阅相关 man 页面。 改变和显示终端行设置,请参阅 stty(1)。

搜索系统管理数据库

Glibc提供了getent(1)搜索管理数据库的各类项目。例如passwd、group、hosts、services、protocols、networks。

getent database [key ...]

禁用声音(响铃)

最直接的方法是拔掉PC喇叭。;-) 对于Bash shell可执行:

echo "set bell-style none">> ~/.inputrc

控制台上的错误信息

不想看屏幕显示的错误信息,首选的方法是检查/etc/init.d/klogd,在该脚本中设置KLOGD="-c 3"然后运行/etc/init.d/klogd restart。另一种方法是执行dmesg -n3。

这儿是各种错误级别的含义:

  • 0: KERN_EMERG, 系统不可用
  • 1: KERN_ALERT, 必须立即执行
  • 2: KERN_CRIT, 紧急状态
  • 3: KERN_ERR, 错误状态
  • 4: KERN_WARNING, 警告状态
  • 5: KERN_NOTICE, 正常状态且十分重要
  • 6: KERN_INFO, 报告
  • 7: KERN_DEBUG, debug-level信息

如果你很厌恶详细而无用的错误信息,可以试试这个小补丁shutup-abit-bp6(位于样例脚本子目录)。

另一个该看看的地方是/etc/syslog.conf;,检查一下是否有信息记录被发送到了控制台设备。

正确设置控制台类型

在类Unix系统中,访问控制台屏幕通常要调用库例程,这就为用户提供了一种独立于终端的方式来优化字符的屏幕更新过程。参阅ncurses(3X)和terminfo(5)。

在Ubuntu系统中,有大量预定义项目:

$ toe | less                  # 所有项目
$ toe /etc/terminfo/ | less   # 用户可再配置的项目

你的选择可导出到环境变量TERM。

当登录到远程Debian系统时,如果 xterm 的terminfo项目在非Debian的 xterm 中失效,请将终端类型改为支持较少特性的版本如“xterm-r6”。 参阅/usr/share/doc/libncurses5/FAQ。“dumb”是terminfo的最小公分母。

恢复控制台的健壮性

如果执行 cat some-binary-file后屏幕一片混乱(命令的返回值与你的输入大相径庭):

$ reset

将DOS下的文本文件转换为Unix类型

将DOS文本文件(行尾=M^J)转换成Unix文本文件(行尾=J)。

# apt-get install sysutils
$ dos2unix dosfile 

使用 recode 转化文本文件

下面将在 DOS、 Mac 和 Unix 的文本文件中转换行结尾格式:

$ recode /cl../cr <dos.txt >mac.txt
$ recode /cr.. <mac.txt >unix.txt
$ recode ../cl <unix.txt >dos.txt 

自由的 recode 在各种各样的字符集和界面中转换:

$ recode charset1/surface1..charset2/surface2 \
<input.txt >output.txt 

使用的通用字符集设置是(参阅 Locales 简介, 第 9.7.3 节)  :

  • us — ASCII (7 bits)
  • l1 — ISO Latin-1 (ISO-8859-1, Western Europe, 8 bits)
  • EUCJP — EUC-JP for Japanese (Unix)
  • SJIS — Shift-JIS for Japanese (Microsoft)
  • ISO2022JP — Mail encoding for Japanese (7 bits)
  • u2 — UCS-2 (Universal Character Set, 2 bytes)
  • u8 — UTF-8 (Universal Transformation Format, 8 bits)

使用的通用界面 [38] :

  • /cr — Carriage return as end of line (Mac text)
  • /cl — Carriage return line feed as end of line (DOS text)
  • / — Line feed as end of line (Unix text)
  • /d1 — Human readable bytewise decimal dump
  • /x1 — Human readable bytewise hexidecimal dump
  • /64 — Base64 编码文本
  • /QP — Quoted-Printable 编码文本

更多信息,请参阅 info recode 中的相关描述。

有更多的专业转换工具:

  • 字符集转换:
    • iconv — 本地编码转换
    • konwert — 特殊编码转换
  • 二进制文件转换:
    • uuencode and uudecode — 用于 Unix
    • mimencode — 用于邮件

正规表达式的置换

将所有文件FILES ...中的所有FROM_REGEX字段替换成 TO_TEXT字段。

$ perl -i -p -e 's/FROM_REGEX/TO_TEXT/g;' FILES ...

-i表示“就地编辑”,-p表示“在FILES...各文件中循环”。如果置换很复杂,应使用参数-i.bak而非-i,这有助于出错恢复;它会将每个原始文件保存为以.bak为后缀的备份文件。

使用脚本来编辑文件

下面的脚本将删除5–10行以及16–20行。

#!/bin/bash
ed $1 <<EOF
16,20d
5,10d
w
q
EOF

在此,ed命令与vi命令模式下的是一样的,从外部编辑文件的方式使它更适于脚本化。

提取源文件修改部分合并到更新包

下面的操作将根据文件位置,提取源文件的修改部分并创建统一的diff文件file.patch0或file.patch1:

$ diff -u file.old file.new1 > file.patch0
$ diff -u old/file new1/file > file.patch1 

diff文件(也称补丁文件)通常用于发送程序更新。收到的补丁文件可使用下面的方法更新另一个文件:

$ patch -p0 file < file.patch0
$ patch -p1 file < file.patch1 

如果有3个版本的源代码,使用diff3来合并效率更高:

$ diff3 -m file.mine file.old file.yours > file 

分割大文件

$ split -b 650m file   # 将大文件分块成多个650MB的小文件
$ cat x* >largefile    # 将所有小文件合并成一个大文件

从文本格式的表格中抽取数据

假设有一个文本文件名为DPL,其中存放着所有前Debian项目领导人的名字和他们的上台日期,表格格式是以空格做为分隔的。

Ian     Murdock   August  1993
Bruce   Perens    April   1996
Ian     Jackson   January 1998
Wichert Akkerman  January 1999
Ben     Collins   April   2001
Bdale   Garbee    April   2002
Martin  Michlmayr March   2003

Awk经常用于从这类文件中提取数据。

$ awk '{ print $3 }' <DPL                   # month started
August
April
January
January
April
April
March
$ awk '($1=="Ian") { print }' <DPL          # DPL called Ian
Ian     Murdock   August  1993
Ian     Jackson   January 1998
$ awk '($2=="Perens") { print $3,$4 }' <DPL # When Perens started
April 1996

象 Bash 这种 Shell 也能够用来分析这种文件:

$ while read first last month year; do 
echo $month
done <DPL
... 跟第一个 Awk 例子有相同的输出

在这里,read 内建命令使用字符 $IFS (internal field separators 内部列分隔符)来将行分开为单词。

如果你改变 IFS 为 ":",你能够用 shell 漂亮的分析 /etc/passwd:

$ oldIFS="$IFS"   # 保存旧值
$ IFS=":"
$ while read user password uid gid rest_of_line; do
if [ "$user" === "osamu" ]; then 
echo "$user's ID is $uid"
fi
done < /etc/passwd
osamu's ID is 1001
$ IFS="$oldIFS"   # 恢复旧值

(如果使用 Awk 作同样的事情,使用 FS=":" 来设置列分隔符。)

shell 也使用 IFS 来分开参数扩展、命令替换和算术扩展的结果集。 但在被单引号或双引号引用的单词内,不会发生这种情况。 默认的 IFS 值是: <space>、 <tab> 和 <newline> 。

请小心使用这个 shell IFS 技巧。 当 shell 解释部分脚本作为它的输入时,奇怪的事情将会发生。

$ IFS=":,"                        # 使用 ":" 和 "," 作为 IFS
$ echo IFS=$IFS,   IFS="$IFS"     # echo 是 Bash 内建的
IFS==  , IFS=:,
$ date -R                         # 只是一个命令输出
Sat, 23 Aug 2003 08:30:15 +0200
$ echo $(date -R)                 # 子 shell --> 输入到主 shell
Sat  23 Aug 2003 08 30 36 +0200
$ unset IFS                       # 重设 IFS 为默认的
$ echo $(date -R)
Sat, 23 Aug 2003 08:30:50 +0200

精巧的管道命令辅助脚本

下列脚本做为管道的一部分十分有用。

find /usr | egrep -v "/usr/var|/usr/tmp|/usr/local"
# 查找 /usr 下的所有文件,排除某些文件
xargs -n 1 command   # 将所有项作为标准输入来执行命令
xargs -n 1 echo |    # 将空格隔离的项分开为行
xargs echo      |    # 合并所有的行到一行里面
grep -e pattern|     # 提取含有 pattern 的行
cut -d: -f3 -|
# 提取用 : 分开的第 3 列(比如说 passwd 文件)
awk '{ print $3 }' | # 提取用空格分开的第 3 列
awk -F'\t' '{ print $3 }' |
# 提取用 tab 分开的第 3 列
col -bx |            # 删除退格键,扩展 tab 为空格
expand -|            # 扩展 tab
sort -u|             # 排序并删除重复行

tr '\n' ' '|         # 将多行连接为一行
tr '\r' ''|          # 删除 CR
tr 'A-Z' 'a-z'|      # 转化大写字母为小写
sed 's/^/# /'|       # 将每行变为注释
sed 's/\.ext//g'|    # 删除 .ext
sed  -n -e 2p|       # 显示第 2 行
head -n 2 -|         # 显示头两行
tail -n 2 -|         # 显示最后两行

循环每一个文件的脚本片段

下面的方法将循环处理匹配 *.ext 的每一个文件,确保适当处理文件名包含空格的奇怪文件,并且执行相同的操作。

  • Shell 循环 (在 PS2=" " 时使用多行格式的例子。 如果在一行内输入这些命令,需要在每一个换行处加一个分号。):
for x in *.ext; do
if test -f "$x"; then
command "$x"
fi
done
  • find 和 xargs 结合:
find . -type f -maxdepth 1 -name '*.ext' -print0 | \
xargs -0 -n 1 command 
  • 加 -exec 选项的 find 和一个命令结合:
find . -type f -maxdepth 1 -name '*.ext' \
-exec command '{}' \;
  • 加 -exec 选项的 find 和一个短的 shell 脚本结合:
find . -type f -maxdepth 1 -name '*.ext' \
-exec sh -c "command '{}' && echo 'successful'" \;

短小的Perl脚本

虽然任何 Awk 脚本均可使用 a2p(1) 自动重写成 Perl, 但最好用手工的方法将一行 Awk 脚本转化为一行 perl 脚本。例如:

awk '($2=="1957") { print $3 }' |

与下列任意一行相当:

perl -ne '@f=split; if ($f[1] eq "1957") { print "$f[2]\n"}' |
perl -ne 'if ((@f=split)[1] eq "1957") { print "$f[2]\n"}' |
perl -ne '@f=split; print $f[2] if ( $f[1]==1957 )' |
perl -lane 'print $F[2] if $F[1] eq "1957"' |

其实上面各行中所有 perl 参数中的空格均可去掉,这得益于Perl的数字字符串自动转换功能。

perl -lane 'print$F[2]if$F[1]eq+1957' |

有关命令行参数的信息可参阅perlrun(1),在http://perlgolf.sourceforge.net有更多令人着魔的Perl脚本,你会感兴趣的。

从网页上获取文本或邮件列表文档

下面的操作将网页转化为文本文件。从网上拷贝配置文件时十分有用。

$ lynx -dump http://www.remote-site.com/help-info.html >textfile 

links和w3m也可以这么用,只是生成的文本样式可能略有不同。

如果是邮件列表文档,可使用munpack从文本获得mime内容。

打印网页

下面的操作将网页内容打印成PostScript文件或发送到打印机。

$ apt-get install html2ps
$ html2ps URL | lpr

参阅 lpr/lpd, 第 3.6.1 节。还可使用a2ps和mpage软件包生成PostScript文件。

打印帮助页面

下面的操作将帮助页面打印成PostScript文件或发送到打印机。

$ man -Tps some-manpage | lpr
$ man -Tps some-manpage | mpage -2 | lpr

合并两个 PostScript 或 PDF 文件

可以将两个 PostScript 文件或 PDF 文件合并。

$ gs -q -dNOPAUSE -dBATCH -sDEVICE=pswrite \
-sOutputFile=bla.ps -f foo1.ps foo2.ps
$ gs -q -dNOPAUSE -dBATCH -sDEVICE=pdfwrite \
-sOutputFile=bla.pdf -f foo1.pdf foo2.pdf 

命令耗时

显示某进程的耗时

# time some-command >/dev/null
real    0m0.035s       # 挂钟时间(过去的真实时间)
user    0m0.000s       # 用户模式时间
sys     0m0.020s       # 核心模式时间

nice命令

使用nice(来自GNU shellutils软件包)可设置命令启动时的nice值。renice(bsdutils)和 top可以重设进程的nice值。nice值为19代表最慢的(优先级最低的)进程;负值就“not-nice”,如-20代表非常快的(优先级高的)进程。只有超级用户可以设定负nice值。

# nice  -19 top                                         # very nice
# nice --20 cdrecord -v -eject speed=2 dev=0,0 disk.img # very fast

有时极端的nice值对系统弊大于利,所以使用该命令要小心。

日程安排(cron,at)

在Ubuntu下使用cron和at进行任务日程安排。参阅at(1)、crontab(5)、crontab(8)。

执行命令crontab -e创建或编辑crontab文件,为规律事务(按周期循环的事务)安排日程。下面的一个crontab文件样例:

# use /bin/sh to run commands, no matter what /etc/passwd says
SHELL=/bin/sh
# mail any output to `paul', no matter whose crontab this is
MAILTO=paul
# Min Hour DayOfMonth Month DayOfWeek command (Day... are OR'ed)
# run at 00:05, every day
5  0  *  * *   $HOME/bin/daily.job >> $HOME/tmp/out 2>&1
# run at 14:15 on the first of every month -- output mailed to paul
15 14 1  * *   $HOME/bin/monthly
# run at 22:00 on weekdays(1-5), annoy Joe. % for newline, last % for cc:
0 22 *   * 1-5 mail -s "It's 10pm" joe%Joe,%%Where are your kids?%.%%
23 */2 1 2 *   echo "run 23 minutes after 0am, 2am, 4am ..., on Feb 1"
5  4 *   * sun echo "run at 04:05 every sunday"
# run at 03:40 on the first Monday of each month
40 3 1-7 * *   [ "$(date +%a)" ==== "Mon" ] && command -args

执行at命令为偶然任务(只执行一次的任务)安排日程:

$ echo 'command -args'| at 3:40 monday

用screen来定制控制台

screen程序允许在单一的物理终端或终端模拟窗口运行多个伪终端,每个伪终端都拥有自己的交互式shell。即便可以使用Linux伪终端或多个 xterm 窗口,研究一下如何设置screen 丰富的特性仍很有益,这些特性包括:

  • 回溯历史显示,
  • 拷贝和粘贴,
  • 输出到日志,
  • 图形入口,
  • 将终端与整个screen会话分离,稍后再连接。
远程访问方案

如果你经常从远程终端登录到Linux机器或使用VT100终端程序,screen的detach(分离)特性将简化你的生活。

  • 通过拔号连接登录,运行了一个非常复杂的screen会谈,打开了好几个窗口,有编辑器和其它一些程序。
  • 突然你需要离开终端一下,但你并不想挂断连接中止工作。
  • 输入A d离开会话,然后登出系统。(或者更简单些,输入A DD离开会话并自动登出系统)
  • 当你回来时,需要再次登录,可输入命令screen -r,screen会如魔法般地重新连接上所有打开的窗口。
典型的screen命令

一但打开了screen程序,除了命令按键(默认为A)所有的键盘输入都被送到当前窗口,所有的screen命令均按特定方式输入:A加一个单键命令[加一些参数]的。常用的命令有:

^A ?     显示帮助屏幕(显示命令集)
^A c     创建并切换到新窗口
^A n     跳到下一个窗口
^A p     跳到上一个窗口
^A 0     跳到0号窗口
^A w     显示窗口列表
^A a     将Ctrl-A做为键盘输入发送到当前窗口
^A h     对当前窗口做硬拷贝写入到文件
^A H     开始/中止将当前窗口事件记录到文件
<sup>A </sup>X    锁定终端(密码保护)
^A d     从终端分离屏幕会话
^A DD    分离屏幕会话并退出登录

以上只是screen命令的一个很小的子集。只要是你认为screen能干的事,没准它真就可以!详情参阅screen(1)。

screen会话中的退格键和Ctrl-H

在运行screen时,如果发现退格键和/或Ctrl-H无法正常工作,可编辑/etc/screenrc,找到这行:

bindkey -k kb stuff "\177"

将这注释掉(例如在句首添加“#”)。

X下与screen等价的程序

找找xmove。参阅xmove(1)。

网络测试基础

安装netkit-ping、traceroute、dnsutils、ipchains(适用于2.2版内核)、iptables(适用于2.4版内核)和net-tools软件包,然后执行:

$ ping yahoo.com            # 检查Internet连接
$ traceroute yahoo.com      # 跟踪IP数据包
$ ifconfig                  # 检查主机设置
$ route -n                  # 检查路由设置
$ dig [@dns-server.com] host.dom [{a|mx|any}] |less
# 检查dns-server.com的host.dom DNS记录
# 查找{a|mx|any}记录
$ ipchains  -L -n |less     # 检查包过滤(2.2 kernel)
$ iptables -L -n |less      # 检查包过滤(2.4 kernel)
$ netstat -a                # 查找系统上所有打开的端口
$ netstat -l --inet         # 查找系统监听的端口
$ netstat -ln --tcp         # 查找系统监听的TCP端口(端口数字)

从本地缓冲池中清空(flush)邮件

从本地缓冲池中清空邮件:

# exim -q    # 清空待读邮件
# exim -qf   # 清空所有邮件
# exim -qff  # 清空冻结邮件

-qff选项用在/etc/ppp/ip-up.d/exim脚本中效果更好。 在 Sarge 中,使用 exim4 代替 exim。

删除本地缓冲池中的冻结邮件

删除本地缓冲池中的冻结邮件并返回出错信息:

# exim -Mg `mailq | grep frozen | awk '{ print $3 }'`

在 Sarge 中,使用 exim4 代替 exim。

再分发 mbox 中的信件

如果home目录没有空间继续处理邮件,procmail 将失败, 就需要对磁盘空间进行扩容,扩容完成后需要手工分发/var/mail/username目录中的邮件到home目录中的分类邮箱,执行:

# /etc/init.d/exim stop
# formail -s procmail </var/mail/username
# /etc/init.d/exim start

在 Sarge 中,使用 exim4 代替 exim。

清空文件内容

要清空某些文件如日志文件的内容,千万不要使用rm删除文件然后再创建一个新的空文件,因为在两次操作的间隔,系统可能需要访问该文件。下面是清空文件内容的安全方法:

$ :>file-to-be-cleared 

空文件

下面的命令可以创建空文件:

$ dd if=/dev/zero    of=filename bs=1k count=5 # 5KB 零内容
$ dd if=/dev/urandom of=filename bs=1M count=7 # 7MB 随机内容
$ touch filename #  创建一个 0 B 大小的文件 (如果文件存在,更新该文件的修改时间)

例如,最实用的用法是从Debian启动软盘的shell中执行下列命令将硬盘/dev/hda的内容完全清空。

# dd if=/dev/urandom of=/dev/hda ; dd if=/dev/zero of=/dev/hda

chroot

chroot 程序,chroot(8),不需要重启系统,就可以在单独的系统上同时运行多个不同的 GNU/Linux 环境。

还可以在较快主机的 chroot 下运行某些需耗大量系统资源内存的程序如 apt-get 或 dselect,并将较慢子机的硬盘通过 NFS 方式挂载到主机,开放读/写权限,在主机上以 chroot 方式操作子机。

用 chroot 来运行不同版本的 Ubuntu

在老版本中使用 debootstrap 命令很容易构造 chroot Debian 体系。对于 Hoary 的后续发行版,用 cdebootstrap 命令加上适当的选项来代替 debootstrap。例如,在一台拥有快速 Internet 连接的机器的 /sid-root 下创建一个 dapper chroot:

main # cd / ; mkdir /dapper-root
main # debootstrap dapper /dapper-root http://archive.ubuntu.com/ubuntu/
... 看它下载整个系统
main # echo "proc-dapper /dapper-root/proc proc none 0 0" >> /etc/fstab
main # mount proc-dapper /dapper-root/proc -t proc
main # cp /etc/hosts /dapper-root/etc/hosts
main # chroot /dapper-root /bin/bash
chroot # cd /dev; /sbin/MAKEDEV generic ; cd -
chroot # apt-setup # 创建 /etc/apt/sources.list 文件
chroot # vi /etc/apt/sources.list # 将源指向 dapper
chroot # dselect  # 可以使用 aptitude,安装 mc 和 vim :-)

现在你就拥有了一个全功能 Ubuntu 子系统,可以尽情享受而不必担心主 Ubuntu 受到不利影响。

该 debootstrap 应用技巧还可以实现在没有 Ubuntu 安装盘的情况下,从另一个 GNU/Linux 发行版下安装 Ubuntu。参阅 http://www.debian.org/releases/stable/i386/apcs04.html.en。

设置chroot登录

输入chroot /sid-root /bin/bash非常简单,但这将保留当前的所有环境变量,你可能并不希望这样并且有时还会出问题。更好的方法是,在别的虚拟终端上执行另一个登录进程,登录到chroot目录。

在默认的 Ubuntu 系统中,从tty1到tty6运行Linux控制台,tty7运行X Window系统,在本例中,我们将tty8设置成chroot控制台。按照 用 chroot 来运行不同版本的 Ubuntu, 第 8.6.35.1 节中的描述创建好chroot系统后,就可以在主系统的root shell中输入:

main # echo "8:23:respawn:/usr/sbin/chroot /sid-root "\
"/sbin/getty 38400 tty8"  >> /etc/inittab
main # init q    # 重启 init
配置chroot下的X

想在chroot下安全地运行最新版的X和GNOME吗?完全可以!下面的例子将实现在虚拟终端vt9下运行GDM。

首先,按照 用 chroot 来运行不同版本的 Ubuntu, 第 8.6.35.1 节中描述的方法安装好chroot系统,从主系统的root下拷贝关键配置文件到chroot系统。

main # cp /etc/X11/xorg.conf /dapper-root/etc/X11/xorg.conf
main # chroot /dapper-root # or use chroot console
chroot # cd /dev; /sbin/MAKEDEV generic ; cd -
chroot # apt-get install gdm gnome x-window-system
chroot # vi /etc/gdm/gdm.conf # do s/vt7/vt9/ in [servers] section
chroot # /etc/init.d/gdm start

在此,编辑/etc/gdm/gdm.conf,使其在vt7到vt9上创建虚拟终端。

现在可以很容易地能过切换Linux虚拟终端来实现在主系统的X环境和chroot系统的X环境之间转换,例如使用Ctrl-Alt-F7和Ctrl-Alt-F9。酷吧!

[FIXME] 在chroot系统下 gdm 的init脚本中添加一条注释和一条链接。

使用chroot来运行其它发行版

很容易创建一个包含其它发行版的chroot环境。使用其它发行版的安装程序将它们安装到单独的硬盘分区中。例如root分区位于/dev/hda9:

main # cd / ; mkdir /other-dist
main # mount -t ext3 /dev/hda9 /other-dist
main # chroot /other-dist /bin/bash

接下来按照 用 chroot 来运行不同版本的 Ubuntu, 第 8.6.35.1 节、 设置chroot登录, 第 8.6.35.2 节和 配置chroot下的X, 第 8.6.35.3 节 处理。

使用chroot来编译软件包

这儿有一个很特殊的chroot软件包pbuilder,它构造一个chroot系统并在其中编译软件包。该体系可用于检查软件包编译时关联关系是否正确,并确保编译生成的软件包中没有不必要的或错误的关联关系。

怎样检查硬链接

检查两个文件是否是指向同一个文件的两个硬链接:


$ ls -li file1 file2 

mount硬盘上的镜像文件

如果file.img文件是硬盘内容的镜像文件,而且原始硬盘的配置参数为xxxx === (bytes/sector) * (sectors/cylinder),那么,下面的命令将其挂载到/mnt:

# mount -o loop,offset=xxxx file.img /mnt

注意绝大部分的硬盘都是512 bytes/sector。

Samba

获取Windows文件的基本方法:

# mount -t smbfs -o username=myname,uid=my_uid,gid=my_gid \
//server/share /mnt/smb  # 挂载 Windows 的文件到 Linux
# smbmount //server/share /mnt/smb \
-o "username=myname,uid=my_uid,gid=my_gid"
# smbclient -L 192.168.1.2 # 列出某个计算机的共享目录

可从Linux检查Samba网上邻居:

# smbclient -N -L ip_address_of_your_PC | less
# nmblookup -T "*"

外来文件系统的操作工具

Linux内核支持多种外来文件系统,想访问它们只需将其挂载到合适的文件系统下就行了。对某些文件系统,还提供专门工具不需要挂载,只依靠用户空间的程序,不需要内核提供文件系统支持,就能完成访问。

  • mtools: for MSDOS filesystem (MS-DOS, Windows)
  • cpmtools: for CP/M filesystem
  • hfsutils: for HFS filesystem (native Macintosh)
  • hfsplus: for HFS+ filesystem (modern Macintosh)

对于创建和检查MS-DOS FAT文件系统dosfstools非常有用。

需要注意的典型错误

这里有一些危险行为的例子。如果你是使用特权账号 root 的话,负面影响将会更大。

rm -rf .*

在象"rm -rf .*" 的命令行参数中使用通配符文件名,有可能造成危险的结果, 因为 ".*" 扩展为 "." 和 ".."。 比较幸运的是,在 Debian 发行版中,当前版本的 "rm" 命令会检查文件名参数的健全性,会拒绝删除 "." 和 ".."。 但这种检查并不一定在其它地方存在。 尝试下面的操作来参看通配符文件名是怎样工作的。

  • "echo ." : 列出当前目录自身
  • "echo *" : 列出当前目录下所有不以点开头的文件和目录
  • "echo .[^.]*" : 列出当前目录下所有以点开头的文件和目录
  • "echo .*" : 列出父目录下的所有东西和父目录自身

rm /etc/passwd

由于你的过失,丢失象 /etc/passwd 这样的重要文件,是一件非常痛苦的事。Ubuntu 系统周期性的将他们备份到 /var/backups/。 当你恢复这些文件的时候,你需要设置适当的权限。

# cp /var/backups/passwd /etc/passwd
# chmod 644 /etc/passwd

参阅 恢复软件包选择状态的数据, 第 6.3.4 节。